home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1998 #5 / AmigaPlus_CD-ROM_Nr.5-98.iso / pd / musik / playmf / fireworks / source / parabolic.c < prev    next >
C/C++ Source or Header  |  1998-04-03  |  15KB  |  611 lines

  1.  
  2. /*-------------------------------------------------*/
  3. /* fireworks.c - graphical MIDI note visualisation */
  4. /*          ® 1998 by Christian Buchner            */
  5. /*-------------------------------------------------*/
  6.  
  7. #include "fireworks.h"
  8. #include "fireworks_protos.h"
  9. #include "fwmodes.h"
  10.  
  11. #include "parabolic_protos.h"
  12.  
  13. extern UBYTE randomarray33[256];
  14. extern UWORD chip WaitPointer[];
  15.  
  16. /*------------------------------------------*/
  17. /* Parabolic fireworks (gravity simulation) */
  18. /*------------------------------------------*/
  19.  
  20. #define K 10
  21. #define MAXLIFETIME (K*MAXCOORD)
  22.  
  23. struct ParData
  24. {
  25.     struct Globals *glob;
  26.     struct Prefs *pref;
  27.     
  28.     ULONG curtime;
  29.     
  30.     WORD centx, centy;
  31.     WORD divx, divy;
  32.     UWORD winscale;
  33.     
  34.     struct MinList CrackerList;
  35.     
  36.     WORD fxtab[128], fytab[128];
  37.     WORD  parabtable[MAXLIFETIME];    /* parabolic flight path */
  38.     UWORD parabskip[MAXLIFETIME];    /* info for painting flight paths */
  39. };
  40.  
  41. #define SCALE 1024
  42.  
  43. /* the firecrackers */
  44.  
  45. struct ParabolicCracker
  46. {
  47.     struct Node        cr_node;
  48.     UBYTE            cr_chn;            /* 0 - 15  */
  49.     UBYTE            cr_note;        /* 0 - 127 */
  50.     UBYTE            cr_vel;            /* 0 - 127 */
  51.     
  52.     LONG            cr_starttime;        /* time stamp of note on */
  53.     LONG            cr_stoptime;        /* time stamp of note off */
  54.     
  55.     WORD            cr_fx;            /* -SCALE to SCALE equals -1 to -1 */
  56.     WORD            cr_fy;            /* -SCALE to SCALE equals -1 to -1 */
  57.     
  58.     UWORD            cr_offset;        /* offset to lifetime */
  59.     WORD            cr_coordoffset;    /* offset to coordinate */
  60.     
  61.     UWORD            cr_multiplier;    /* time skip multiplier (0 to SCALE) */
  62.     
  63.     WORD            cr_sparkx;        /* for painting sparks */
  64.     WORD            cr_sparky;
  65. };
  66.  
  67. APTR Par_InitFireworks(struct Globals *glob, struct Prefs *pref)
  68. {
  69.     struct ParData *pd = NULL;
  70.     UWORD i;
  71.     UWORD lt;
  72.     WORD val;
  73.     
  74.     if (pd = AllocVec(sizeof(struct ParData), MEMF_ANY|MEMF_CLEAR))
  75.     {
  76.         pd->glob = glob;
  77.         pd->pref = pref;
  78.         
  79.         NewList((struct List*)&pd->CrackerList);
  80.         
  81.         BusyPointer(glob, pref);
  82.         
  83.         /* pre-calculate angles of all possible 128 notes */
  84.         for (i = 0 ; i < 128 ; i++)
  85.         {
  86.             float angle = PI - (float)i/127 * PI;
  87.             
  88.             pd->fxtab[i] = SCALE * cos(angle);
  89.             pd->fytab[i] = SCALE * sin(angle);
  90.         }
  91.         
  92.         val = -(MAXLIFETIME/2);
  93.         
  94.         for (lt=0 ; lt <= MAXLIFETIME/2 ; lt++, val++)
  95.         {
  96.             pd->parabtable[lt] = pd->parabtable[MAXLIFETIME-1-lt] =
  97.                 (LONG)(val * val) / ((MAXLIFETIME*MAXLIFETIME/4) / (K * MAXCOORD / 4));
  98.         }
  99.         
  100.         if (pref->FWMode == ParabolicMode2)
  101.         {
  102.             val = -(MAXLIFETIME/2);
  103.             
  104.             for (lt=0 ; lt <= MAXLIFETIME/2 ; )
  105.             {
  106.                 UWORD s = (64.0 * pow(1+4*(float)(val*val)/(MAXLIFETIME*MAXLIFETIME/4),1.5));
  107.                 
  108.                 for (i=0; i<16; i++)
  109.                 {
  110.                     pd->parabskip[lt] = pd->parabskip[MAXLIFETIME-1-lt] = s;
  111.                     lt++; val++;
  112.                 }
  113.             }
  114.         }
  115.         
  116.         NormalPointer(glob, pref);
  117.         
  118.         Par_RethinkWindow((APTR)pd);
  119.         
  120.         GetTimeDelta();            /* initialize delta counter */
  121.         pd->curtime = 0;        /* start at time counter 0 */
  122.     }
  123.     
  124.     return((APTR)pd);
  125. }
  126.  
  127. void Par_RethinkWindow(APTR data)
  128. {
  129.     struct ParData *pd = (struct ParData*) data;
  130.     struct Globals *glob = pd->glob;
  131.     
  132.     /* Calculate ray scaling factors */
  133.     pd->divx  = SCALE * MAXCOORD / (glob->ww);
  134.     pd->divy  = SCALE * MAXCOORD / (glob->wh);
  135.     pd->centx = CENTER_X * (glob->ww) / MAXCOORD;
  136.     pd->centy = CENTER_Y * (glob->wh) / MAXCOORD;
  137.     
  138.     /* for min...max window size range from (3*SCALE)...SCALE */
  139.     pd->winscale = SCALE * (3 * MAXCOORD) / (glob->ww + glob->wh + MAXCOORD);
  140. }
  141.  
  142. void Par_TimePassed(APTR data)
  143. {
  144.     struct ParData *pd = (struct ParData*) data;
  145.     
  146.     pd->curtime += GetTimeDelta();
  147. }
  148.  
  149. BOOL Par_IsIdle(APTR data)
  150. {
  151.     struct ParData *pd = (struct ParData*) data;
  152.     
  153.     if (IsListEmpty((struct List*)&pd->CrackerList))
  154.         return(TRUE);
  155.     else
  156.         return(FALSE);
  157. }
  158.  
  159. void Par_DrawFireworks(APTR data, UWORD Mask)
  160. {
  161.     struct ParData *pd = (struct ParData*) data;
  162.     struct ParabolicCracker *cr, *ncr;
  163.     struct Globals *glob = pd->glob;
  164.     struct Prefs *pref = pd->pref;
  165.     
  166.     UWORD lifetime;
  167.     UWORD lt;
  168.     WORD sx1, sy1;
  169.     LONG lastpen = -1, newpen;
  170.     UWORD margin = (pref->Flags & PREFF_DOUBLE) ? 1 : 0;
  171.     
  172.     struct Layer *SaveLayer = glob->PaintRP.Layer;
  173.     glob->PaintRP.Layer = NULL;        /* we do our own clipping here */
  174.     
  175.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  176.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  177.           cr = ncr )
  178.     {
  179.         /* get the pixel's lifetime information */
  180.         
  181.         if ((pd->curtime - cr->cr_starttime) < MAXLIFETIME)
  182.             lifetime = (UWORD)(pd->curtime - cr->cr_starttime);
  183.         else
  184.             lifetime = MAXLIFETIME-1;
  185.         
  186.         lt = lifetime + cr->cr_offset;
  187.         if (lt >= MAXLIFETIME)
  188.         {
  189.             lt = MAXLIFETIME-1;
  190.             lifetime = lt - cr->cr_offset;
  191.         }
  192.         
  193.         /* calculate pixel coordinate */
  194.         sx1 = pd->centx + cr->cr_fx * lifetime                  / pd->divx;
  195.         sy1 = pd->centy
  196.             + (pd->parabtable[lt] - cr->cr_coordoffset) * SCALE / pd->divy;
  197.         
  198.         /* see if the pixel has disappeared */
  199.         /* or exceeded its maximum lifetime */
  200.         if ( (sx1 >= (glob->ww-margin)) || (sy1 >= (glob->wh-margin)) ||
  201.              (sx1 < 0) || lt >= (MAXLIFETIME-1) )
  202.         {
  203.             Remove((struct Node*)cr);
  204.             FreePooled(glob->NotePool,cr,sizeof(struct ParabolicCracker));
  205.         }
  206.         else
  207.         {
  208.             /* display this channel ? */
  209.             if ((1<<cr->cr_chn) & Mask)
  210.             {
  211.                 /* change pen if necessary */
  212.                 newpen = glob->PenArray[Channelpens+cr->cr_chn];
  213.                 if (lastpen != newpen)
  214.                 {
  215.                     SetAPen(&glob->PaintRP, newpen);
  216.                     lastpen = newpen;
  217.                 }
  218.                 
  219.                 if (sy1 >= 0)
  220.                 {
  221.                     /* draw the pixel */
  222.                     WritePixel(&glob->PaintRP, sx1, sy1);
  223.                     if (pref->Flags & PREFF_DOUBLE)
  224.                     {
  225.                         WritePixel(&glob->PaintRP, sx1+1, sy1  );
  226.                         WritePixel(&glob->PaintRP, sx1  , sy1+1);
  227.                         WritePixel(&glob->PaintRP, sx1+1, sy1+1);
  228.                     }
  229.                 }
  230.                 if (pref->Flags & PREFF_SPARKS)
  231.                 {
  232.                     cr->cr_sparkx = sx1;
  233.                     cr->cr_sparky = sy1;
  234.                 }
  235.             }
  236.         }
  237.     }
  238.     
  239.     if (pref->Flags & PREFF_SPARKS)
  240.     {
  241.         SetAPen(&glob->PaintRP, glob->PenArray[Sparkpen]);
  242.         
  243.         for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  244.               ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  245.               cr = ncr )
  246.         {
  247.             /* display this channel ? */
  248.             if ((1<<cr->cr_chn) & Mask)
  249.             {
  250.                 UWORD margin = (pref->Flags & PREFF_DOUBLE) ? 2 : 1;
  251.                 UBYTE rnd = (pd->curtime>>6) + cr->cr_starttime + cr->cr_note;
  252.                 
  253.                 if (randomarray33[rnd])
  254.                 {
  255.                     sx1 = cr->cr_sparkx;
  256.                     sy1 = cr->cr_sparky;
  257.                     
  258.                     if ((sx1 >= margin) && (sy1 >= margin) &&
  259.                         (sx1 < (glob->ww - margin)) &&
  260.                         (sy1 < (glob->wh - margin)) )
  261.                         glob->PaintRP.Layer = NULL;
  262.                     else
  263.                         glob->PaintRP.Layer = SaveLayer;
  264.                     
  265.                     RectFill(&glob->PaintRP, sx1-margin, sy1-margin, sx1+margin, sy1+margin);
  266.                 }
  267.             }
  268.         }
  269.     }
  270.     
  271.     glob->PaintRP.Layer = SaveLayer;
  272. }
  273.  
  274. void Par_NoteOn(APTR data, UBYTE chn, UBYTE note, UBYTE vel, LONG reltime)
  275. {
  276.     struct ParData *pd = (struct ParData*) data;
  277.     struct Globals *glob = pd->glob;
  278.     struct Prefs *pref = pd->pref;
  279.     struct ParabolicCracker *cr;
  280.     WORD absfx;
  281.     
  282.     if (cr = AllocPooled(glob->NotePool, sizeof(struct ParabolicCracker)))
  283.     {
  284.         cr->cr_node.ln_Pri = chn;
  285.         
  286.         cr->cr_chn  = chn;
  287.         cr->cr_note = note;
  288.         cr->cr_vel  = vel;
  289.         
  290.         cr->cr_starttime = pd->curtime - reltime;
  291.         cr->cr_stoptime  = -1;
  292.         cr->cr_fx = pd->fxtab[note] * cr->cr_vel / 127 * pref->Sensitivity / 100;
  293.         cr->cr_fy = pd->fytab[note] * cr->cr_vel / 127 * pref->Sensitivity / 100;
  294.         
  295.         cr->cr_offset      = (MAXLIFETIME/2) * (SCALE-cr->cr_fy) / SCALE;
  296.         cr->cr_coordoffset = pd->parabtable[cr->cr_offset];
  297.         
  298.         if (pref->FWMode == ParabolicMode2)
  299.         {
  300.             absfx = cr->cr_fx;
  301.             if (absfx < 0) absfx = -absfx;
  302.             
  303.             /* for absfx=0...1 -> range from (2*SCALE)...(SCALE/2) */
  304.             cr->cr_multiplier = (SCALE*SCALE)/((UWORD)((SCALE/2)+3*absfx/2));
  305.         }
  306.         
  307.         /* sorted by channel num to speed up painting */
  308.         Enqueue((struct List*)&pd->CrackerList, (struct Node*)cr);
  309.     }
  310. }
  311.  
  312. void Par_NoteOff(APTR data, UBYTE chn, UBYTE note, LONG reltime)
  313. {
  314.     struct ParData *pd = (struct ParData*) data;
  315.     struct ParabolicCracker *cr, *ncr;
  316.     
  317.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  318.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  319.           cr = ncr )
  320.     {
  321.         if ( (cr->cr_chn  == chn ) &&
  322.              (cr->cr_note == note) &&
  323.              (cr->cr_stoptime == -1) )
  324.         {
  325.             cr->cr_stoptime = pd->curtime - reltime;
  326.             break;
  327.         }
  328.     }
  329. }
  330.  
  331. void Par_ReleaseNotes(APTR data, LONG reltime)
  332. {
  333.     struct ParData *pd = (struct ParData*) data;
  334.     struct ParabolicCracker *cr, *ncr;
  335.     
  336.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  337.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  338.           cr = ncr )
  339.     {
  340.         if (cr->cr_stoptime == -1) cr->cr_stoptime = pd->curtime - reltime;
  341.     }
  342. }
  343.  
  344. void Par_FreeNoteData(APTR data)
  345. {
  346.     struct ParData *pd = (struct ParData*) data;
  347.     struct Globals *glob = pd->glob;
  348.     struct ParabolicCracker *cr, *ncr;
  349.     
  350.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  351.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  352.           cr = ncr )
  353.     {
  354.         Remove((struct Node*)cr);
  355.         FreePooled(glob->NotePool,cr,sizeof(struct ParabolicCracker));
  356.     }
  357. }
  358.  
  359. void Par_ExitFireworks(APTR data)
  360. {
  361.     struct ParData *pd = (struct ParData*) data;
  362.     
  363.     if (pd)
  364.     {
  365.         Par_FreeNoteData(data);
  366.         
  367.         FreeVec(pd);
  368.     }
  369. }
  370.  
  371.  
  372.  
  373. /*-------------------------------------*/
  374. /* Parabolic rays (gravity simulation) */
  375. /*-------------------------------------*/
  376.  
  377. void Par_DrawFireworks2(APTR data, UWORD Mask)
  378. {
  379.     struct ParData *pd = (struct ParData*) data;
  380.     struct ParabolicCracker *cr, *ncr;
  381.     struct Globals *glob = pd->glob;
  382.     struct Prefs *pref = pd->pref;
  383.     
  384.     UWORD lifetime;
  385.     UWORD deathtime;
  386.     UWORD lt, dt, t;
  387.     WORD sx1, sy1;
  388.     WORD sx2, sy2;
  389.     WORD dx, dy;
  390.     LONG lastpen = -1, newpen;
  391.     UWORD margin = (pref->Flags & PREFF_DOUBLE) ? 1 : 0;
  392.     
  393.     struct Layer *SaveLayer = glob->PaintRP.Layer;
  394.     glob->PaintRP.Layer = NULL;    /* most of the time we do our own clipping */
  395.     
  396.     for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  397.           ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  398.           cr = ncr )
  399.     {
  400.         /* get the parabolic ray's lifetime information */
  401.         
  402.         if ((pd->curtime - cr->cr_starttime) < MAXLIFETIME)
  403.             lifetime = (UWORD)(pd->curtime - cr->cr_starttime);
  404.         else
  405.             lifetime = MAXLIFETIME-1;
  406.         
  407.         lt = lifetime + cr->cr_offset;
  408.         if (lt >= MAXLIFETIME)
  409.         {
  410.             lt = MAXLIFETIME-1;
  411.             lifetime = lt - cr->cr_offset;
  412.         }
  413.         
  414.         /* has ray already been stopped by a note off? */
  415.         if (cr->cr_stoptime == -1)
  416.         {
  417.             deathtime = 0;
  418.         }
  419.         else
  420.         {
  421.             if ((pd->curtime - cr->cr_stoptime) < MAXLIFETIME)
  422.                 deathtime = (UWORD)(pd->curtime - cr->cr_stoptime);
  423.             else
  424.                 deathtime = MAXLIFETIME-1;
  425.         }
  426.         
  427.         dt = deathtime + cr->cr_offset;
  428.         if (dt >= MAXLIFETIME)
  429.         {
  430.             dt = MAXLIFETIME-1;
  431.             deathtime = dt - cr->cr_offset;
  432.         }
  433.         
  434.         /* calculate parabolic ray coordinate */
  435.         sx1 = pd->centx + cr->cr_fx * deathtime                 / pd->divx;
  436.         sy1 = pd->centy
  437.             + (pd->parabtable[dt] - cr->cr_coordoffset) * SCALE / pd->divy;
  438.         
  439.         /* see if the parabolic ray has disappeared */
  440.         /* or exceeded its maximum lifetime */
  441.         if ( (sx1 >= (glob->ww-margin)) || (sy1 >= (glob->wh-margin)) ||
  442.              (sx1 < 0) || dt >= (MAXLIFETIME-1) )
  443.         {
  444.             Remove((struct Node*)cr);
  445.             FreePooled(glob->NotePool,cr,sizeof(struct ParabolicCracker));
  446.         }
  447.         else
  448.         {
  449.             /* display this channel ? */
  450.             if ((1<<cr->cr_chn) & Mask)
  451.             {
  452.                 /* change pen if necessary */
  453.                 newpen = glob->PenArray[Channelpens+cr->cr_chn];
  454.                 if (lastpen != newpen)
  455.                 {
  456.                     SetAPen(&glob->PaintRP, newpen);
  457.                     lastpen = newpen;
  458.                 }
  459.                 
  460.                 if (lifetime == deathtime)
  461.                 {
  462.                     if (sy1 >= 0)
  463.                     {
  464.                         /* draw the pixel */
  465.                         WritePixel(&glob->PaintRP, sx1, sy1);
  466.                         if (pref->Flags & PREFF_DOUBLE)
  467.                         {
  468.                             WritePixel(&glob->PaintRP, sx1+1, sy1  );
  469.                             WritePixel(&glob->PaintRP, sx1  , sy1+1);
  470.                             WritePixel(&glob->PaintRP, sx1+1, sy1+1);
  471.                         }
  472.                     }
  473.                 }
  474.                 else
  475.                 {
  476.                     BOOL Invisible = FALSE;
  477.                     
  478.                     BOOL Clean = (sy1 >= 0) ? TRUE : FALSE;
  479.                     
  480.                     /* a wide flightpath and a large window will result */
  481.                     /* in the most detailed plot */
  482.                     UWORD scale = SCALE * pd->winscale      / SCALE
  483.                                         * cr->cr_multiplier / SCALE;
  484.                     
  485.                     glob->PaintRP.Layer = SaveLayer;
  486.                     
  487.                     Move(&glob->PaintRP, sx1, sy1);
  488.                     
  489.                     for ( t=dt ; t<lt ; )
  490.                     {
  491.                         UWORD skip = pd->parabskip[t] * scale / SCALE;
  492.                         
  493.                         if (skip == 0) skip = 1;
  494.                         
  495.                         deathtime += skip;
  496.                         t         += skip;
  497.                         
  498.                         if (t>lt)
  499.                         {
  500.                             t=lt;
  501.                             deathtime=lifetime;
  502.                         }
  503.                         
  504.                         if (sy1 < 0) Invisible = TRUE;
  505.                         
  506.                         if ((sx1 >= (glob->ww)) || (sx1 < 0) || (sy1 > (glob->wh)))
  507.                             break;
  508.                         
  509.                         sx2 = sx1;
  510.                         sy2 = sy1;
  511.                         
  512.                         sx1 = pd->centx + cr->cr_fx * deathtime                / pd->divx;
  513.                         sy1 = pd->centy
  514.                             + (pd->parabtable[t] - cr->cr_coordoffset) * SCALE / pd->divy;
  515.                         
  516.                         if (Invisible)
  517.                         {
  518.                             if (sy1 >= 0)
  519.                             {
  520.                                 Move(&glob->PaintRP, sx2, sy2);
  521.                                 Invisible = FALSE;
  522.                             }
  523.                         }
  524.                         
  525.                         if (!Invisible)
  526.                         {
  527.                             if ((sx1 >= 0) && (sx1 < (glob->ww - margin)) &&
  528.                                 (sy1 >= 0) && (sy1 < (glob->wh - margin)) )
  529.                             {
  530.                                 if (Clean)
  531.                                     glob->PaintRP.Layer = NULL;
  532.                                 else
  533.                                     Clean = TRUE;
  534.                             }
  535.                             else
  536.                             {
  537.                                 if (Clean)
  538.                                 {
  539.                                     glob->PaintRP.Layer = SaveLayer;
  540.                                     Clean = FALSE;
  541.                                 }
  542.                             }
  543.                             
  544.                             Draw(&glob->PaintRP, sx1, sy1);
  545.                             //WritePixel(&glob->PaintRP, sx1, sy1);
  546.                             
  547.                             if (pref->Flags & PREFF_DOUBLE)
  548.                             {
  549.                                 dx = sx2 - sx1; if (dx<0) dx=-dx;
  550.                                 dy = sy2 - sy1; if (dy<0) dy=-dy;
  551.                                 
  552.                                 if (dy >= dx)
  553.                                 {
  554.                                     Move(&glob->PaintRP, sx2+1, sy2);
  555.                                     Draw(&glob->PaintRP, sx1+1, sy1);
  556.                                 }
  557.                                 else
  558.                                 {
  559.                                     Move(&glob->PaintRP, sx2, sy2+1);
  560.                                     Draw(&glob->PaintRP, sx1, sy1+1);
  561.                                 }
  562.                                 
  563.                                 Move(&glob->PaintRP, sx1, sy1);
  564.                             }
  565.                         }
  566.                     }
  567.                 }
  568.                 if (pref->Flags & PREFF_SPARKS)
  569.                 {
  570.                     cr->cr_sparkx = sx1;
  571.                     cr->cr_sparky = sy1;
  572.                 }
  573.             }
  574.         }
  575.     }
  576.     
  577.     if (pref->Flags & PREFF_SPARKS)
  578.     {
  579.         SetAPen(&glob->PaintRP, glob->PenArray[Sparkpen]);
  580.         
  581.         for ( cr = (struct ParabolicCracker*) pd->CrackerList.mlh_Head ;
  582.               ncr = (struct ParabolicCracker*) cr->cr_node.ln_Succ ;
  583.               cr = ncr )
  584.         {
  585.             /* display this channel ? */
  586.             if ((1<<cr->cr_chn) & Mask)
  587.             {
  588.                 UWORD margin = (pref->Flags & PREFF_DOUBLE) ? 2 : 1;
  589.                 UBYTE rnd = (pd->curtime>>6) + cr->cr_starttime + cr->cr_note;
  590.                 
  591.                 if (randomarray33[rnd])
  592.                 {
  593.                     sx1 = cr->cr_sparkx;
  594.                     sy1 = cr->cr_sparky;
  595.                     
  596.                     if ((sx1 >= margin) && (sy1 >= margin) &&
  597.                         (sx1 < (glob->ww - margin)) &&
  598.                         (sy1 < (glob->wh - margin)) )
  599.                         glob->PaintRP.Layer = NULL;
  600.                     else
  601.                         glob->PaintRP.Layer = SaveLayer;
  602.                     
  603.                     RectFill(&glob->PaintRP, sx1-margin, sy1-margin, sx1+margin, sy1+margin);
  604.                 }
  605.             }
  606.         }
  607.     }
  608.     
  609.     glob->PaintRP.Layer = SaveLayer;
  610. }
  611.