home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 Mobile / Chip_Mobile_2001.iso / palm / spiele / argon / argon.exe / src / video.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-26  |  20.1 KB  |  850 lines

  1. /*
  2.   video.c - (c) 1999 by Till Harbaum
  3.  
  4.   4 bits per pixel video routines for ArgonV
  5.  
  6.   T.Harbaum@tu-bs.de - http://www.ibr.cs.tu-bs.de/~harbaum/pilot
  7.  
  8.   This program is distributed in the hope that it will be useful,
  9.   but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.   GNU General Public License for more details.
  12.  
  13. */
  14.  
  15. #include <Pilot.h>
  16.  
  17. #include "video.h"
  18. #include "argonv.h"
  19. #include "graphics.h"
  20.  
  21. #define CHECK   // define for some internal checks
  22.  
  23. #define LSSA  *((         void **)0xFFFFFA00)
  24. #define VPW   *((unsigned char  *)0xFFFFFA05)
  25. #define LYMAX *((unsigned short *)0xFFFFFA0A)
  26. #define LCXP  *((unsigned short *)0xFFFFFA18)
  27. #define LCYP  *((unsigned short *)0xFFFFFA1A)
  28. #define LCWCH *((unsigned short *)0xFFFFFA1C)
  29. #define LBLCK *((unsigned char  *)0xFFFFFA1F)
  30. #define PICF  *((unsigned char  *)0xFFFFFA20)
  31. #define LPXCD *((unsigned char  *)0xFFFFFA25)
  32. #define CKCON *((unsigned char  *)0xFFFFFA27)
  33. #define LLBAR *((unsigned char  *)0xFFFFFA29)
  34. #define LPOSR *((unsigned char  *)0xFFFFFA2D)
  35. #define FRCM  *((unsigned char  *)0xFFFFFA31)
  36. #define LGPMR *((unsigned short *)0xFFFFFA32)
  37.  
  38. #define VIDEO_WIDTH  192u
  39. #define VIDEO_HEIGHT 192u
  40. #define VIDEO_BUFFER (VIDEO_HEIGHT*(VIDEO_WIDTH/2))
  41.  
  42. #ifndef sysFtrNumProcessorID
  43. #define sysFtrNumProcessorID    2
  44. #define sysFtrNumProcessorMask  0xFFFF0000 // Mask to obtain processor model
  45. #define sysFtrNumProcessor328   0x00010000 // Motorola 68328 (Dragonball)
  46. #define sysFtrNumProcessorEZ    0x00020000 // Motorola 68EZ328 (Dragonball EZ)
  47. #endif
  48.  
  49. char *video_base = NULL, *draw_base;
  50. void *video_old_base;
  51. unsigned char lpxcd;
  52.  
  53. // size of level
  54. #define LLENGTH  (50)             // length in screens (identical to argoned)
  55. #define LENGTH   (LLENGTH*10)     // length in tiles
  56. #define BSIZE    (LENGTH*10)      // buffer size
  57. #define BEXTRA   (11*10)          // extra buffer
  58. #define BTOTAL   (BSIZE+2*BEXTRA) // total buffer size
  59. #define FG_LINES (LENGTH+10)      // length + 2*10 - 11
  60.  
  61. // image buffer
  62. unsigned char foreground_state[BTOTAL];   /* tile state information */
  63. unsigned char foreground_data[BTOTAL];    /* level data             */
  64.  
  65. void VideoAnimateForeground(int start) {
  66.   int i, a=0;
  67.   static cnt=0;
  68.   unsigned long r = SysRandom(0);
  69.  
  70.   for(i=start;i<(start+110);i++) {
  71.  
  72.     /* electro flash */
  73.     if(foreground_state[i] == 1) {
  74.       if(cnt&0x1c) foreground_data[i]=0;
  75.       else {
  76.     foreground_data[i] = FG_FLASH0+(r&3);
  77.     r >>= 2;
  78.     a++;
  79.       }
  80.     }
  81.  
  82.     /* reload randomizer */
  83.     if(a==16) {
  84.       r = SysRandom(0);
  85.       a = 0;
  86.     }
  87.   }
  88.   cnt++;
  89. }
  90.  
  91. /* CPU type detection code from Geoff Richmond */
  92. static Boolean VideoIsEZ(void) {
  93.  
  94.   DWord id, chip;
  95.   Err err;
  96.  
  97.   err = FtrGet(sysFtrCreator, sysFtrNumProcessorID, &id);
  98.   if (err) {
  99.     // can't get that feature; we must be on an old unit
  100.     // without it defined, thus we're on a DragonBall.
  101.     chip = sysFtrNumProcessor328;
  102.   } else
  103.     chip = id & sysFtrNumProcessorMask;
  104.  
  105.   return(chip != sysFtrNumProcessor328);
  106. }
  107.  
  108. /* information about locked resources */
  109. struct LockedRsc {
  110.   Handle ResH;
  111.   unsigned long *ResP;
  112. };
  113.  
  114. /* save buffer for locked resoures */
  115. struct LockedRsc  BackRsc[GRAPHIC_BACK];
  116. struct LockedRsc  ImagRsc[GRAPHIC_IMAG];
  117. struct LockedRsc  SprtRsc[GRAPHIC_SPRT];
  118. struct LockedRsc  FontRsc, ConvRsc, CSinRsc, LevlRsc;
  119.  
  120. /* sin and cos to export */
  121. char *VideoSin, *VideoCos;
  122.  
  123. Boolean LockRsc(struct LockedRsc *LRsc, int len, unsigned long type) {
  124.   int i;
  125.  
  126.   for(i=0;i<len;i++) {
  127.     LRsc[i].ResH = (Handle)DmGetResource( type, i);
  128. #ifdef CHECK
  129.     if(!LRsc[i].ResH) {
  130.       PRINTF("rsc err %s %d", &type, i);
  131.       return false;
  132.     }
  133. #endif    
  134.     LRsc[i].ResP = MemHandleLock((VoidHand)LRsc[i].ResH);
  135.   }
  136.   return true;
  137. }
  138.  
  139. void UnlockRsc(struct LockedRsc *LRsc, int len) {
  140.   int i;
  141.  
  142.   for(i=0;i<len;i++) {
  143.     MemPtrUnlock(LRsc[i].ResP);
  144.     DmReleaseResource((VoidHand) LRsc[i].ResH );
  145.   }
  146. }
  147.  
  148. Boolean VideoRscInit(void) {
  149.   if(!LockRsc( BackRsc, GRAPHIC_BACK, 'back')||    // background image
  150.      !LockRsc( ImagRsc, GRAPHIC_IMAG, 'imag')||    // foreground tiles
  151.      !LockRsc( SprtRsc, GRAPHIC_SPRT, 'sprt')||    // sprite
  152.      !LockRsc(&FontRsc,            1, 'font')||    // computer font
  153.      !LockRsc(&ConvRsc,            1, 'conv')||    // 1->4 bit conversion
  154.      !LockRsc(&CSinRsc,            1, 'csin')||    // sinus table
  155.      !LockRsc(&LevlRsc,            1, 'levl'))     // level data
  156.      return false;
  157.  
  158.   VideoSin = (char*)CSinRsc.ResP;
  159.   VideoCos = (char*)CSinRsc.ResP + 64;
  160.  
  161.   return true;
  162. }
  163.  
  164. void VideoInitLevel(void) {
  165.   int i;
  166.  
  167.   char *s = (char*)LevlRsc.ResP;
  168.   char *d = foreground_data;
  169.   char *k = foreground_state;
  170.  
  171.   /* top of buffer */
  172.   for(i=0;i<BEXTRA;i++)
  173.     *d++ = *k++ = 0;
  174.  
  175.   /* init foreground state buffer */
  176.   for(i=0;i<BSIZE;i++) {
  177.  
  178.     if((*s>=FG_FLASH0)&&(*s<=FG_FLASH3)) {
  179.       *k++ = 1;  /* state 1 = blizzard */
  180.     } else
  181.       *k++ = 0;
  182.  
  183.     *d++ = *s++;
  184.   }
  185.  
  186.   /* bottom of buffer */
  187.   for(i=0;i<BEXTRA;i++)
  188.     *d++ = *k++ = 0;
  189. }
  190.  
  191. void VideoRscRelease(void) {
  192.   UnlockRsc( BackRsc, GRAPHIC_BACK);
  193.   UnlockRsc( ImagRsc, GRAPHIC_IMAG);
  194.   UnlockRsc( SprtRsc, GRAPHIC_SPRT);
  195.   UnlockRsc(&FontRsc,            1);
  196.   UnlockRsc(&ConvRsc,            1);
  197.   UnlockRsc(&CSinRsc,            1);
  198.   UnlockRsc(&LevlRsc,            1);
  199. }
  200.  
  201. void VideoDrawText(int x, int y, unsigned char *str) {
  202.   unsigned long *dst= ((unsigned long*)draw_base)+ 2 + y*24 + x;
  203.   unsigned long *d, *conv = (unsigned long*)ConvRsc.ResP;
  204.   int i;
  205.   unsigned char *s;
  206.  
  207.   while(*str!=0) {
  208.     d = dst;
  209.     s = &(((unsigned char*)FontRsc.ResP) [8 * *str]);
  210.     
  211.     for(i=0;i<8;i++) {
  212.       *d |= conv[*s++];
  213.       d  += 24;
  214.     }
  215.   
  216.     str++;
  217.     dst++;
  218.   }
  219. }
  220.  
  221. void VideoDrawPartialText(int x, int y, unsigned char *str, 
  222.               int xbeg, int xend, int ybeg, int yend) {
  223.  
  224.   unsigned long *dst= ((unsigned long*)draw_base)+ 2 + (ybeg+y)*24 + x + xbeg;
  225.   unsigned long *d, *conv = (unsigned long*)ConvRsc.ResP;
  226.   int i, n = xend - xbeg;
  227.   unsigned char *s;
  228.  
  229.   str+=xbeg;
  230.  
  231.   while((*str!=0)&&(n-->=0)) {
  232.     d = dst;
  233.     s = &(((unsigned char*)FontRsc.ResP) [8 * *str + ybeg]);
  234.     
  235.     for(i=ybeg;i<=yend;i++) {
  236.       *d |= conv[*s++];
  237.       d  += 24;
  238.     }
  239.   
  240.     str++;
  241.     dst++;
  242.   }
  243. }
  244.  
  245. #ifdef ASM
  246. asm("
  247. .globl VideoDrawSprite
  248. VideoDrawSprite:
  249.     movem.l %d3-%d7/%a2-%a3/%a6,-(%sp)
  250.  
  251.     move.w 38(%sp),%d1           | Y
  252.     muls.w #96,%d1               | 48*Y
  253.     add.l draw_base(%a4),%d1     | drawbase+48*2*Y
  254.  
  255.         move.w 36(%sp),%d2           | X
  256.     move.w %d2,%d0
  257.     asr.w #2,%d0                 | /4
  258.     move.w %d0,%a0
  259.     add.l %a0,%a0                | *2
  260.  
  261.     lea (%a0,%d1.l),%a3          | dest addr0
  262.  
  263.     move.w 40(%sp),%d0
  264.     asl.w #3,%d0                 | sprite no * 8
  265.  
  266.     lea SprtRsc(%a4),%a0
  267.     move.l 4(%a0,%d0.w),%a1      | addr of sprite data
  268.  
  269.     lea ConvRsc(%a4),%a0
  270.     move.l 4(%a0),%a6            | conversion table
  271.  
  272.     move.w %d2,%d4
  273.     and.w #3,%d4
  274.     asl.w #2,%d4                 | xoffset
  275.  
  276.     moveq.l #32,%d3
  277.     sub.w %d4,%d3                | 32-(xoffset)
  278.  
  279.         move.w #15,%d6               | line counter
  280.  
  281. spr_next_line:
  282.         tst.w (%a1)                  | test mask
  283.         beq.s spr_skip               | skip this line
  284.  
  285.         clr.w  %d0
  286.     move.b (%a1)+,%d0            | 8 bit mask
  287.         asl.w #2,%d0
  288.     move.l (%a6,%d0.w),%d1       | 8->32 bits
  289.  
  290.     clr.w %d0
  291.     move.b (%a1)+,%d0            | next 8 bits
  292.     asl.w #2,%d0
  293.     move.l (%a6,%d0.w),%d2       | 8->32 bits
  294.  
  295.     move.l %d1,%d0
  296.     lsr.l %d4,%d0                | shift mask
  297.     not.l %d0
  298.     and.l %d0,(%a3)              | dest &= ~(mask1>>xoffset)
  299.  
  300.     asl.l %d3,%d1                | <<
  301.     move.l %d2,%d0               | mask2
  302.     lsr.l %d4,%d0                | >>xoffset
  303.     or.l %d0,%d1
  304.     not.l %d1                    | ~
  305.     and.l %d1,4(%a3)             | write
  306.  
  307.     asl.l %d3,%d2                | <<(32-xoffset)
  308.     not.l %d2                    | ~
  309.     and.l %d2,8(%a3)             | write
  310.  
  311.     move.l (%a1)+,%d1            | read sprite image
  312.     move.l (%a1)+,%d2            | dito
  313.  
  314.     move.l %d1,%d0
  315.     lsr.l %d4,%d0
  316.     or.l %d0,(%a3)+              | shift data 1
  317.  
  318.     asl.l %d3,%d1
  319.     move.l %d2,%d0
  320.         lsr.l %d4,%d0
  321.     or.l %d0,%d1
  322.     or.l %d1,(%a3)+              | shift data 2
  323.  
  324.     asl.l %d3,%d2
  325.     or.l %d2,(%a3)+              | shift data 3
  326.  
  327.     add.w #84,%a3                | next dest line
  328.  
  329.     dbra %d6, spr_next_line      | process next line
  330. spr_end:
  331.     movem.l (%sp)+,%d3-%d7/%a2-%a3/%a6
  332.     rts
  333.  
  334. spr_skip:
  335.         add.w #10,%a1
  336.     add.w #96,%a3                | next dest line
  337.  
  338.     dbra %d6, spr_next_line      | process next line
  339.         bra.s spr_end
  340.  
  341. ");
  342. #else
  343. void VideoDrawSprite(int x, int y, int spr) {
  344.   int i;
  345.   unsigned long  *d, s, m0,m1;
  346.   unsigned short *dest = ((unsigned short*)draw_base) + 48*y + x/4;
  347.   void *src  = SprtRsc[spr].ResP;
  348.   unsigned long *conv = (unsigned long*)ConvRsc.ResP;
  349.  
  350.   int n = (x&3)<<2;
  351.   int m = 32 - n;
  352.  
  353.   for(i=0;i<16;i++) {
  354.     d = (unsigned long*)dest;
  355.  
  356.     /* process four words per line */
  357.  
  358.     /* get mask */
  359.     m0 = (unsigned long)conv[*((unsigned char*)src)++];
  360.     m1 = (unsigned long)conv[*((unsigned char*)src)++];
  361.     *(d+0) &= ~ (m0 >> n);
  362.     *(d+1) &= ~((m0 << m)|(m1 >> n));
  363.     *(d+2) &= ~ (m1 << m);
  364.  
  365.     /* get data */
  366.     m0 = *((unsigned long*)src)++;
  367.     m1 = *((unsigned long*)src)++;
  368.     *(d+0) |=  (m0 >> n);
  369.     *(d+1) |= ((m0 << m)|(m1 >> n));
  370.     *(d+2) |=  (m1 << m);
  371.  
  372.     dest += 96/sizeof(unsigned short);
  373.   }
  374. }
  375. #endif
  376.  
  377. /* collision with background object */
  378. Boolean VideoHitBg(int index) {
  379.  
  380.   /* foregound_data[nnnn-1] == graphics/imagnnnn_gr.gif */
  381.   switch(foreground_data[index]) {
  382.  
  383.     /* electro fizzle */
  384.   case 0x06:
  385.   case 0x07:
  386.   case 0x08:
  387.   case 0x09:
  388.     damage(DAMAGE_FIZZLE);      /* damage ship */
  389.     return false;   /* no wall contact (don't push ship) */
  390.     break;
  391.     
  392.     /* boni (just collect) */
  393.   case 0x0a: /* triangle (shot increase) */
  394.     shot_mode++;
  395.     if(shot_mode > SHOT_TRIPLE) shot_mode = SHOT_TRIPLE;
  396.     else new_message("New Weapon");
  397.     goto bonus_remove;
  398.   case 0x0b: /* circle (shield reload) */
  399.     new_message("Shields up");
  400.     damage(DAMAGE_RELOAD);
  401.     goto bonus_remove;
  402.   case 0x0c: /* dot (bonus score) */
  403.     score_inc(SCORE_100);
  404.     new_message("Bonus score");
  405.     goto bonus_remove;
  406.   case 0x0d: /* star (faster shot) */
  407.     shot_reload++;
  408.     if(shot_reload > 2) shot_reload = 2;
  409.     new_message("Fast shot");
  410.     goto bonus_remove;
  411.   case 0x0e: /* 's' (restart here) */
  412.     new_message("Restart here");
  413.     ship_save_position();
  414.     goto bonus_remove;
  415.  
  416. bonus_remove:
  417.     foreground_data[index] = 0x00;  /* remove bonus tile */
  418.     return false;
  419.     break;
  420.   }
  421.  
  422.   /* hit something else: e.g. wall */
  423.   return true;
  424. }
  425.  
  426. /* this routine is ugly (but working) and might need to be replaced ... */
  427. Boolean VideoSpriteBgCollide(unsigned int ypos, int x, int y, int s) {
  428.   int i,k;
  429.   int xo, yo, n, m;
  430.   unsigned short *smask, *imask;
  431.  
  432.   /* sprite touches at most 4 background tiles */
  433.  
  434.   xo = x&0x0f;               /* x pos within block */
  435.   yo = ypos&0x0f;            /* y pos within scroll pos block */
  436.  
  437.   /* calculate foreground buffer index of left top tile */
  438.   k = 10*(FG_LINES-(ypos/16)%FG_LINES)+ 10*((y-yo)/16) + ((x-16)/16);
  439.  
  440.   yo = (y-yo)&0x0f;          /* y pos within block */
  441.  
  442.   smask = (unsigned short*)SprtRsc[s].ResP;   /* Pointer to sprite mask */
  443.  
  444.   /* sprite spans exactly one row */
  445.   if(xo==0) {
  446.     /* sprite spans exactly one line */
  447.  
  448.     if((m = foreground_data[k]) !=0) {
  449.       imask = ((unsigned short*)ImagRsc[m-1].ResP) + 5*yo;
  450.       
  451.       /* just compare masks */
  452.       for(n=yo;n<16;n++) {
  453.     if(((*imask) & (*smask)) != 0)
  454.       if(VideoHitBg(k)) return true;   /* hit the wall? return true */
  455.  
  456.     imask += 5; smask += 5;
  457.       }
  458.     } else
  459.       smask += (16-yo)*5;  /* just skip first block */
  460.  
  461.     /* were all lines in this first block? (sprite and bg are aligned) */
  462.     if(yo!=0) {
  463.       /* nope -> handle block below */
  464.       if((m = foreground_data[k+10]) !=0) {
  465.     imask = (unsigned short*)ImagRsc[m-1].ResP;
  466.  
  467.     /* just compare masks */
  468.     for(n=0;n<yo;n++) {
  469.       if(((*imask) & (*smask)) != 0) 
  470.         if(VideoHitBg(k+10)) return true;
  471.  
  472.       imask += 5; smask += 5;
  473.     }
  474.       }
  475.     }
  476.   } else {
  477.     /* sprite overlaps several columns */
  478.  
  479.     /* check left row top */
  480.     if((m = foreground_data[k]) !=0) {
  481.       imask = ((unsigned short*)ImagRsc[m-1].ResP) + 5*yo;
  482.       
  483.       /* just compare masks */
  484.       for(n=yo;n<16;n++) {
  485.     if((*imask & ((*smask)>>xo)) != 0) 
  486.       if(VideoHitBg(k)) return true;
  487.  
  488.     imask += 5; smask += 5;
  489.       }
  490.     } else
  491.       smask += (16-yo)*5;
  492.  
  493.     /* check left row bottom */
  494.     if(yo!=0) {
  495.       if((m = foreground_data[k+10]) !=0) {
  496.     imask = (unsigned short*)ImagRsc[m-1].ResP;
  497.       
  498.     /* just compare masks */
  499.     for(n=0;n<yo;n++) {
  500.       if((*imask & ((*smask)>>xo)) != 0) 
  501.         if(VideoHitBg(k+10)) return true;
  502.  
  503.       imask += 5; smask += 5;
  504.     }
  505.       }
  506.     }
  507.  
  508.     /* reload sprite pointer */
  509.     smask = (unsigned short*)SprtRsc[s].ResP;   /* Pointer to sprite mask */
  510.     xo = 16-xo;
  511.  
  512.     /* check right row top */
  513.     if((m = foreground_data[k+1]) !=0) {
  514.       imask = ((unsigned short*)ImagRsc[m-1].ResP) + 5*yo;
  515.       
  516.       /* just compare masks */
  517.       for(n=yo;n<16;n++) {
  518.     if((*imask & ((*smask)<<xo)) != 0) 
  519.       if(VideoHitBg(k+1)) return true;
  520.  
  521.     imask += 5; smask += 5;
  522.       }
  523.     } else
  524.       smask += (16-yo)*5;
  525.  
  526.     /* check right row bottom */
  527.     if(yo!=0) {
  528.       if((m = foreground_data[k+11]) !=0) {
  529.     imask = (unsigned short*)ImagRsc[m-1].ResP;
  530.       
  531.     /* just compare masks */
  532.     for(n=0;n<yo;n++) {
  533.       if((*imask & ((*smask)<<xo)) != 0) 
  534.         if(VideoHitBg(k+11)) return true;
  535.  
  536.       imask += 5; smask += 5;
  537.     }
  538.       }
  539.     }
  540.   }
  541.   return false;
  542. }
  543.  
  544. Boolean VideoSpriteCollide(int x1, int y1, int s1, int x2, int y2, int s2) {
  545.   int xdiff, ydiff;
  546.   unsigned short *mask1, *mask2;
  547.   int n;
  548.  
  549.   /* handle vertical intersection */
  550.   if(y2>y1) {                        // sprite 2 is lower
  551.     ydiff = y2-y1;
  552.     if(ydiff >= 16) return false;    // sprites don't overlap
  553.     mask1 = &(((unsigned short*)SprtRsc[s1].ResP)[5*ydiff]);
  554.     mask2 =    (unsigned short*)SprtRsc[s2].ResP;
  555.   } else {                           // sprite 1 is lower
  556.     ydiff = y1-y2;
  557.     if(ydiff >= 16) return false;    // sprites don't overlap
  558.     mask1 =    (unsigned short*)SprtRsc[s1].ResP;
  559.     mask2 = &(((unsigned short*)SprtRsc[s2].ResP)[5*ydiff]);
  560.   }
  561.  
  562.   /* handle horizontal intersection */
  563.   if(x2>x1) {
  564.     xdiff = x2-x1;
  565.     if(xdiff >= 16) return false;    // sprites don't overlap
  566.  
  567.     for(n=0;n<(16-ydiff);n++) {
  568.       if((( *mask2 >> xdiff ) & *mask1) ) return true;  // hit
  569.  
  570.       mask1 += 5;
  571.       mask2 += 5;
  572.     }
  573.  
  574.   } else {
  575.     xdiff = x1-x2;
  576.     if(xdiff >= 16) return false;    // sprites don't overlap
  577.  
  578.     for(n=0;n<(16-ydiff);n++) {
  579.       if((( *mask1 >> xdiff ) & *mask2) ) return true;  // hit
  580.  
  581.       mask1 += 5;
  582.       mask2 += 5;
  583.     }
  584.   }
  585.   return false;
  586.  
  587. #ifdef ASM
  588. asm("
  589. .globl VideoFgLine
  590. VideoFgLine:
  591.     movem.l %d4-%d6/%a2-%a3,-(%sp)
  592.     move.l 24(%sp),%d6            | destination address
  593.     move.w 28(%sp),%d5            | offset of tile in buffer
  594.  
  595.     lea ConvRsc(%a4),%a0
  596.         move.l 4(%a0),%a2             | get address of 1->4 conversion table
  597.  
  598.         lea ImagRsc(%a4),%a3          | image data
  599.         addq.l #4,%a3
  600.  
  601.     move.w #9,%d4                 | tile counter
  602.  
  603. next_tile:
  604.     lea foreground_data(%a4),%a0
  605.         clr.w %d0
  606.     move.b (%a0,%d5.w),%d0        | read tile id
  607.     addq.w #1,%d5                 | next tile
  608.  
  609.     tst.w %d0                     | no tile here?
  610.     jbeq empty_tile
  611.  
  612.     subq.w #1,%d0
  613.     asl.w #3,%d0                  | 2*(id-1)
  614.  
  615.     move.l (%a3,%d0.w),%a1        | ressource data pointer
  616.  
  617.     move.l %d6,%a0                | dest address
  618.     move.w #15,%d2
  619.     clr.w %d1
  620.  
  621. next_line:
  622.         clr %d0
  623.     move.b (%a1)+,%d0             | get 8 bits pixel mask
  624.         not.b %d0
  625.     asl #2,%d0                    | * 4
  626.  
  627.     move.l (%a2,%d0.w),%d0        | converted mask
  628.         and.l (%a0),%d0
  629.  
  630.     clr %d1
  631.     move.b (%a1)+,%d1             | get next mask byte
  632.         not.b %d1
  633.     asl #2,%d1                    | * 4
  634.  
  635.     move.l (%a2,%d1.w),%d1        | converted mask
  636.         and.l 4(%a0),%d1 
  637.  
  638.         or.l (%a1)+, %d0              | combine with image data
  639.         move.l %d0, (%a0)+            | and map to screen
  640.  
  641.         or.l (%a1)+, %d1              | combine with image data
  642.         move.l %d1, (%a0)+            | and map to screen
  643.  
  644.     add.w #88,%a0                 | next screen line
  645.  
  646.         dbra %d2, next_line
  647.  
  648. empty_tile:
  649.     addq.l #8,%d6                 | next dest tile address
  650.     dbra %d4, next_tile           | once more
  651.  
  652.     movem.l (%sp)+,%d4-%d6/%a2-%a3
  653.     rts
  654. ");
  655. #else
  656. void VideoFgLine(unsigned long *dst, int tile) {
  657.   int i,j,k;
  658.   unsigned long *d;
  659.   void *s;
  660.   unsigned long *conv = (unsigned long*)ConvRsc.ResP;
  661.  
  662.   /* ten tiles per line */
  663.   for(i=0;i<10;i++) {
  664.     k = foreground_data[tile++];
  665.  
  666.     /* tile contains data */
  667.     if(k!=0) {
  668.       s = ImagRsc[k-1].ResP;
  669.  
  670.       /* tile has 16 lines */
  671.       for(d=dst,j=0;j<16;j++) {
  672.     *d     &= ~conv[*((unsigned char*)s)++];
  673.     *(d+1) &= ~conv[*((unsigned char*)s)++];
  674.     
  675.     *d++   |= *((unsigned long*)s)++;
  676.     *d++   |= *((unsigned long*)s)++;
  677.     
  678.     d += (96-8)/sizeof(long);
  679.       }
  680.     }
  681.  
  682.     /* next row */
  683.     dst+=2;
  684.   }
  685. }
  686. #endif
  687.  
  688. void VideoDrawTitleBg(void) {
  689.   static int y=10;
  690.  
  691.   /* generate background */
  692.   MemMove(draw_base+VIDEO_WIDTH*8 + (160-(y/2))*96, 
  693.       BackRsc[0].ResP,      (y/2)*96);
  694.   MemMove(draw_base+VIDEO_WIDTH*8,            
  695.       BackRsc[0].ResP+(y/2)*24, (VIDEO_WIDTH*80)-(y/2)*96);
  696.  
  697.   if(y-- == 0) y=320;
  698. }
  699.  
  700. void VideoDrawBackground(unsigned int ypos) {
  701.   int i,j,k;
  702.   unsigned long *dst;
  703.   extern void score_inc(int amount);
  704.  
  705.   /* generate background */
  706.   i = 159-(ypos%320)/2;
  707.   MemMove(draw_base+VIDEO_WIDTH*8 + (160-i)*96, 
  708.       BackRsc[0].ResP,      i*96);
  709.   MemMove(draw_base+VIDEO_WIDTH*8,            
  710.       BackRsc[0].ResP+i*24, (VIDEO_WIDTH*80)-i*96);
  711.  
  712.   /* generate foreground */
  713.   i = ypos & 0x0f;
  714.   k = 10*(FG_LINES-(ypos/16)%FG_LINES);
  715.  
  716.   VideoAnimateForeground(k);
  717.  
  718.   if(i==0) {
  719.     dst = (unsigned long*)(draw_base+VIDEO_WIDTH*8+8);
  720.  
  721.     for(j=0;j<10;j++) {
  722.       k += 10;
  723.       VideoFgLine(dst, k);
  724.       dst += 16*24;
  725.     }
  726.   } else {
  727.  
  728.     dst = (unsigned long*)(draw_base - 64*24 + 8 + VIDEO_WIDTH*8 + i*96 );
  729.     for(j=0;j<11;j++) {
  730.       VideoFgLine(dst, k);
  731.       k += 10;
  732.       dst += 16*24;
  733.     }
  734.  
  735.   }
  736.  
  737.   /* offset within this level */
  738.   i = ypos%(16*FG_LINES);
  739.  
  740.   /* draw start and end messages */
  741.   if(i == 0)              
  742.     new_message(  "GET READY!");
  743.  
  744.   if(i == 16*(LENGTH+1)) {
  745.     new_message("STAGE FINISHED");
  746.     score_inc(SCORE_STAGE);
  747.   }
  748. }
  749.  
  750. void VideoFlip(void) {
  751.   static int page=0;
  752.  
  753.   draw_base = video_base + ((page)?VIDEO_BUFFER:0);
  754.  
  755.   LSSA      = video_base + ((VIDEO_WIDTH/2)*16) + 8 +
  756.                            ((page)?0:VIDEO_BUFFER);
  757.  
  758.   page ^= 1;
  759. }
  760.  
  761. Boolean VideoGreyscaleOn(void) {
  762.   int i,j;
  763.  
  764.   if(!VideoIsEZ()) {
  765.     FrmCustomAlert(alt_err,"Argon V requires a Palm IIIx, Palm V or Visor.",0,0);
  766.     return false;
  767.   }
  768.  
  769.   if(video_base != NULL) return false;
  770.  
  771.   /* allocate buffer memory */
  772.   if((video_base = MemPtrNew(2*VIDEO_BUFFER)) == NULL) {
  773.     FrmCustomAlert(alt_err,"Out of memory allocating video buffer.",0,0);
  774.     return false;
  775.   }
  776.  
  777.   draw_base = video_base + VIDEO_BUFFER;
  778.   MemSet(video_base, VIDEO_BUFFER, 0);
  779.  
  780.   if(!VideoRscInit()) {
  781.     video_base = NULL;
  782.     return false;
  783.   }
  784.  
  785.   /* save old video base */
  786.   video_old_base = LSSA;
  787.  
  788.   /* save old refresh value and set to full refresh */
  789.   lpxcd = LPXCD;
  790.   LPXCD = 0;
  791.  
  792.   CKCON &= ~0x80; /* display off */
  793.  
  794.   /* virtual page width now 80 bytes (160 greyscale pixels) */
  795.   VPW   = 48;
  796.   PICF |= 0x02;      /* switch to 4 bit grayscale mode */
  797.   LLBAR = 40;        /* line buffer now 80 bytes */
  798.  
  799.   /* register to control grayscale pixel oscillations */
  800.   FRCM = 0xB9;
  801.   
  802.   /* set new video base address */
  803.   LSSA = video_base + ((VIDEO_WIDTH/2)*16)+8;
  804.   
  805.   /* let the LCD get to a 2 new frames (40ms delay) */
  806.   SysTaskDelay(4);
  807.   
  808.   /* switch LCD back on */
  809.   CKCON |= 0x80;
  810.  
  811.   return true;
  812. }
  813.  
  814. void VideoGreyscaleOff(void) {
  815.  
  816.   if(video_base != NULL) {
  817.  
  818.     VideoRscRelease();
  819.  
  820.     /* free video buffer */
  821.     MemPtrFree(video_base);
  822.     video_base = NULL;
  823.  
  824.     /* switch off LCD update temporarily */
  825.     CKCON &= ~0x80;
  826.   
  827.     /* virtual page width now 20 bytes (160 pixels) */
  828.     VPW    = 10;
  829.     PICF  &= ~0x03;  /* switch to black and white mode */
  830.     LLBAR  = 10;     /* line buffer now 20 bytes */
  831.  
  832.     /* let the LCD get to a new frame (20ms delay) */
  833.     SysTaskDelay(4);
  834.   
  835.     /* switch LCD back on in new mode */
  836.     CKCON |= 0x80;
  837.  
  838.     /* stop hardware scrolling */
  839.     LPOSR = 0;
  840.  
  841.     /* restore old video base */
  842.     LSSA = video_old_base;
  843.  
  844.     /* restore old refresh value */
  845.     LPXCD = lpxcd;
  846.   }
  847. }
  848.  
  849.