home *** CD-ROM | disk | FTP | other *** search
/ Amiga Magazin: Amiga-CD 2000 April & May / AMIGA_2000_04.iso / pd-disketten / dms-gepackt / 6_96 / apd-6-96-2.dms / apd-6-96-2.adf / Skalieren / scale5.cpp < prev    next >
C/C++ Source or Header  |  1996-03-21  |  9KB  |  350 lines

  1.  
  2. // Scale 
  3. // (C) 1996 Clemens Marschner
  4. // $VER: Scale 2.4 (12-Apr-96; 13:36)
  5. // Compiliert mit Maxon-C++ (makefile)
  6.  
  7. #include <intuition/intuition.h>
  8. #include <graphics/gfx.h>
  9. #include <graphics/rastport.h>
  10. #include <pragma/intuition_lib.h>
  11. #include <pragma/exec_lib.h>
  12. #include <pragma/graphics_lib.h>
  13. #include <pragma/dos_lib.h>
  14. #include <stream.h>
  15.  
  16. // defines
  17.  
  18. #define FOREVER for(;;)
  19.  
  20. // Protos
  21.  
  22. // Assembler-Funktion: Schreibt die Pixel horizontal
  23. extern "C" void WriteLine(register __a0 const char *src, register __a1 char *dest, 
  24.                     register __a2 const char *werte, register __d0 int breite);
  25.  
  26.  
  27. void PollLoop();
  28. void Scale(struct RastPort *rp, int dx, int dy, int x1, int y1);
  29. void CalcProps(UBYTE *ziel, int b, int dx);
  30.  
  31. // Konstanten
  32.  
  33. const int b = 12*8, h = 12*9;
  34.  
  35. // externe und globale Variablen
  36.  
  37. extern const char bild[h][b];                    
  38. // die Bitmap. Der Demonstration halber als Chunky-Array (leichterer Zugriff!)
  39. // siehe bild.c
  40.  
  41. struct Window *win; 
  42. struct RastPort *rp;
  43.  
  44. void Example() {
  45.     int mx = win->Width/2;
  46.     int my = win->Height / 2;
  47.     for(int i=0; i<40; i+=4) {
  48.         Scale(rp, b+i*2+10, h+i+10, 5,15);
  49.     }
  50. }
  51.  
  52. void main() {
  53.     win = OpenWindowTags(NULL, 
  54.             WA_Flags, WFLG_ACTIVATE | WFLG_CLOSEGADGET | WFLG_DEPTHGADGET | 
  55.             WFLG_DRAGBAR| WFLG_NOCAREREFRESH|WFLG_DEPTHGADGET|WFLG_SIZEGADGET,
  56.             WA_Top, 11,                WA_Width, 480,            WA_Height, 300,
  57.             WA_Left, 238,            WA_Top, 0,                WA_Title, "Scaling",
  58.             WA_MinWidth, 50, WA_MinHeight, 25, WA_MaxWidth,~0,WA_MaxHeight,~0,
  59.             WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE,
  60.             WA_BlockPen, 4,            WA_DetailPen, 3,            TAG_END);
  61.     if(!win) { cout << "Window offenbar nicht offenbar\n"; return; };
  62.     rp = win->RPort;
  63.     try {
  64.         Delay(125); // warten, bis alle Files zu sind (bei Start aus dem Compiler heraus)
  65.         Example();  // zeichnet ein paar Bitmaps
  66.         PollLoop(); // paßt die Bitmap dem Window an
  67.     } catch(...) { cout << "Fehler\n"; }
  68.     CloseWindow(win);
  69. }
  70.  
  71.  
  72. inline void Clear(UBYTE*m,int sz) {
  73.     while(sz--) *m++=0;
  74. }
  75.  
  76. // zentrale Routine: Berechnet die Pixelweiten und legt sie im Array "ziel" ab.
  77.  
  78. void CalcProps(UBYTE *ziel, int qubreite, int zlbreite) {
  79.     int x = 0, y = 0, error, dx=zlbreite, dy=qubreite;
  80.     if(zlbreite > (qubreite<<8))     {
  81.         cout << "Zu groß. Höchstens 25500% möglich\n";    return;
  82.     }
  83.  
  84.     // double     error = -(0.5 - 0.5*m) * 2*(dx+1) - (dx+1)
  85.     //                                                                    ^ 0.5 * s (Prüfbedingung)
  86.     //                                                    ^ Skalierung (Faktor s) -> ints
  87.     //                                    ^ error-Wert durch korrigierte Linie
  88.     //                     = (-1 + m) * (dx+1) - (dx+1) mit m = (dy+1)/(dx+1)
  89.     //    int         error = (-(dx+1) + (dy+1)) - (dx+1)
  90.     //                        = -dx - 1 + dy + 1 - dx -1
  91.     //                        =  dy-dy - dx-1
  92.     //                        = dy-2*dx-1
  93.     // bei Verkleinerung: dx und dy vertauscht
  94.     Clear(ziel, qubreite);
  95.     
  96.     if(qubreite<=zlbreite) {                // vergrößern
  97.         error= dy-2*dx-1;                       // (dy-dx - (dx+1))    
  98.         int sub=2*(dx+1), add=2*(dy+1), i = zlbreite;
  99.         //              ^ m*s            ^ 1*s
  100.         for(i=zlbreite; i; i--) {            // (i) prüfen ist schneller als (i<zlbreite)
  101.             ziel[x]++;
  102.             if(error>0) {
  103.                 x++;
  104.                 error-=sub;
  105.             } 
  106.             error+=add;
  107.         } 
  108.         return;
  109.     } else {    // verkleinern: dx und dy vertauscht, um in 1. Oktanden zu kommen
  110.         error= dx-2*dy-1;                           
  111.         int sub=2*(dy+1), add=2*(dx+1);        
  112.         for (int i = 0; i< qubreite; i++) {    // hier die langsame Version 
  113.             x++;
  114.             if(error>0) {
  115.                 ziel[x]++;
  116.                 error-=sub;
  117.             } 
  118.             error+=add;
  119.         }
  120.         return;
  121.     }     
  122. }
  123.  
  124. UBYTE breiteanz[2000];
  125. UBYTE hoeheanz[2000];
  126. struct RastPort trp;        // für WritePixelLine8
  127. struct BitMap tbm;        //            ""
  128.  
  129. // Scale: Skaliert Bild bild[][] mit Breite b und Hoehe h
  130.  
  131. void Scale(struct RastPort *rp, int dx, int dy, int x1, int y1) {
  132.     // dx/dy: Zielbreite/Höhe. x1/y1: Linke obere Ecke der Ausgabe
  133.  
  134.     if(!(dx||dy))    return;         // Eine Nullfläche brauchen wir nicht ausgeben
  135.     
  136.     // viel Administratives für WritePixelLine8    
  137.     UBYTE *zbrpuffer = new char[((dx+1 + 15)>>4)<<4];    // auf 16 aufgerundet
  138.     UBYTE *zhopuffer = new char[((dy+1 + 15)>>4)<<4];    
  139.     int     quelly = 0;
  140.  
  141.     // RastPort fertigmachen...
  142.     trp = *rp;                                trp.Layer = NULL;        tbm.Rows = 1;
  143.     tbm.Depth = rp->BitMap->Depth;    trp.BitMap = &tbm;
  144.     tbm.BytesPerRow = ((dx + 1 + 15) >> 4) << 1;        // Empfehlung des RKM
  145.     
  146.     struct BitMap *bm = trp.BitMap;
  147.     
  148.     // Eine Bitmap mit vier Zeilen, die danach als vier Bitmaps mit einer Zeile
  149.     // aufgefaßt wird
  150.     if(!(tbm.Planes[0] = AllocRaster(dx, rp->BitMap->Depth))) {
  151.         cout << "AllocRaster returnierte 0\n";
  152.         throw(int(1));
  153.     }
  154.     
  155.     for(int m = 1; m < rp->BitMap->Depth; m++) {
  156.         tbm.Planes[m] = tbm.Planes[0] + tbm.BytesPerRow * m * tbm.Rows;
  157.     }
  158.     
  159.     // Hier werden die Pixelbreiten berechnet:    
  160.     CalcProps(breiteanz, b, dx);
  161.     // und hier die Höhen:
  162.     CalcProps(hoeheanz, h, dy);
  163.     // -> breiteanz[i]: die Breiten der Pixel mit x=i
  164.     // -> hoeheanz[j]: die Höhen der Pixel mit y=j
  165.  
  166.     int dyc = dy+y1;
  167.     while(y1 < dyc) {
  168.         if(hoeheanz[quelly] > 0)                 // Wenn die Zeile überhaupt auftaucht...
  169.         {
  170.             WriteLine(bild[quelly],zbrpuffer,breiteanz,b);
  171.                 // Die Assembler-Version ist ein Ersatz für:
  172.                 //UBYTE *zbcp = zbrpuffer;
  173.              //for(int i=0; i < b; i++)
  174.              //    for(int j = 0; j < breiteanz[i]; j++)
  175.              //        *zbcp++ = bild[quelly][i];
  176.                 // ziemlich langsam
  177.             UBYTE anz = hoeheanz[quelly];
  178.             // die erste Zeile mit WritePixelLine8() ausgeben
  179.             if(anz) {
  180.                 WritePixelLine8(rp, x1,y1++, dx, zbrpuffer, &trp);
  181.                 anz--;
  182.             }
  183.             // im Ggs. zu einigen Grafikkarten-Routinen löscht WritePixelLine8()
  184.             // den Quellbereich zbrpuffer. Dafür steht eine Kopie der Zeile in bm
  185.             // d.h.: jede weitere Zeile einfach kopieren
  186.             while (anz--) {
  187.                 BltBitMapRastPort(bm, 0,0,rp,x1,y1++,dx,1,ABC|ABNC);
  188.             }
  189.         }
  190.         quelly++; 
  191.     }
  192.         
  193.     FreeRaster(tbm.Planes[0],dx, rp->BitMap->Depth);
  194.     delete zbrpuffer;
  195.     delete zhopuffer;
  196. }
  197.  
  198. // PollLoop: Paßt das Bild immer auf Fensterbreite an
  199.  
  200. void PollLoop() {
  201.     BOOL running = TRUE, mbpressed=FALSE;
  202.     struct IntuiMessage *imsg, icpy;
  203.     if(!win) return;
  204.     Scale(rp, win->Width - win->BorderLeft - win->BorderRight, 
  205.                 win->Height - win->BorderTop - win->BorderBottom,
  206.                 win->BorderLeft+1, win->BorderTop+1);
  207.     for(;;)
  208.     {
  209.         Wait(1 << win->UserPort->mp_SigBit);
  210.         while(imsg = (struct IntuiMessage*)GetMsg(win->UserPort)) 
  211.         {
  212.             icpy = *imsg;    // C++-Kopie
  213.             ReplyMsg((struct Message*)imsg);
  214.             switch(icpy.Class) 
  215.             {
  216.                 case IDCMP_CLOSEWINDOW:
  217.                     running = FALSE;
  218.                     break;
  219.                 case IDCMP_NEWSIZE:
  220.                     Scale(rp, win->Width - win->BorderLeft - win->BorderRight-1, 
  221.                                 win->Height - win->BorderTop - win->BorderBottom,
  222.                                 win->BorderLeft+1, win->BorderTop);
  223.                     break;
  224.             }
  225.         }
  226.         if(!running) break;
  227.     }
  228. }
  229.  
  230. // i.F. einige Vorversionen von CalcProps() (Version 1 ist ganz interessant)
  231.  
  232. /****
  233. void CalcProps(UBYTE *ziel, int qubreite, int zlbreite) {
  234.     double x = 0, y = 0, error, dx, dy;
  235.     int summe=0;
  236.     if(zlbreite > (qubreite<<8)) 
  237.     {
  238.         cout << "Zu groß. Höchstens 25500% möglich\n";
  239.         return;
  240.     }
  241.     BOOL kleiner = FALSE;
  242.     
  243.     if(qubreite >= zlbreite) {
  244.         kleiner = TRUE;
  245.     }
  246.     
  247.     dx = qubreite;            
  248.     dy = zlbreite;
  249.     
  250.     error = -dx-1;
  251.  
  252.     if(kleiner) {
  253.         for (int i = 0; i< zlbreite; i++) 
  254.         {
  255.             summe+=ziel[x];
  256.             x++;
  257.             if(error>=0) {
  258.                 ziel[x]++;
  259.                 //cout << "z["<<x<<"]="<<ziel[x]<<"; ";
  260.                 error-=dy+1;
  261.             } 
  262.             error+=2*dx+2;
  263.         }
  264.     if(summe != qubreite) cout << "Summe: "<<summe<<"; z: "<<zlbreite<<endl;
  265.     }
  266.     else 
  267.     {
  268.         for (int i = 0; i< qubreite; i++) {
  269.             ziel[x]++;
  270.             if(error>=0) {
  271.                 //cout << "z["<<x<<"]="<<ziel[x]<<"; ";
  272.                 summe+=ziel[x];
  273.                 x++;
  274.                 error-=dx+1;    // error-=0.5 skaliert mit 2*dy+1
  275.             } 
  276.             error+=2*dy+2;    // error+=m skaliert mit 2*(dx+1)
  277.         }
  278.     if(summe != zlbreite) cout << "Summe: "<<summe<<"; z: "<<zlbreite<<endl;
  279.     }
  280. }
  281.  
  282. // Version 1: mit doubles
  283. void CalcProps(UBYTE *ziel, int qubreite, int zlbreite) {
  284.     double x = 0, y = 0, error, dx=zlbreite, dy=qubreite, m;
  285.     int summe=0;
  286.     if(zlbreite > (qubreite<<8)) 
  287.     {
  288.         cout << "Zu groß. Höchstens 25500% möglich\n";
  289.         return;
  290.     }
  291.     BOOL kleiner = (qubreite>=zlbreite);
  292.  
  293.     // nur Vergrößerung
  294.     if(kleiner) {
  295.         return;
  296.     }    
  297.     for(int i=0; i<qubreite; i++) ziel[i]=0;
  298.  
  299.     // Fehler: 1 bis zwei Pixel -- wegen double-Fehler???
  300.     cout << "Vergrößerung von " << qubreite << " auf " << zlbreite << " Pixel\n";
  301.     m = (dy+1)/(dx+1);
  302.     error= 0.5 - 0.5*m;    // muss man sich mit einer Zeichnung klarmachen
  303.     cout << "Steigung: "<<m<<"; error = " << error << "\n";
  304.     for (i = 0; i< zlbreite; i++) {
  305.         ziel[x]++;
  306.         if(error>=0.5) {
  307.             summe+=ziel[x];
  308.             x++;
  309.             error--;
  310.         } 
  311.         error+=m;
  312.     }
  313.     if(summe != zlbreite) cout << "Summe: "<<summe<<"; z: "<<zlbreite<<endl;
  314.  
  315. }
  316.  
  317. void CalcProps(UBYTE *ziel, int qubreite, int zlbreite) {
  318.     int x = 0, y = 0, error, dx=zlbreite, dy=qubreite, m;
  319.     int summe=0;
  320.     if(zlbreite > (qubreite<<8)) 
  321.     {
  322.         cout << "Zu groß. Höchstens 25500% möglich\n";
  323.         return;
  324.     }
  325.     BOOL kleiner = (qubreite>=zlbreite);
  326.  
  327.     // nur Vergrößerung
  328.     if(kleiner) {
  329.         return;
  330.     }    
  331.     
  332.     // alle Werte mit 2*(dx+1) multipliziert
  333.     error= dy-dx;    
  334.     int sub=2*(dx+1);
  335.     int add=2*(dy+1);
  336.     for (i = 0; i< zlbreite; i++) {
  337.         ziel[x]++;
  338.         if(error>=dx+1) {
  339.             summe+=ziel[x];
  340.             x++;
  341.             error-=sub;
  342.         } 
  343.         error+=add;
  344.     }
  345.     if(qubreite != x) cout << "->Qubreite: " << qubreite << "; x: "<<x<<" (Fehler: "<<qubreite-x<<")"<<endl; 
  346.     if(summe != zlbreite) cout << "->Summe: "<<summe<<"; zlbreite: "<<zlbreite<<" (Fehler: "<<zlbreite-summe<<")"<<endl;
  347. }
  348.  
  349. ***/
  350.