]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_rf.c
==== animation fram walk ==== i polished the shit out of it and it works MUCH better...
[16.git] / src / lib / 16_rf.c
1 /* Keen Dreams Source Code\r
2  * Copyright (C) 2014 Javier M. Chavez\r
3  *\r
4  * This program is free software; you can redistribute it and/or modify\r
5  * it under the terms of the GNU General Public License as published by\r
6  * the Free Software Foundation; either version 2 of the License, or\r
7  * (at your option) any later version.\r
8  *\r
9  * This program is distributed in the hope that it will be useful,\r
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
12  * GNU General Public License for more details.\r
13  *\r
14  * You should have received a copy of the GNU General Public License along\r
15  * with this program; if not, write to the Free Software Foundation, Inc.,\r
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
17  */\r
18 \r
19 // 16_RF.C\r
20 \r
21 /*\r
22 =============================================================================\r
23 \r
24 notes\r
25 -----\r
26 \r
27 scrolling more than one tile / refresh forces a total redraw\r
28 \r
29 two overlapping sprites of equal priority can change drawing order when\r
30 updated\r
31 \r
32 =============================================================================\r
33 */\r
34 \r
35 #include "src/lib/16_rf.h"\r
36 #pragma hdrstop\r
37 \r
38 /*\r
39 =============================================================================\r
40 \r
41                                                  LOCAL CONSTANTS\r
42 \r
43 =============================================================================\r
44 */\r
45 \r
46 #define SCREENTILESWIDE 20\r
47 #define SCREENTILESHIGH 13\r
48 \r
49 #define SCREENSPACE             (SCREENWIDTH*240)\r
50 #define FREEEGAMEM              (0x10000l-3l*SCREENSPACE)\r
51 \r
52 //\r
53 // the update array must have enough space for two screens that can float\r
54 // up two two tiles each way\r
55 //\r
56 // (PORTTILESWIDE+1)*PORTTILESHIGH must be even so the arrays can be cleared\r
57 // by word width instructions\r
58 \r
59 #define UPDATESCREENSIZE        (UPDATEWIDE*PORTTILESHIGH+2)\r
60 #define UPDATESPARESIZE         (UPDATEWIDE*2+4)\r
61 #define UPDATESIZE                      (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
62 \r
63 #define G_EGASX_SHIFT   7       // global >> ?? = screen x\r
64 #define G_CGASX_SHIFT   6       // global >> ?? = screen x\r
65 #define G_SY_SHIFT              4       // global >> ?? = screen y\r
66 \r
67 unsigned        SX_T_SHIFT;             // screen x >> ?? = tile EGA = 1, CGA = 2;\r
68 #define SY_T_SHIFT              4       // screen y >> ?? = tile\r
69 \r
70 \r
71 #define EGAPORTSCREENWIDE       42\r
72 #define CGAPORTSCREENWIDE       84\r
73 #define PORTSCREENHIGH  224\r
74 \r
75 #define UPDATESCREENSIZE        (UPDATEWIDE*PORTTILESHIGH+2)\r
76 #define UPDATESPARESIZE         (UPDATEWIDE*2+4)\r
77 #define UPDATESIZE                      (UPDATESCREENSIZE+2*UPDATESPARESIZE)\r
78 \r
79 /*\r
80 =============================================================================\r
81 \r
82                                                    LOCAL TYPES\r
83 \r
84 =============================================================================\r
85 */\r
86 \r
87 typedef struct spriteliststruct\r
88 {\r
89         int                     screenx,screeny;\r
90         int                     width,height;\r
91 \r
92         unsigned        grseg,sourceofs,planesize;\r
93         drawtype        draw;\r
94         unsigned        tilex,tiley,tilewide,tilehigh;\r
95         int                     priority,updatecount;\r
96         struct spriteliststruct **prevptr,*nextsprite;\r
97 } spritelisttype;\r
98 \r
99 \r
100 typedef struct\r
101 {\r
102         int                     screenx,screeny;\r
103         int                     width,height;\r
104 } eraseblocktype;\r
105 \r
106 \r
107 typedef struct\r
108 {\r
109         unsigned        current;                // foreground tiles have high bit set\r
110         int                     count;\r
111 } tiletype;\r
112 \r
113 \r
114 typedef struct animtilestruct\r
115 {\r
116         unsigned        x,y,tile;\r
117         tiletype        *chain;\r
118         unsigned        far *mapplane;\r
119         struct animtilestruct **prevptr,*nexttile;\r
120 } animtiletype;\r
121 \r
122 /*\r
123 =============================================================================\r
124 \r
125                                                  GLOBAL VARIABLES\r
126 \r
127 =============================================================================\r
128 */\r
129 \r
130 unsigned        tics;\r
131 long            lasttimecount;\r
132 \r
133 boolean         compatability;                  // crippled refresh for wierdo SVGAs\r
134 \r
135 unsigned        mapwidth,mapheight,mapbyteswide,mapwordswide\r
136                         ,mapbytesextra,mapwordsextra;\r
137 unsigned        mapbwidthtable[MAXMAPHEIGHT];\r
138 \r
139 //\r
140 // Global : Actor coordinates are in this, at 1/16 th of a pixel, to allow\r
141 // for fractional movement and acceleration.\r
142 //\r
143 // Tiles  : Tile offsets from the upper left corner of the current map.\r
144 //\r
145 // Screen : Graphics level offsets from map origin, x in bytes, y in pixels.\r
146 // originxscreen is the same spot as originxtile, just with extra precision\r
147 // so graphics don't need to be done in tile boundaries.\r
148 //\r
149 \r
150 unsigned        originxglobal,originyglobal;\r
151 unsigned        originxtile,originytile;\r
152 unsigned        originxscreen,originyscreen;\r
153 unsigned        originmap;\r
154 unsigned        originxmin,originxmax,originymin,originymax;\r
155 unsigned        originxtile,originytile;\r
156 \r
157 unsigned        masterofs;\r
158 \r
159 //\r
160 // Table of the offsets from bufferofs of each tile spot in the\r
161 // view port.  The extra wide tile should never be drawn, but the space\r
162 // is needed to account for the extra 0 in the update arrays.  Built by\r
163 // RF_Startup\r
164 //\r
165 \r
166 unsigned        blockstarts[UPDATEWIDE*UPDATEHIGH];\r
167 unsigned        updatemapofs[UPDATEWIDE*UPDATEHIGH];\r
168 \r
169 unsigned        uwidthtable[PORTTILESHIGH];             // lookup instead of multiply\r
170 \r
171 byte            update[2][UPDATESIZE];\r
172 byte            *updateptr,*baseupdateptr,                                              // current start of update window\r
173                         *updatestart[2],\r
174                         *baseupdatestart[2];\r
175 \r
176 //from others\r
177 cardtype        videocard;              // set by VW_Startup\r
178 grtype          grmode;                 // CGAgr, EGAgr, VGAgr\r
179 \r
180 unsigned        bufferofs;              // hidden area to draw to before displaying\r
181 unsigned        displayofs;             // origin of the visable screen\r
182 //\r
183 \r
184 /*\r
185 =============================================================================\r
186 \r
187                                                  LOCAL VARIABLES\r
188 \r
189 =============================================================================\r
190 */\r
191 #ifdef PROFILE\r
192 static          char    scratch[20],str[20];\r
193 #endif\r
194 \r
195 tiletype        allanims[MAXANIMTYPES];\r
196 unsigned        numanimchains;\r
197 \r
198 void            (*refreshvector) (void);\r
199 \r
200 unsigned        screenstart[3] =\r
201         {0,SCREENSPACE,SCREENSPACE*2};\r
202 \r
203 unsigned        xpanmask;                       // prevent panning to odd pixels\r
204 \r
205 unsigned        screenpage;                     // screen currently being displayed\r
206 unsigned        otherpage;\r
207 \r
208 #if GRMODE == EGAGR\r
209 unsigned        tilecache[NUMTILE16];\r
210 #endif\r
211 \r
212 spritelisttype  spritearray[MAXSPRITES],*prioritystart[PRIORITIES],\r
213                                 *spritefreeptr;\r
214 \r
215 animtiletype    animarray[MAXANIMTILES],*animhead,*animfreeptr;\r
216 \r
217 int                             animfreespot;\r
218 \r
219 eraseblocktype  eraselist[2][MAXSPRITES],*eraselistptr[2];\r
220 \r
221 /*\r
222 =============================================================================\r
223 \r
224                                                  LOCAL PROTOTYPES\r
225 \r
226 =============================================================================\r
227 */\r
228 \r
229 void RFL_NewTile (unsigned updateoffset);\r
230 void RFL_MaskForegroundTiles (void);\r
231 void RFL_UpdateTiles (void);\r
232 \r
233 void RFL_CalcOriginStuff (long x, long y);\r
234 void RFL_InitSpriteList (void);\r
235 void RFL_InitAnimList (void);\r
236 void RFL_CheckForAnimTile (unsigned x, unsigned y);\r
237 void RFL_AnimateTiles (void);\r
238 void RFL_RemoveAnimsOnX (unsigned x);\r
239 void RFL_RemoveAnimsOnY (unsigned y);\r
240 void RFL_EraseBlocks (void);\r
241 void RFL_UpdateSprites (void);\r
242 \r
243 \r
244 /*\r
245 =============================================================================\r
246 \r
247                                          GRMODE INDEPENDANT ROUTINES\r
248 \r
249 =============================================================================\r
250 */\r
251 \r
252 \r
253 /*\r
254 =====================\r
255 =\r
256 = RF_Startup\r
257 =\r
258 =====================\r
259 */\r
260 \r
261 static  char *ParmStrings[] = {"comp",""};\r
262 \r
263 void RF_Startup (void)\r
264 {\r
265         int i,x,y;\r
266         unsigned        *blockstart;\r
267 \r
268         if (grmode == EGAGR)\r
269                 for (i = 1;i < _argc;i++)\r
270                         if (US_CheckParm(_argv[i],ParmStrings) == 0)\r
271                         {\r
272                                 compatability = true;\r
273                                 break;\r
274                         }\r
275 \r
276         for (i=0;i<PORTTILESHIGH;i++)\r
277                 uwidthtable[i] = UPDATEWIDE*i;\r
278 \r
279         originxmin = originymin = MAPBORDER*TILEGLOBAL;\r
280 \r
281         eraselistptr[0] = &eraselist[0][0];\r
282         eraselistptr[1] = &eraselist[1][0];\r
283 \r
284 \r
285 \r
286         if (grmode == EGAGR)\r
287         {\r
288                 SX_T_SHIFT = 1;\r
289 \r
290                 baseupdatestart[0] = &update[0][UPDATESPARESIZE];\r
291                 baseupdatestart[1] = &update[1][UPDATESPARESIZE];\r
292 \r
293                 screenpage = 0;\r
294                 otherpage = 1;\r
295                 displayofs = screenstart[screenpage];\r
296                 bufferofs = screenstart[otherpage];\r
297                 masterofs = screenstart[2];\r
298 \r
299                 updateptr = baseupdatestart[otherpage];\r
300 \r
301                 blockstart = &blockstarts[0];\r
302                 for (y=0;y<UPDATEHIGH;y++)\r
303                         for (x=0;x<UPDATEWIDE;x++)\r
304                                 *blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH;\r
305 \r
306                 xpanmask = 6;   // dont pan to odd pixels\r
307         }\r
308 \r
309         else if (grmode == CGAGR)\r
310         {\r
311                 SX_T_SHIFT = 2;\r
312 \r
313                 updateptr = baseupdateptr = &update[0][UPDATESPARESIZE];\r
314 \r
315                 bufferofs = 0;\r
316                 masterofs = 0x8000;\r
317 \r
318                 blockstart = &blockstarts[0];\r
319                 for (y=0;y<UPDATEHIGH;y++)\r
320                         for (x=0;x<UPDATEWIDE;x++)\r
321                                 *blockstart++ = SCREENWIDTH*16*y+x*TILEWIDTH;\r
322         }\r
323 }\r
324 \r
325 \r
326 \r
327 \r
328 /*\r
329 =====================\r
330 =\r
331 = RF_Shutdown\r
332 =\r
333 =====================\r
334 */\r
335 \r
336 void RF_Shutdown (void)\r
337 {\r
338 \r
339 }\r
340 \r
341 //===========================================================================\r
342 \r
343 /*\r
344 =====================\r
345 =\r
346 = RF_NewMap\r
347 =\r
348 = Makes some convienient calculations based on maphead->\r
349 =\r
350 =====================\r
351 */\r
352 /*++++\r
353 void RF_NewMap (void)\r
354 {\r
355         int i,x,y;\r
356         unsigned spot,*table;\r
357 \r
358         mapwidth = mapheaderseg[mapon]->width;\r
359         mapbyteswide = 2*mapwidth;\r
360         mapheight = mapheaderseg[mapon]->height;\r
361         mapwordsextra = mapwidth-PORTTILESWIDE;\r
362         mapbytesextra = 2*mapwordsextra;\r
363 \r
364 //\r
365 // make a lookup table for the maps left edge\r
366 //\r
367         spot = 0;\r
368         for (i=0;i<mapheight;i++)\r
369         {\r
370           mapbwidthtable[i] = spot;\r
371           spot += mapbyteswide;\r
372         }\r
373 \r
374 //\r
375 // fill in updatemapofs with the new width info\r
376 //\r
377         table = &updatemapofs[0];\r
378         for (y=0;y<PORTTILESHIGH;y++)\r
379                 for (x=0;x<UPDATEWIDE;x++)\r
380                         *table++ = mapbwidthtable[y]+x*2;\r
381 \r
382 \r
383 //\r
384 // the y max value clips off the bottom half of a tile so a map that is\r
385 // 13 + MAPBORDER*2 tile high will not scroll at all vertically\r
386 //\r
387         originxmax = (mapwidth-MAPBORDER-SCREENTILESWIDE)*TILEGLOBAL;\r
388         originymax = (mapheight-MAPBORDER-SCREENTILESHIGH)*TILEGLOBAL;\r
389         if (originxmax<originxmin)              // for very small maps\r
390                 originxmax=originxmin;\r
391         if (originymax<originymin)\r
392                 originymax=originymin;\r
393 \r
394 //\r
395 // clear out the lists\r
396 //\r
397         RFL_InitSpriteList ();\r
398         RFL_InitAnimList ();\r
399 \r
400 \r
401         lasttimecount = TimeCount;              // setup for adaptive timing\r
402         tics = 1;\r
403 }\r
404 */\r
405 //===========================================================================\r
406 \r
407 /*\r
408 ==========================\r
409 =\r
410 = RF_MarkTileGraphics\r
411 =\r
412 = Goes through mapplane[0/1] and marks all background/foreground tiles\r
413 = needed, then follows all animation sequences to make sure animated\r
414 = tiles get all the stages.  Every unique animating tile is given an\r
415 = entry in allanims[], so every instance of that tile will animate at the\r
416 = same rate.  The info plane for each animating tile will hold a pointer\r
417 = into allanims[], therefore you can't have both an animating foreground\r
418 = and background tile in the same spot!\r
419 =\r
420 ==========================\r
421 */\r
422 /*++++\r
423 void RF_MarkTileGraphics (void)\r
424 {\r
425         unsigned        size;\r
426         int                     tile,next,anims;\r
427         unsigned        far     *start,far *end,far *info;\r
428         unsigned        i,tilehigh;\r
429 \r
430         memset (allanims,0,sizeof(allanims));\r
431         numanimchains = 0;\r
432 \r
433         size = mapwidth*mapheight;\r
434 \r
435 //\r
436 // background plane\r
437 //\r
438         start = mapsegs[0];\r
439         info = mapsegs[2];\r
440         end = start+size;\r
441         do\r
442         {\r
443                 tile = *start++;\r
444                 if (tile>=0)                    // <0 is a tile that is never drawn\r
445                 {\r
446                         CA_MarkGrChunk(STARTTILE16+tile);\r
447                         if (tinf[ANIM+tile])\r
448                         {\r
449                                 // this tile will animated\r
450 \r
451                                 for (i=0;i<numanimchains;i++)\r
452                                         if (allanims[i].current == tile)\r
453                                         {\r
454                                                 *info = (unsigned)&allanims[i];\r
455                                                 goto nextback;\r
456                                         }\r
457 \r
458                                 // new chain of animating tiles\r
459 \r
460                                 if (i>=MAXANIMTYPES)\r
461                                         //Quit ("RF_MarkTileGraphics: Too many unique animated tiles!");\r
462                                 allanims[i].current = tile;\r
463                                 allanims[i].count = tinf[SPEED+tile];\r
464 \r
465                                 *info = (unsigned)&allanims[i];\r
466                                 numanimchains++;\r
467 \r
468                                 anims = 0;\r
469                                 next = tile+(signed char)(tinf[ANIM+tile]);\r
470                                 while (next != tile)\r
471                                 {\r
472                                         CA_MarkGrChunk(STARTTILE16+next);\r
473                                         next += (signed char)(tinf[ANIM+next]);\r
474                                         if (++anims > 20)\r
475                                                 //Quit ("MarkTileGraphics: Unending animation!");\r
476                                 }\r
477 \r
478                         }\r
479                 }\r
480 nextback:\r
481                 info++;\r
482         } while (start<end);\r
483 \r
484 //\r
485 // foreground plane\r
486 //\r
487         start = mapsegs[1];\r
488         info = mapsegs[2];\r
489         end = start+size;\r
490         do\r
491         {\r
492                 tile = *start++;\r
493                 if (tile>=0)                    // <0 is a tile that is never drawn\r
494                 {\r
495                         CA_MarkGrChunk(STARTTILE16M+tile);\r
496                         if (tinf[MANIM+tile])\r
497                         {\r
498                                 // this tile will animated\r
499 \r
500                                 tilehigh = tile | 0x8000;       // foreground tiles have high bit\r
501                                 for (i=0;i<numanimchains;i++)\r
502                                         if (allanims[i].current == tilehigh)\r
503                                         {\r
504                                                 *info = (unsigned)&allanims[i];\r
505                                                 goto nextfront;\r
506                                         }\r
507 \r
508                                 // new chain of animating tiles\r
509 \r
510                                 if (i>=MAXANIMTYPES)\r
511                                         //Quit ("RF_MarkTileGraphics: Too many unique animated tiles!");\r
512                                 allanims[i].current = tilehigh;\r
513                                 allanims[i].count = tinf[MSPEED+tile];\r
514 \r
515                                 *info = (unsigned)&allanims[i];\r
516                                 numanimchains++;\r
517 \r
518                                 anims = 0;\r
519                                 next = tile+(signed char)(tinf[MANIM+tile]);\r
520                                 while (next != tile)\r
521                                 {\r
522                                         CA_MarkGrChunk(STARTTILE16M+next);\r
523                                         next += (signed char)(tinf[MANIM+next]);\r
524                                         if (++anims > 20)\r
525                                                 //Quit ("MarkTileGraphics: Unending animation!");\r
526                                 }\r
527 \r
528                         }\r
529                 }\r
530 nextfront:\r
531                 info++;\r
532         } while (start<end);\r
533 }\r
534 */\r
535 \r
536 //===========================================================================\r
537 \r
538 \r
539 /*\r
540 =========================\r
541 =\r
542 = RFL_InitAnimList\r
543 =\r
544 = Call to clear out the entire animating tile list and return all of them to\r
545 = the free list.\r
546 =\r
547 =========================\r
548 */\r
549 \r
550 void RFL_InitAnimList (void)\r
551 {\r
552         int     i;\r
553 \r
554         animfreeptr = &animarray[0];\r
555 \r
556         for (i=0;i<MAXANIMTILES-1;i++)\r
557                 animarray[i].nexttile = &animarray[i+1];\r
558 \r
559         animarray[i].nexttile = NULL;\r
560 \r
561         animhead = NULL;                        // nothing in list\r
562 }\r
563 \r
564 \r
565 /*\r
566 ====================\r
567 =\r
568 = RFL_CheckForAnimTile\r
569 =\r
570 ====================\r
571 */\r
572 /*++++\r
573 void RFL_CheckForAnimTile (unsigned x, unsigned y)\r
574 {\r
575         unsigned        tile,offset,speed,lasttime,thistime,timemissed;\r
576         unsigned        far *map;\r
577         animtiletype    *anim,*next;\r
578 \r
579 // the info plane of each animating tile has a near pointer into allanims[]\r
580 // which gives the current state of all concurrently animating tiles\r
581 \r
582         offset = mapbwidthtable[y]/2+x;\r
583 \r
584 //\r
585 // background\r
586 //\r
587         map = mapsegs[0]+offset;\r
588         tile = *map;\r
589         if (tinf[ANIM+tile])\r
590         {\r
591                 if (!animfreeptr)\r
592                         //Quit ("RF_CheckForAnimTile: No free spots in tilearray!");\r
593                 anim = animfreeptr;\r
594                 animfreeptr = animfreeptr->nexttile;\r
595                 next = animhead;                                // stick it at the start of the list\r
596                 animhead = anim;\r
597                 if (next)\r
598                         next->prevptr = &anim->nexttile;\r
599                 anim->nexttile = next;\r
600                 anim->prevptr = &animhead;\r
601 \r
602                 anim->x = x;\r
603                 anim->y = y;\r
604                 anim->tile = tile;\r
605                 anim->mapplane = map;\r
606                 anim->chain = (tiletype *)*(mapsegs[2]+offset);\r
607         }\r
608 \r
609 //\r
610 // foreground\r
611 //\r
612         map = mapsegs[1]+offset;\r
613         tile = *map;\r
614         if (tinf[MANIM+tile])\r
615         {\r
616                 if (!animfreeptr)\r
617                         //Quit ("RF_CheckForAnimTile: No free spots in tilearray!");\r
618                 anim = animfreeptr;\r
619                 animfreeptr = animfreeptr->nexttile;\r
620                 next = animhead;                                // stick it at the start of the list\r
621                 animhead = anim;\r
622                 if (next)\r
623                         next->prevptr = &anim->nexttile;\r
624                 anim->nexttile = next;\r
625                 anim->prevptr = &animhead;\r
626 \r
627                 anim->x = x;\r
628                 anim->y = y;\r
629                 anim->tile = tile;\r
630                 anim->mapplane = map;\r
631                 anim->chain = (tiletype *)*(mapsegs[2]+offset);\r
632         }\r
633 \r
634 }\r
635 */\r
636 \r
637 /*\r
638 ====================\r
639 =\r
640 = RFL_RemoveAnimsOnX\r
641 =\r
642 ====================\r
643 */\r
644 \r
645 void RFL_RemoveAnimsOnX (unsigned x)\r
646 {\r
647         animtiletype *current,*next;\r
648 \r
649         current = animhead;\r
650         while (current)\r
651         {\r
652                 if (current->x == x)\r
653                 {\r
654                         *(void **)current->prevptr = current->nexttile;\r
655                         if (current->nexttile)\r
656                                 current->nexttile->prevptr = current->prevptr;\r
657                         next = current->nexttile;\r
658                         current->nexttile = animfreeptr;\r
659                         animfreeptr = current;\r
660                         current = next;\r
661                 }\r
662                 else\r
663                         current = current->nexttile;\r
664         }\r
665 }\r
666 \r
667 \r
668 /*\r
669 ====================\r
670 =\r
671 = RFL_RemoveAnimsOnY\r
672 =\r
673 ====================\r
674 */\r
675 \r
676 void RFL_RemoveAnimsOnY (unsigned y)\r
677 {\r
678         animtiletype *current,*next;\r
679 \r
680         current = animhead;\r
681         while (current)\r
682         {\r
683                 if (current->y == y)\r
684                 {\r
685                         *(void **)current->prevptr = current->nexttile;\r
686                         if (current->nexttile)\r
687                                 current->nexttile->prevptr = current->prevptr;\r
688                         next = current->nexttile;\r
689                         current->nexttile = animfreeptr;\r
690                         animfreeptr = current;\r
691                         current = next;\r
692                 }\r
693                 else\r
694                         current = current->nexttile;\r
695         }\r
696 }\r
697 \r
698 \r
699 /*\r
700 ====================\r
701 =\r
702 = RFL_AnimateTiles\r
703 =\r
704 ====================\r
705 */\r
706 /*++++\r
707 void RFL_AnimateTiles (void)\r
708 {\r
709         animtiletype *current;\r
710         unsigned        updateofs,tile,x,y;\r
711         tiletype        *anim;\r
712 \r
713 //\r
714 // animate the lists of tiles\r
715 //\r
716         anim = &allanims[0];\r
717         while (anim->current)\r
718         {\r
719                 anim->count-=tics;\r
720                 while ( anim->count < 1)\r
721                 {\r
722                         if (anim->current & 0x8000)\r
723                         {\r
724                                 tile = anim->current & 0x7fff;\r
725                                 tile += (signed char)tinf[MANIM+tile];\r
726                                 anim->count += tinf[MSPEED+tile];\r
727                                 tile |= 0x8000;\r
728                         }\r
729                         else\r
730                         {\r
731                                 tile = anim->current;\r
732                                 tile += (signed char)tinf[ANIM+tile];\r
733                                 anim->count += tinf[SPEED+tile];\r
734                         }\r
735                         anim->current = tile;\r
736                 }\r
737                 anim++;\r
738         }\r
739 \r
740 \r
741 //\r
742 // traverse the list of animating tiles\r
743 //\r
744         current = animhead;\r
745         while (current)\r
746         {\r
747                 tile =current->chain->current;\r
748                 if ( tile != current->tile)\r
749                 {\r
750                 // tile has animated\r
751                 //\r
752                 // remove tile from master screen cache,\r
753                 // change a tile to its next state, set the structure up for\r
754                 // next animation, and post an update region to both update pages\r
755                 //\r
756                         current->tile = tile;\r
757 \r
758                         *(current->mapplane) = tile & 0x7fff;           // change in map\r
759 \r
760 #if GRMODE == EGAGR\r
761                         if (tile<0x8000)                // background\r
762                                 tilecache[tile] = 0;\r
763 #endif\r
764 \r
765                         x = current->x-originxtile;\r
766                         y = current->y-originytile;\r
767 \r
768                         if (x>=PORTTILESWIDE || y>=PORTTILESHIGH)\r
769                                 //Quit ("RFL_AnimateTiles: Out of bounds!");\r
770 \r
771                         updateofs = uwidthtable[y] + x;\r
772                         RFL_NewTile(updateofs);                         // puts "1"s in both pages\r
773                 }\r
774                 current = current->nexttile;\r
775         }\r
776 }\r
777 */\r
778 \r
779 //===========================================================================\r
780 \r
781 /*\r
782 =========================\r
783 =\r
784 = RFL_InitSpriteList\r
785 =\r
786 = Call to clear out the entire sprite list and return all of them to\r
787 = the free list.\r
788 =\r
789 =========================\r
790 */\r
791 \r
792 void RFL_InitSpriteList (void)\r
793 {\r
794         int     i;\r
795 \r
796         spritefreeptr = &spritearray[0];\r
797         for (i=0;i<MAXSPRITES-1;i++)\r
798                 spritearray[i].nextsprite = &spritearray[i+1];\r
799 \r
800         spritearray[i].nextsprite = NULL;\r
801 \r
802 // NULL in all priority levels\r
803 \r
804         memset (prioritystart,0,sizeof(prioritystart));\r
805 }\r
806 \r
807 //===========================================================================\r
808 \r
809 /*\r
810 =================\r
811 =\r
812 = RFL_CalcOriginStuff\r
813 =\r
814 = Calculate all the global variables for a new position\r
815 = Long parms so position can be clipped to a maximum near 64k\r
816 =\r
817 =================\r
818 */\r
819 \r
820 void RFL_CalcOriginStuff (long x, long y)\r
821 {\r
822         if (x<originxmin)\r
823           x=originxmin;\r
824         else if (x>originxmax)\r
825           x=originxmax;\r
826 \r
827         if (y<originymin)\r
828           y=originymin;\r
829         else if (y>originymax)\r
830           y=originymax;\r
831 \r
832         originxglobal = x;\r
833         originyglobal = y;\r
834         originxtile = originxglobal>>G_T_SHIFT;\r
835         originytile = originyglobal>>G_T_SHIFT;\r
836         originxscreen = originxtile<<SX_T_SHIFT;\r
837         originyscreen = originytile<<SY_T_SHIFT;\r
838         originmap = mapbwidthtable[originytile] + originxtile*2;\r
839 \r
840 #if GRMODE == EGAGR\r
841         panx = (originxglobal>>G_P_SHIFT) & 15;\r
842         pansx = panx & 8;\r
843         pany = pansy = (originyglobal>>G_P_SHIFT) & 15;\r
844         panadjust = panx/8 + ylookup[pany];\r
845 #endif\r
846 \r
847 #if GRMODE == CGAGR\r
848         panx = (originxglobal>>G_P_SHIFT) & 15;\r
849         pansx = panx & 12;\r
850         pany = pansy = (originyglobal>>G_P_SHIFT) & 15;\r
851         panadjust = pansx/4 + ylookup[pansy];\r
852 #endif\r
853 \r
854 }\r
855 \r
856 //===========================================================================\r
857 \r
858 /*\r
859 =====================\r
860 =\r
861 = RF_SetRefreshHook\r
862 =\r
863 =====================\r
864 */\r
865 \r
866 void RF_SetRefreshHook (void (*func) (void) )\r
867 {\r
868         refreshvector = func;\r
869 }\r
870 \r
871 \r
872 \r
873 /*\r
874 =================\r
875 =\r
876 = RFL_NewRow\r
877 =\r
878 = Bring a new row of tiles onto the port, spawning animating tiles\r
879 =\r
880 =================\r
881 */\r
882 \r
883 void    RFL_NewRow (int dir)\r
884 {\r
885         unsigned count,updatespot,updatestep;\r
886         int             x,y,xstep,ystep;\r
887 \r
888         switch (dir)\r
889         {\r
890         case 0:         // top row\r
891                 updatespot = 0;\r
892                 updatestep = 1;\r
893                 x = originxtile;\r
894                 y = originytile;\r
895                 xstep = 1;\r
896                 ystep = 0;\r
897                 count = PORTTILESWIDE;\r
898                 break;\r
899 \r
900         case 1:         // right row\r
901                 updatespot = PORTTILESWIDE-1;\r
902                 updatestep = UPDATEWIDE;\r
903                 x = originxtile + PORTTILESWIDE-1;\r
904                 y = originytile;\r
905                 xstep = 0;\r
906                 ystep = 1;\r
907                 count = PORTTILESHIGH;\r
908                 break;\r
909 \r
910         case 2:         // bottom row\r
911                 updatespot = UPDATEWIDE*(PORTTILESHIGH-1);\r
912                 updatestep = 1;\r
913                 x = originxtile;\r
914                 y = originytile + PORTTILESHIGH-1;\r
915                 xstep = 1;\r
916                 ystep = 0;\r
917                 count = PORTTILESWIDE;\r
918                 break;\r
919 \r
920         case 3:         // left row\r
921                 updatespot = 0;\r
922                 updatestep = UPDATEWIDE;\r
923                 x = originxtile;\r
924                 y = originytile;\r
925                 xstep = 0;\r
926                 ystep = 1;\r
927                 count = PORTTILESHIGH;\r
928                 break;\r
929         //default:\r
930                 //Quit ("RFL_NewRow: Bad dir!");\r
931         }\r
932 \r
933         while (count--)\r
934         {\r
935                 RFL_NewTile(updatespot);\r
936                 RFL_CheckForAnimTile (x,y);\r
937                 updatespot+=updatestep;\r
938                 x+=xstep;\r
939                 y+=ystep;\r
940         }\r
941 }\r
942 \r
943 //===========================================================================\r
944 \r
945 /*\r
946 =====================\r
947 =\r
948 = RF_ForceRefresh\r
949 =\r
950 =====================\r
951 */\r
952 \r
953 void RF_ForceRefresh (void)\r
954 {\r
955         RF_NewPosition (originxglobal,originyglobal);\r
956         RF_Refresh ();\r
957         RF_Refresh ();\r
958 }\r
959 \r
960 \r
961 \r
962 /*\r
963 =============================================================================\r
964 \r
965                                         EGA specific routines\r
966 \r
967 =============================================================================\r
968 */\r
969 \r
970 #if GRMODE == EGAGR\r
971 \r
972 \r
973 /*\r
974 =====================\r
975 =\r
976 = RF_NewPosition EGA\r
977 =\r
978 =====================\r
979 */\r
980 \r
981 void RF_NewPosition (unsigned x, unsigned y)\r
982 {\r
983         int mx,my;\r
984         byte    *page0ptr,*page1ptr;\r
985         unsigned        updatenum;\r
986 \r
987 //\r
988 // calculate new origin related globals\r
989 //\r
990         RFL_CalcOriginStuff (x,y);\r
991 \r
992 //\r
993 // clear out all animating tiles\r
994 //\r
995         RFL_InitAnimList ();\r
996 \r
997 //\r
998 // set up the new update arrays at base position\r
999 //\r
1000         memset (tilecache,0,sizeof(tilecache));         // old cache is invalid\r
1001 \r
1002         updatestart[0] = baseupdatestart[0];\r
1003         updatestart[1] = baseupdatestart[1];\r
1004 \r
1005         page0ptr = updatestart[0]+PORTTILESWIDE;        // used to stick "0"s after rows\r
1006         page1ptr = updatestart[1]+PORTTILESWIDE;\r
1007 \r
1008         updatenum = 0;                          // start at first visable tile\r
1009 \r
1010         for (my=0;my<PORTTILESHIGH;my++)\r
1011         {\r
1012                 for (mx=0;mx<PORTTILESWIDE;mx++)\r
1013                 {\r
1014                         RFL_NewTile(updatenum);                 // puts "1"s in both pages\r
1015                         RFL_CheckForAnimTile(mx+originxtile,my+originytile);\r
1016                         updatenum++;\r
1017                 }\r
1018                 updatenum++;\r
1019                 *page0ptr = *page1ptr = 0; // set a 0 at end of a line of tiles\r
1020                 page0ptr+=(PORTTILESWIDE+1);\r
1021                 page1ptr+=(PORTTILESWIDE+1);\r
1022         }\r
1023         *(word *)(page0ptr-PORTTILESWIDE)\r
1024                 = *(word *)(page1ptr-PORTTILESWIDE) = UPDATETERMINATE;\r
1025 }\r
1026 \r
1027 //===========================================================================\r
1028 \r
1029 /*\r
1030 =================\r
1031 =\r
1032 = RFL_OldRow EGA\r
1033 =\r
1034 = Uncache the trailing row of tiles\r
1035 =\r
1036 =================\r
1037 */\r
1038 \r
1039 void    RFL_OldRow (unsigned updatespot,unsigned count,unsigned step)\r
1040 {\r
1041 \r
1042 asm     mov     si,[updatespot]                 // pointer inside each map plane\r
1043 asm     mov     cx,[count]                              // number of tiles to clear\r
1044 asm     mov     dx,[step]                               // move to next tile\r
1045 asm     mov     es,[WORD PTR mapsegs]                   // background plane\r
1046 asm     mov     ds,[WORD PTR mapsegs+2]                 // foreground plane\r
1047 \r
1048 clearcache:\r
1049 asm     mov     bx,[si]\r
1050 asm     or      bx,bx\r
1051 asm     jnz     blockok                                 // if a foreground tile, block wasn't cached\r
1052 asm     mov     bx,[es:si]\r
1053 asm     shl     bx,1\r
1054 asm     mov     [WORD PTR ss:tilecache+bx],0  //tile is no longer in master screen cache\r
1055 blockok:\r
1056 asm     add     si,dx\r
1057 asm     loop    clearcache\r
1058 \r
1059 asm     mov     ax,ss\r
1060 asm     mov     ds,ax\r
1061 \r
1062 }\r
1063 \r
1064 \r
1065 /*\r
1066 =====================\r
1067 =\r
1068 = RF_Scroll  EGA\r
1069 =\r
1070 = Move the origin x/y global coordinates, readjust the screen panning, and\r
1071 = scroll if needed.  If the scroll distance is greater than one tile, the\r
1072 = entire screen will be redrawn (this could be generalized, but scrolling\r
1073 = more than one tile per refresh is a bad idea!).\r
1074 =\r
1075 =====================\r
1076 */\r
1077 \r
1078 void RF_Scroll (int x, int y)\r
1079 {\r
1080         long            neworgx,neworgy;\r
1081         int                     i,deltax,deltay,absdx,absdy;\r
1082         int                     oldxt,oldyt,move,yy;\r
1083         unsigned        updatespot;\r
1084         byte            *update0,*update1;\r
1085         unsigned        oldpanx,oldpanadjust,oldoriginmap,oldscreen,newscreen,screencopy;\r
1086         int                     screenmove;\r
1087 \r
1088         oldxt = originxtile;\r
1089         oldyt = originytile;\r
1090         oldoriginmap = originmap;\r
1091         oldpanadjust = panadjust;\r
1092         oldpanx = panx;\r
1093 \r
1094         RFL_CalcOriginStuff ((long)originxglobal + x,(long)originyglobal + y);\r
1095 \r
1096         deltax = originxtile - oldxt;\r
1097         absdx = abs(deltax);\r
1098         deltay = originytile - oldyt;\r
1099         absdy = abs(deltay);\r
1100 \r
1101         if (absdx>1 || absdy>1)\r
1102         {\r
1103         //\r
1104         // scrolled more than one tile, so start from scratch\r
1105         //\r
1106                 RF_NewPosition(originxglobal,originyglobal);\r
1107                 return;\r
1108         }\r
1109 \r
1110         if (!absdx && !absdy)\r
1111                 return;                                 // the screen has not scrolled an entire tile\r
1112 \r
1113 \r
1114 //\r
1115 // adjust screens and handle SVGA crippled compatability mode\r
1116 //\r
1117         screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;\r
1118         for (i=0;i<3;i++)\r
1119         {\r
1120                 screenstart[i]+= screenmove;\r
1121                 if (compatability && screenstart[i] > (0x10000l-SCREENSPACE) )\r
1122                 {\r
1123                         //\r
1124                         // move the screen to the opposite end of the buffer\r
1125                         //\r
1126                         screencopy = screenmove>0 ? FREEEGAMEM : -FREEEGAMEM;\r
1127                         oldscreen = screenstart[i] - screenmove;\r
1128                         newscreen = oldscreen + screencopy;\r
1129                         screenstart[i] = newscreen + screenmove;\r
1130                         VW_ScreenToScreen (oldscreen,newscreen,\r
1131                                 PORTTILESWIDE*2,PORTTILESHIGH*16);\r
1132 \r
1133                         if (i==screenpage)\r
1134                                 VW_SetScreen(newscreen+oldpanadjust,oldpanx & xpanmask);\r
1135                 }\r
1136         }\r
1137         bufferofs = screenstart[otherpage];\r
1138         displayofs = screenstart[screenpage];\r
1139         masterofs = screenstart[2];\r
1140 \r
1141 \r
1142 //\r
1143 // float the update regions\r
1144 //\r
1145         move = deltax;\r
1146         if (deltay==1)\r
1147           move += UPDATEWIDE;\r
1148         else if (deltay==-1)\r
1149           move -= UPDATEWIDE;\r
1150 \r
1151         updatestart[0]+=move;\r
1152         updatestart[1]+=move;\r
1153 \r
1154 //\r
1155 // draw the new tiles just scrolled on to the master screen, and\r
1156 // mark them as needing to be copied to each screen next refreshes\r
1157 // Make sure a zero is at the end of each row in update\r
1158 //\r
1159 \r
1160         if (deltax)\r
1161         {\r
1162                 if (deltax==1)\r
1163                 {\r
1164                         RFL_NewRow (1);                 // new right row\r
1165                         RFL_OldRow (oldoriginmap,PORTTILESHIGH,mapbyteswide);\r
1166                         RFL_RemoveAnimsOnX (originxtile-1);\r
1167                 }\r
1168                 else\r
1169                 {\r
1170                         RFL_NewRow (3);                 // new left row\r
1171                         RFL_OldRow (oldoriginmap+(PORTTILESWIDE-1)*2,PORTTILESHIGH\r
1172                         ,mapbyteswide);\r
1173                         RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);\r
1174                 }\r
1175 \r
1176                 update0 = updatestart[0]+PORTTILESWIDE;\r
1177                 update1 = updatestart[1]+PORTTILESWIDE;\r
1178                 for     (yy=0;yy<PORTTILESHIGH;yy++)\r
1179                 {\r
1180                         *update0 = *update1 = 0;        // drop a 0 at end of each row\r
1181                         update0+=UPDATEWIDE;\r
1182                         update1+=UPDATEWIDE;\r
1183                 }\r
1184         }\r
1185 \r
1186 //----------------\r
1187 \r
1188         if (deltay)\r
1189         {\r
1190                 if (deltay==1)\r
1191                 {\r
1192                         RFL_NewRow (2);                 // new bottom row\r
1193                         RFL_OldRow (oldoriginmap,PORTTILESWIDE,2);\r
1194                         updatespot = UPDATEWIDE*(PORTTILESHIGH-1);\r
1195                         RFL_RemoveAnimsOnY (originytile-1);\r
1196                 }\r
1197                 else\r
1198                 {\r
1199                         RFL_NewRow (0);                 // new top row\r
1200                         RFL_OldRow (oldoriginmap+mapbwidthtable[PORTTILESHIGH-1]\r
1201                         ,PORTTILESWIDE,2);\r
1202                         updatespot = 0;\r
1203                         RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);\r
1204                 }\r
1205 \r
1206                 *(updatestart[0]+updatespot+PORTTILESWIDE) =\r
1207                         *(updatestart[1]+updatespot+PORTTILESWIDE) = 0;\r
1208         }\r
1209 \r
1210 //----------------\r
1211 \r
1212         //\r
1213         // place a new terminator\r
1214         //\r
1215         update0 = updatestart[0]+UPDATEWIDE*PORTTILESHIGH-1;\r
1216         update1 = updatestart[1]+UPDATEWIDE*PORTTILESHIGH-1;\r
1217         *update0++ = *update1++ = 0;\r
1218         *(unsigned *)update0 = *(unsigned *)update1 = UPDATETERMINATE;\r
1219 }\r
1220 \r
1221 //===========================================================================\r
1222 \r
1223 /*\r
1224 =====================\r
1225 =\r
1226 = RF_PlaceSprite   EGA\r
1227 =\r
1228 =====================\r
1229 */\r
1230 \r
1231 void RF_PlaceSprite (void **user,unsigned globalx,unsigned globaly,\r
1232         unsigned spritenumber, drawtype draw, int priority)\r
1233 {\r
1234         spritelisttype  register *sprite,*next;\r
1235         spritetabletype far *spr;\r
1236         spritetype /*_seg*/     *block;\r
1237         unsigned        shift,pixx;\r
1238 \r
1239         if (!spritenumber)\r
1240         {\r
1241                 RF_RemoveSprite (user);\r
1242                 return;\r
1243         }\r
1244 \r
1245         sprite = (spritelisttype *)*user;\r
1246 \r
1247         if      (sprite)\r
1248         {\r
1249         // sprite allready exists in the list, so we can use it's block\r
1250 \r
1251         //\r
1252         // post an erase block to both pages by copying screenx,screeny,width,height\r
1253         // both pages may not need to be erased if the sprite just changed last frame\r
1254         //\r
1255                 if (sprite->updatecount<2)\r
1256                 {\r
1257                         if (!sprite->updatecount)\r
1258                                 memcpy (eraselistptr[otherpage]++,sprite,sizeof(eraseblocktype));\r
1259                         memcpy (eraselistptr[screenpage]++,sprite,sizeof(eraseblocktype));\r
1260                 }\r
1261 \r
1262                 if (priority != sprite->priority)\r
1263                 {\r
1264                 // sprite mvoed to another priority, so unlink the old one and\r
1265                 // relink it in the new priority\r
1266 \r
1267                         next = sprite->nextsprite;                      // cut old links\r
1268                         if (next)\r
1269                                 next->prevptr = sprite->prevptr;\r
1270                         *sprite->prevptr = next;\r
1271                         goto linknewspot;\r
1272                 }\r
1273         }\r
1274         else\r
1275         {\r
1276         // this is a brand new sprite, so allocate a block from the array\r
1277 \r
1278                 if (!spritefreeptr)\r
1279                         //Quit ("RF_PlaceSprite: No free spots in spritearray!");\r
1280 \r
1281                 sprite = spritefreeptr;\r
1282                 spritefreeptr = spritefreeptr->nextsprite;\r
1283 \r
1284 linknewspot:\r
1285                 next = prioritystart[priority];         // stick it in new spot\r
1286                 if (next)\r
1287                         next->prevptr = &sprite->nextsprite;\r
1288                 sprite->nextsprite = next;\r
1289                 prioritystart[priority] = sprite;\r
1290                 sprite->prevptr = &prioritystart[priority];\r
1291         }\r
1292 \r
1293 //\r
1294 // write the new info to the sprite\r
1295 //\r
1296         spr = &spritetable[spritenumber-STARTSPRITES];\r
1297         block = (spritetype /*_seg*/ *)grsegs[spritenumber];\r
1298 \r
1299         globaly+=spr->orgy;\r
1300         globalx+=spr->orgx;\r
1301 \r
1302         pixx = globalx >> G_SY_SHIFT;\r
1303         shift = (pixx&7)/2;\r
1304 \r
1305         sprite->screenx = pixx >> (G_EGASX_SHIFT-G_SY_SHIFT);\r
1306         sprite->screeny = globaly >> G_SY_SHIFT;\r
1307         sprite->width = block->width[shift];\r
1308         sprite->height = spr->height;\r
1309         sprite->grseg = spritenumber;\r
1310         sprite->sourceofs = block->sourceoffset[shift];\r
1311         sprite->planesize = block->planesize[shift];\r
1312         sprite->draw = draw;\r
1313         sprite->priority = priority;\r
1314         sprite->tilex = sprite->screenx >> SX_T_SHIFT;\r
1315         sprite->tiley = sprite->screeny >> SY_T_SHIFT;\r
1316         sprite->tilewide = ( (sprite->screenx + sprite->width -1) >> SX_T_SHIFT )\r
1317                 - sprite->tilex + 1;\r
1318         sprite->tilehigh = ( (sprite->screeny + sprite->height -1) >> SY_T_SHIFT )\r
1319                 - sprite->tiley + 1;\r
1320 \r
1321         sprite->updatecount = 2;                // draw on next two refreshes\r
1322 \r
1323 // save the sprite pointer off in the user's pointer so it can be moved\r
1324 // again later\r
1325 \r
1326         *user = sprite;\r
1327 }\r
1328 \r
1329 //===========================================================================\r
1330 \r
1331 /*\r
1332 =====================\r
1333 =\r
1334 = RF_RemoveSprite  EGA\r
1335 =\r
1336 =====================\r
1337 */\r
1338 \r
1339 void RF_RemoveSprite (void **user)\r
1340 {\r
1341         spritelisttype  *sprite,*next;\r
1342 \r
1343         sprite = (spritelisttype *)*user;\r
1344         if (!sprite)\r
1345                 return;\r
1346 \r
1347 //\r
1348 // post an erase block to both pages by copying screenx,screeny,width,height\r
1349 // both pages may not need to be erased if the sprite just changed last frame\r
1350 //\r
1351         if (sprite->updatecount<2)\r
1352         {\r
1353                 if (!sprite->updatecount)\r
1354                         memcpy (eraselistptr[otherpage]++,sprite,sizeof(eraseblocktype));\r
1355                 memcpy (eraselistptr[screenpage]++,sprite,sizeof(eraseblocktype));\r
1356         }\r
1357 \r
1358 //\r
1359 // unlink the sprite node\r
1360 //\r
1361         next = sprite->nextsprite;\r
1362         if (next)                                               // if (!next), sprite is last in chain\r
1363                 next->prevptr = sprite->prevptr;\r
1364         *sprite->prevptr = next;\r
1365 \r
1366 //\r
1367 // add it back to the free list\r
1368 //\r
1369         sprite->nextsprite = spritefreeptr;\r
1370         spritefreeptr = sprite;\r
1371 \r
1372 //\r
1373 // null the users pointer, so next time that actor gets placed, it will\r
1374 // allocate a new block\r
1375 //\r
1376 \r
1377         *user = 0;\r
1378 }\r
1379 \r
1380 \r
1381 //===========================================================================\r
1382 \r
1383 \r
1384 /*\r
1385 ====================\r
1386 =\r
1387 = RFL_EraseBlocks  EGA\r
1388 =\r
1389 = Write mode 1 should be set\r
1390 =\r
1391 ====================\r
1392 */\r
1393 \r
1394 void RFL_EraseBlocks (void)\r
1395 {\r
1396         eraseblocktype  *block,*done;\r
1397         int                     screenxh,screenyh;\r
1398         unsigned        pos,xtl,ytl,xth,yth,x,y;\r
1399         byte            *updatespot;\r
1400         unsigned        updatedelta;\r
1401         unsigned        erasecount;\r
1402 \r
1403 #ifdef PROFILE\r
1404         erasecount = 0;\r
1405 #endif\r
1406 \r
1407         block = otherpage ? &eraselist[1][0] : &eraselist[0][0];\r
1408 \r
1409         done = eraselistptr[otherpage];\r
1410 \r
1411         while (block != done)\r
1412         {\r
1413 \r
1414         //\r
1415         // clip the block to the current screen view\r
1416         //\r
1417                 block->screenx -= originxscreen;\r
1418                 block->screeny -= originyscreen;\r
1419 \r
1420                 if (block->screenx < 0)\r
1421                 {\r
1422                         block->width += block->screenx;\r
1423                         if (block->width<1)\r
1424                                 goto next;\r
1425                         block->screenx = 0;\r
1426                 }\r
1427 \r
1428                 if (block->screeny < 0)\r
1429                 {\r
1430                         block->height += block->screeny;\r
1431                         if (block->height<1)\r
1432                                 goto next;\r
1433                         block->screeny = 0;\r
1434                 }\r
1435 \r
1436                 screenxh = block->screenx + block->width;\r
1437                 screenyh = block->screeny + block->height;\r
1438 \r
1439                 if (screenxh > EGAPORTSCREENWIDE)\r
1440                 {\r
1441                         block->width = EGAPORTSCREENWIDE-block->screenx;\r
1442                         screenxh = block->screenx + block->width;\r
1443                 }\r
1444 \r
1445                 if (screenyh > PORTSCREENHIGH)\r
1446                 {\r
1447                         block->height = PORTSCREENHIGH-block->screeny;\r
1448                         screenyh = block->screeny + block->height;\r
1449                 }\r
1450 \r
1451                 if (block->width<1 || block->height<1)\r
1452                         goto next;\r
1453 \r
1454         //\r
1455         // erase the block by copying from the master screen\r
1456         //\r
1457                 pos = ylookup[block->screeny]+block->screenx;\r
1458                 VW_ScreenToScreen (masterofs+pos,bufferofs+pos,\r
1459                         block->width,block->height);\r
1460 \r
1461         //\r
1462         // put 2s in update where the block was, to force sprites to update\r
1463         //\r
1464                 xtl = block->screenx >> SX_T_SHIFT;\r
1465                 xth = (block->screenx+block->width-1) >> SX_T_SHIFT;\r
1466                 ytl = block->screeny >> SY_T_SHIFT;\r
1467                 yth = (block->screeny+block->height-1) >> SY_T_SHIFT;\r
1468 \r
1469                 updatespot = updateptr + uwidthtable[ytl] + xtl;\r
1470                 updatedelta = UPDATEWIDE - (xth-xtl+1);\r
1471 \r
1472                 for (y=ytl;y<=yth;y++)\r
1473                 {\r
1474                         for (x=xtl;x<=xth;x++)\r
1475                                 *updatespot++ = 2;\r
1476                         updatespot += updatedelta;              // down to next line\r
1477                 }\r
1478 #ifdef PROFILE\r
1479                 erasecount++;\r
1480 #endif\r
1481 \r
1482 next:\r
1483                 block++;\r
1484         }\r
1485         eraselistptr[otherpage] = otherpage ? &eraselist[1][0] : &eraselist[0][0];\r
1486 #ifdef PROFILE\r
1487         strcpy (scratch,"\tErase:");\r
1488         itoa (erasecount,str,10);\r
1489         strcat (scratch,str);\r
1490         write (profilehandle,scratch,strlen(scratch));\r
1491 #endif\r
1492 \r
1493 }\r
1494 \r
1495 \r
1496 /*\r
1497 ====================\r
1498 =\r
1499 = RFL_UpdateSprites EGA\r
1500 =\r
1501 = NOTE: Implement vertical clipping!\r
1502 =\r
1503 ====================\r
1504 */\r
1505 \r
1506 void RFL_UpdateSprites (void)\r
1507 {\r
1508         spritelisttype  *sprite;\r
1509         int     portx,porty,x,y,xtl,xth,ytl,yth;\r
1510         int     priority;\r
1511         unsigned dest;\r
1512         byte            *updatespot,*baseupdatespot;\r
1513         unsigned        updatedelta;\r
1514         unsigned        updatecount;\r
1515         unsigned        height,sourceofs;\r
1516 \r
1517 #ifdef PROFILE\r
1518         updatecount = 0;\r
1519 #endif\r
1520 \r
1521         for (priority=0;priority<PRIORITIES;priority++)\r
1522         {\r
1523                 if (priority==MASKEDTILEPRIORITY)\r
1524                         RFL_MaskForegroundTiles ();\r
1525 \r
1526                 for (sprite = prioritystart[priority]; sprite ;\r
1527                         sprite = (spritelisttype *)sprite->nextsprite)\r
1528                 {\r
1529                 //\r
1530                 // see if the sprite has any visable area in the port\r
1531                 //\r
1532 \r
1533                         portx = sprite->screenx - originxscreen;\r
1534                         porty = sprite->screeny - originyscreen;\r
1535                         xtl = portx >> SX_T_SHIFT;\r
1536                         xth = (portx + sprite->width-1) >> SX_T_SHIFT;\r
1537                         ytl = porty >> SY_T_SHIFT;\r
1538                         yth = (porty + sprite->height-1) >> SY_T_SHIFT;\r
1539 \r
1540                         if (xtl<0)\r
1541                           xtl = 0;\r
1542                         if (xth>=PORTTILESWIDE)\r
1543                           xth = PORTTILESWIDE-1;\r
1544                         if (ytl<0)\r
1545                           ytl = 0;\r
1546                         if (yth>=PORTTILESHIGH)\r
1547                           yth = PORTTILESHIGH-1;\r
1548 \r
1549                         if (xtl>xth || ytl>yth)\r
1550                                 continue;\r
1551 \r
1552                 //\r
1553                 // see if it's visable area covers any non 0 update tiles\r
1554                 //\r
1555                         updatespot = baseupdatespot = updateptr + uwidthtable[ytl] + xtl;\r
1556                         updatedelta = UPDATEWIDE - (xth-xtl+1);\r
1557 \r
1558                         if (sprite->updatecount)\r
1559                         {\r
1560                                 sprite->updatecount--;                  // the sprite was just placed,\r
1561                                 goto redraw;                                    // so draw it for sure\r
1562                         }\r
1563 \r
1564                         for (y=ytl;y<=yth;y++)\r
1565                         {\r
1566                                 for (x=xtl;x<=xth;x++)\r
1567                                         if (*updatespot++)\r
1568                                                 goto redraw;\r
1569                                 updatespot += updatedelta;              // down to next line\r
1570                         }\r
1571                         continue;                                                       // no need to update\r
1572 \r
1573 redraw:\r
1574                 //\r
1575                 // set the tiles it covers to 3, because those tiles are being\r
1576                 // updated\r
1577                 //\r
1578                         updatespot = baseupdatespot;\r
1579                         for (y=ytl;y<=yth;y++)\r
1580                         {\r
1581                                 for (x=xtl;x<=xth;x++)\r
1582                                         *updatespot++ = 3;\r
1583                                 updatespot += updatedelta;              // down to next line\r
1584                         }\r
1585                 //\r
1586                 // draw it!\r
1587                 //\r
1588                         height = sprite->height;\r
1589                         sourceofs = sprite->sourceofs;\r
1590                         if (porty<0)\r
1591                         {\r
1592                                 height += porty;                                        // clip top off\r
1593                                 sourceofs -= porty*sprite->width;\r
1594                                 porty = 0;\r
1595                         }\r
1596                         else if (porty+height>PORTSCREENHIGH)\r
1597                         {\r
1598                                 height = PORTSCREENHIGH - porty;    // clip bottom off\r
1599                         }\r
1600 \r
1601                         dest = bufferofs + ylookup[porty] + portx;\r
1602 \r
1603                         switch (sprite->draw)\r
1604                         {\r
1605                         case spritedraw:\r
1606                                 VW_MaskBlock(grsegs[sprite->grseg], sourceofs,\r
1607                                         dest,sprite->width,height,sprite->planesize);\r
1608                                 break;\r
1609 \r
1610                         case maskdraw:\r
1611                                 break;\r
1612 \r
1613                         }\r
1614 #ifdef PROFILE\r
1615                         updatecount++;\r
1616 #endif\r
1617 \r
1618 \r
1619                 }\r
1620         }\r
1621 #ifdef PROFILE\r
1622         strcpy (scratch,"\tSprites:");\r
1623         itoa (updatecount,str,10);\r
1624         strcat (scratch,str);\r
1625         write (profilehandle,scratch,strlen(scratch));\r
1626 #endif\r
1627 \r
1628 }\r
1629 \r
1630 \r
1631 /*\r
1632 =====================\r
1633 =\r
1634 = RF_Refresh   EGA\r
1635 =\r
1636 = All routines will draw at the port at bufferofs, possibly copying from\r
1637 = the port at masterofs.  The EGA version then page flips, while the\r
1638 = CGA version updates the screen from the buffer port.\r
1639 =\r
1640 = Screenpage is the currently displayed page, not the one being drawn\r
1641 = Otherpage is the page to be worked with now\r
1642 =\r
1643 =====================\r
1644 */\r
1645 \r
1646 void RF_Refresh (void)\r
1647 {\r
1648         byte    *newupdate;\r
1649         long    newtime;\r
1650 \r
1651         updateptr = updatestart[otherpage];\r
1652 \r
1653         RFL_AnimateTiles ();            // DEBUG\r
1654 \r
1655 //\r
1656 // update newly scrolled on tiles and animated tiles from the master screen\r
1657 //\r
1658         EGAWRITEMODE(1);\r
1659         EGAMAPMASK(15);\r
1660         RFL_UpdateTiles ();\r
1661         RFL_EraseBlocks ();\r
1662 \r
1663 //\r
1664 // Update is all 0 except where sprites have changed or new area has\r
1665 // been scrolled on.  Go through all sprites and update the ones that cover\r
1666 // a non 0 update tile\r
1667 //\r
1668         EGAWRITEMODE(0);\r
1669         RFL_UpdateSprites ();\r
1670 \r
1671 //\r
1672 // if the main program has a refresh hook set, call their function before\r
1673 // displaying the new page\r
1674 //\r
1675         if (refreshvector)\r
1676                 refreshvector();\r
1677 \r
1678 //\r
1679 // display the changed screen\r
1680 //\r
1681         VW_SetScreen(bufferofs+panadjust,panx & xpanmask);\r
1682 \r
1683 //\r
1684 // prepare for next refresh\r
1685 //\r
1686 // Set the update array to the middle position and clear it out to all "0"s\r
1687 // with an UPDATETERMINATE at the end\r
1688 //\r
1689         updatestart[otherpage] = newupdate = baseupdatestart[otherpage];\r
1690 asm     mov     ax,ds\r
1691 asm     mov     es,ax\r
1692 asm     xor     ax,ax\r
1693 asm     mov     cx,(UPDATESCREENSIZE-2)/2\r
1694 asm     mov     di,[newupdate]\r
1695 asm     rep     stosw\r
1696 asm     mov     [WORD PTR es:di],UPDATETERMINATE\r
1697 \r
1698         screenpage ^= 1;\r
1699         otherpage ^= 1;\r
1700         bufferofs = screenstart[otherpage];\r
1701         displayofs = screenstart[screenpage];\r
1702 \r
1703 //\r
1704 // calculate tics since last refresh for adaptive timing\r
1705 //\r
1706         if (lasttimecount > TimeCount)\r
1707                 lasttimecount = TimeCount;              // if the game was paused a LONG time\r
1708         do\r
1709         {\r
1710                 newtime = TimeCount;\r
1711                 tics = newtime-lasttimecount;\r
1712         } while (tics<MINTICS);\r
1713         lasttimecount = newtime;\r
1714 \r
1715 #ifdef PROFILE\r
1716         strcpy (scratch,"\tTics:");\r
1717         itoa (tics,str,10);\r
1718         strcat (scratch,str);\r
1719         strcat (scratch,"\n");\r
1720         write (profilehandle,scratch,strlen(scratch));\r
1721 #endif\r
1722 \r
1723         if (tics>MAXTICS)\r
1724         {\r
1725                 TimeCount -= (tics-MAXTICS);\r
1726                 tics = MAXTICS;\r
1727         }\r
1728 }\r
1729 \r
1730 #endif          // GRMODE == EGAGR\r
1731 \r
1732 /*\r
1733 =============================================================================\r
1734 \r
1735                                         CGA specific routines\r
1736 \r
1737 =============================================================================\r
1738 */\r
1739 \r
1740 #if GRMODE == CGAGR\r
1741 \r
1742 \r
1743 /*\r
1744 =====================\r
1745 =\r
1746 = RF_NewPosition   CGA\r
1747 =\r
1748 =====================\r
1749 */\r
1750 \r
1751 void RF_NewPosition (unsigned x, unsigned y)\r
1752 {\r
1753         int mx,my;\r
1754         byte    *spotptr;\r
1755         unsigned        updatenum;\r
1756 \r
1757 //\r
1758 // calculate new origin related globals\r
1759 //\r
1760         RFL_CalcOriginStuff (x,y);\r
1761 \r
1762 //\r
1763 // clear out all animating tiles\r
1764 //\r
1765         RFL_InitAnimList ();\r
1766 \r
1767 //\r
1768 // set up the new update arrays at base position\r
1769 //\r
1770         updateptr = baseupdateptr;\r
1771 \r
1772         spotptr = updateptr + PORTTILESWIDE;    // used to stick "0"s after rows\r
1773 \r
1774         updatenum = 0;                          // start at first visable tile\r
1775 \r
1776         for (my=0;my<PORTTILESHIGH;my++)\r
1777         {\r
1778                 for (mx=0;mx<PORTTILESWIDE;mx++)\r
1779                 {\r
1780                         RFL_NewTile(updatenum);                 // puts "1"s in both pages\r
1781                         RFL_CheckForAnimTile(mx+originxtile,my+originytile);\r
1782                         updatenum++;\r
1783                 }\r
1784                 updatenum++;\r
1785                 *spotptr = 0; // set a 0 at end of a line of tiles\r
1786                 spotptr +=(PORTTILESWIDE+1);\r
1787         }\r
1788         *(word *)(spotptr-PORTTILESWIDE) = UPDATETERMINATE;\r
1789 }\r
1790 \r
1791 \r
1792 /*\r
1793 =====================\r
1794 =\r
1795 = RF_Scroll       CGA\r
1796 =\r
1797 = Move the origin x/y global coordinates, readjust the screen panning, and\r
1798 = scroll if needed.  If the scroll distance is greater than one tile, the\r
1799 = entire screen will be redrawn (this could be generalized, but scrolling\r
1800 = more than one tile per refresh is a bad idea!).\r
1801 =\r
1802 =====================\r
1803 */\r
1804 \r
1805 void RF_Scroll (int x, int y)\r
1806 {\r
1807         long            neworgx,neworgy;\r
1808         int                     i,deltax,deltay,absdx,absdy;\r
1809         int                     oldxt,oldyt,move,yy;\r
1810         unsigned        updatespot;\r
1811         byte            *spotptr;\r
1812         unsigned        oldoriginmap,oldscreen,newscreen,screencopy;\r
1813         int                     screenmove;\r
1814 \r
1815         oldxt = originxtile;\r
1816         oldyt = originytile;\r
1817 \r
1818         RFL_CalcOriginStuff ((long)originxglobal + x,(long)originyglobal + y);\r
1819 \r
1820         deltax = originxtile - oldxt;\r
1821         absdx = abs(deltax);\r
1822         deltay = originytile - oldyt;\r
1823         absdy = abs(deltay);\r
1824 \r
1825         if (absdx>1 || absdy>1)\r
1826         {\r
1827         //\r
1828         // scrolled more than one tile, so start from scratch\r
1829         //\r
1830                 RF_NewPosition(originxglobal,originyglobal);\r
1831                 return;\r
1832         }\r
1833 \r
1834         if (!absdx && !absdy)\r
1835                 return;                                 // the screen has not scrolled an entire tile\r
1836 \r
1837 \r
1838 //\r
1839 // float screens\r
1840 //\r
1841         screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;\r
1842         bufferofs += screenmove;\r
1843         masterofs += screenmove;\r
1844 \r
1845 \r
1846 //\r
1847 // float the update regions\r
1848 //\r
1849         move = deltax;\r
1850         if (deltay==1)\r
1851           move += UPDATEWIDE;\r
1852         else if (deltay==-1)\r
1853           move -= UPDATEWIDE;\r
1854 \r
1855         updateptr+=move;\r
1856 \r
1857 //\r
1858 // draw the new tiles just scrolled on to the master screen, and\r
1859 // mark them as needing to be copied to each screen next refreshes\r
1860 // Make sure a zero is at the end of each row in update\r
1861 //\r
1862 \r
1863         if (deltax)\r
1864         {\r
1865                 if (deltax==1)\r
1866                 {\r
1867                         RFL_NewRow (1);                 // new right row\r
1868                         RFL_RemoveAnimsOnX (originxtile-1);\r
1869                 }\r
1870                 else\r
1871                 {\r
1872                         RFL_NewRow (3);                 // new left row\r
1873                         RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);\r
1874                 }\r
1875 \r
1876                 spotptr = updateptr+PORTTILESWIDE;\r
1877                 for     (yy=0;yy<PORTTILESHIGH;yy++)\r
1878                 {\r
1879                         *spotptr = 0;           // drop a 0 at end of each row\r
1880                         spotptr+=UPDATEWIDE;\r
1881                 }\r
1882         }\r
1883 \r
1884 //----------------\r
1885 \r
1886         if (deltay)\r
1887         {\r
1888                 if (deltay==1)\r
1889                 {\r
1890                         RFL_NewRow (2);                 // new bottom row\r
1891                         *(updateptr+UPDATEWIDE*(PORTTILESHIGH-1)+PORTTILESWIDE) = 0;\r
1892                         RFL_RemoveAnimsOnY (originytile-1);\r
1893                 }\r
1894                 else\r
1895                 {\r
1896                         RFL_NewRow (0);                 // new top row\r
1897                         *(updateptr+PORTTILESWIDE) = 0;\r
1898                         RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);\r
1899                 }\r
1900         }\r
1901 \r
1902 //----------------\r
1903 \r
1904         //\r
1905         // place a new terminator\r
1906         //\r
1907         spotptr = updateptr+UPDATEWIDE*PORTTILESHIGH-1;\r
1908         *spotptr++ = 0;\r
1909         *(unsigned *)spotptr = UPDATETERMINATE;\r
1910 }\r
1911 \r
1912 /*\r
1913 =====================\r
1914 =\r
1915 = RF_PlaceSprite  CGA\r
1916 =\r
1917 =====================\r
1918 */\r
1919 \r
1920 void RF_PlaceSprite (void **user,unsigned globalx,unsigned globaly,\r
1921         unsigned spritenumber, drawtype draw, int priority)\r
1922 {\r
1923         spritelisttype  register *sprite,*next;\r
1924         spritetabletype far *spr;\r
1925         spritetype /*_seg*/     *block;\r
1926         unsigned        shift,pixx;\r
1927 \r
1928         if (!spritenumber)\r
1929         {\r
1930                 RF_RemoveSprite (user);\r
1931                 return;\r
1932         }\r
1933 \r
1934         sprite = (spritelisttype *)*user;\r
1935 \r
1936         if      (sprite)\r
1937         {\r
1938         // sprite allready exists in the list, so we can use it's block\r
1939 \r
1940         //\r
1941         // post an erase block to erase the old position by copying\r
1942         // screenx,screeny,width,height\r
1943         //\r
1944                 if (!sprite->updatecount)               // may not have been drawn at all yet\r
1945                         memcpy (eraselistptr[0]++,sprite,sizeof(eraseblocktype));\r
1946 \r
1947                 if (priority != sprite->priority)\r
1948                 {\r
1949                 // sprite moved to another priority, so unlink the old one and\r
1950                 // relink it in the new priority\r
1951 \r
1952                         next = sprite->nextsprite;                      // cut old links\r
1953                         if (next)\r
1954                                 next->prevptr = sprite->prevptr;\r
1955                         *sprite->prevptr = next;\r
1956                         goto linknewspot;\r
1957                 }\r
1958         }\r
1959         else\r
1960         {\r
1961         // this is a brand new sprite, so allocate a block from the array\r
1962 \r
1963                 if (!spritefreeptr)\r
1964                         //Quit ("RF_PlaceSprite: No free spots in spritearray!");\r
1965 \r
1966                 sprite = spritefreeptr;\r
1967                 spritefreeptr = spritefreeptr->nextsprite;\r
1968 \r
1969 linknewspot:\r
1970                 next = prioritystart[priority];         // stick it in new spot\r
1971                 if (next)\r
1972                         next->prevptr = &sprite->nextsprite;\r
1973                 sprite->nextsprite = next;\r
1974                 prioritystart[priority] = sprite;\r
1975                 sprite->prevptr = &prioritystart[priority];\r
1976         }\r
1977 \r
1978 //\r
1979 // write the new info to the sprite\r
1980 //\r
1981         spr = &spritetable[spritenumber-STARTSPRITES];\r
1982         block = (spritetype /*_seg*/ *)grsegs[spritenumber];\r
1983 \r
1984         globaly+=spr->orgy;\r
1985         globalx+=spr->orgx;\r
1986 \r
1987         sprite->screenx = globalx >> G_CGASX_SHIFT;\r
1988         sprite->screeny = globaly >> G_SY_SHIFT;\r
1989         sprite->width = block->width[0];\r
1990         sprite->height = spr->height;\r
1991         sprite->grseg = spritenumber;\r
1992         sprite->sourceofs = block->sourceoffset[0];\r
1993         sprite->planesize = block->planesize[0];\r
1994         sprite->draw = draw;\r
1995         sprite->priority = priority;\r
1996         sprite->tilex = sprite->screenx >> SX_T_SHIFT;\r
1997         sprite->tiley = sprite->screeny >> SY_T_SHIFT;\r
1998         sprite->tilewide = ( (sprite->screenx + sprite->width -1) >> SX_T_SHIFT )\r
1999                 - sprite->tilex + 1;\r
2000         sprite->tilehigh = ( (sprite->screeny + sprite->height -1) >> SY_T_SHIFT )\r
2001                 - sprite->tiley + 1;\r
2002 \r
2003         sprite->updatecount = 1;                // draw on next refresh\r
2004 \r
2005 // save the sprite pointer off in the user's pointer so it can be moved\r
2006 // again later\r
2007 \r
2008         *user = sprite;\r
2009 }\r
2010 \r
2011 //===========================================================================\r
2012 \r
2013 /*\r
2014 =====================\r
2015 =\r
2016 = RF_RemoveSprite CGA\r
2017 =\r
2018 =====================\r
2019 */\r
2020 \r
2021 void RF_RemoveSprite (void **user)\r
2022 {\r
2023         spritelisttype  *sprite,*next;\r
2024 \r
2025         sprite = (spritelisttype *)*user;\r
2026         if (!sprite)\r
2027                 return;\r
2028 \r
2029 //\r
2030 // post an erase block to erase the old position by copying\r
2031 // screenx,screeny,width,height\r
2032 //\r
2033         if (!sprite->updatecount)\r
2034         {\r
2035                 memcpy (eraselistptr[0]++,sprite,sizeof(eraseblocktype));\r
2036         }\r
2037 \r
2038 //\r
2039 // unlink the sprite node\r
2040 //\r
2041         next = sprite->nextsprite;\r
2042         if (next)                                               // if (!next), sprite is last in chain\r
2043                 next->prevptr = sprite->prevptr;\r
2044         *sprite->prevptr = next;\r
2045 \r
2046 //\r
2047 // add it back to the free list\r
2048 //\r
2049         sprite->nextsprite = spritefreeptr;\r
2050         spritefreeptr = sprite;\r
2051 \r
2052 //\r
2053 // null the users pointer, so next time that actor gets placed, it will\r
2054 // allocate a new block\r
2055 //\r
2056 \r
2057         *user = 0;\r
2058 }\r
2059 \r
2060 \r
2061 /*\r
2062 ====================\r
2063 =\r
2064 = RFL_EraseBlocks CGA\r
2065 =\r
2066 = Write mode 1 should be set\r
2067 =\r
2068 ====================\r
2069 */\r
2070 \r
2071 void RFL_EraseBlocks (void)\r
2072 {\r
2073         eraseblocktype  *block,*done;\r
2074         int                     screenxh,screenyh;\r
2075         unsigned        pos,xtl,ytl,xth,yth,x,y;\r
2076         byte            *updatespot;\r
2077         unsigned        updatedelta;\r
2078 \r
2079         block = &eraselist[0][0];\r
2080 \r
2081         done = eraselistptr[0];\r
2082 \r
2083         while (block != done)\r
2084         {\r
2085 \r
2086         //\r
2087         // clip the block to the current screen view\r
2088         //\r
2089                 block->screenx -= originxscreen;\r
2090                 block->screeny -= originyscreen;\r
2091 \r
2092                 if (block->screenx < 0)\r
2093                 {\r
2094                         block->width += block->screenx;\r
2095                         if (block->width<1)\r
2096                                 goto next;\r
2097                         block->screenx = 0;\r
2098                 }\r
2099 \r
2100                 if (block->screeny < 0)\r
2101                 {\r
2102                         block->height += block->screeny;\r
2103                         if (block->height<1)\r
2104                                 goto next;\r
2105                         block->screeny = 0;\r
2106                 }\r
2107 \r
2108                 screenxh = block->screenx + block->width;\r
2109                 screenyh = block->screeny + block->height;\r
2110 \r
2111                 if (screenxh > CGAPORTSCREENWIDE)\r
2112                 {\r
2113                         block->width = CGAPORTSCREENWIDE-block->screenx;\r
2114                         screenxh = block->screenx + block->width;\r
2115                 }\r
2116 \r
2117                 if (screenyh > PORTSCREENHIGH)\r
2118                 {\r
2119                         block->height = PORTSCREENHIGH-block->screeny;\r
2120                         screenyh = block->screeny + block->height;\r
2121                 }\r
2122 \r
2123                 if (block->width<1 || block->height<1)\r
2124                         goto next;\r
2125 \r
2126         //\r
2127         // erase the block by copying from the master screen\r
2128         //\r
2129                 pos = ylookup[block->screeny]+block->screenx;\r
2130                 block->width = (block->width + (pos&1) + 1)& ~1;\r
2131                 pos &= ~1;                              // make sure a word copy gets used\r
2132                 VW_ScreenToScreen (masterofs+pos,bufferofs+pos,\r
2133                         block->width,block->height);\r
2134 \r
2135         //\r
2136         // put 2s in update where the block was, to force sprites to update\r
2137         //\r
2138                 xtl = block->screenx >> SX_T_SHIFT;\r
2139                 xth = (block->screenx+block->width-1) >> SX_T_SHIFT;\r
2140                 ytl = block->screeny >> SY_T_SHIFT;\r
2141                 yth = (block->screeny+block->height-1) >> SY_T_SHIFT;\r
2142 \r
2143                 updatespot = updateptr + uwidthtable[ytl] + xtl;\r
2144                 updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2145 \r
2146                 for (y=ytl;y<=yth;y++)\r
2147                 {\r
2148                         for (x=xtl;x<=xth;x++)\r
2149                                 *updatespot++ = 2;\r
2150                         updatespot += updatedelta;              // down to next line\r
2151                 }\r
2152 \r
2153 next:\r
2154                 block++;\r
2155         }\r
2156         eraselistptr[0] = &eraselist[0][0];\r
2157 }\r
2158 \r
2159 \r
2160 /*\r
2161 ====================\r
2162 =\r
2163 = RFL_UpdateSprites      CGA\r
2164 =\r
2165 = NOTE: Implement vertical clipping!\r
2166 =\r
2167 ====================\r
2168 */\r
2169 \r
2170 void RFL_UpdateSprites (void)\r
2171 {\r
2172         spritelisttype  *sprite;\r
2173         int     portx,porty,x,y,xtl,xth,ytl,yth;\r
2174         int     priority;\r
2175         unsigned dest;\r
2176         byte            *updatespot,*baseupdatespot;\r
2177         unsigned        updatedelta;\r
2178 \r
2179         unsigned        updatecount;\r
2180         unsigned        height,sourceofs;\r
2181 \r
2182 #ifdef PROFILE\r
2183         updatecount = 0;\r
2184 #endif\r
2185 \r
2186 \r
2187         for (priority=0;priority<PRIORITIES;priority++)\r
2188         {\r
2189                 if (priority==MASKEDTILEPRIORITY)\r
2190                         RFL_MaskForegroundTiles ();\r
2191 \r
2192                 for (sprite = prioritystart[priority]; sprite ;\r
2193                         sprite = (spritelisttype *)sprite->nextsprite)\r
2194                 {\r
2195                 //\r
2196                 // see if the sprite has any visable area in the port\r
2197                 //\r
2198 \r
2199                         portx = sprite->screenx - originxscreen;\r
2200                         porty = sprite->screeny - originyscreen;\r
2201                         xtl = portx >> SX_T_SHIFT;\r
2202                         xth = (portx + sprite->width-1) >> SX_T_SHIFT;\r
2203                         ytl = porty >> SY_T_SHIFT;\r
2204                         yth = (porty + sprite->height-1) >> SY_T_SHIFT;\r
2205 \r
2206                         if (xtl<0)\r
2207                           xtl = 0;\r
2208                         if (xth>=PORTTILESWIDE)\r
2209                           xth = PORTTILESWIDE-1;\r
2210                         if (ytl<0)\r
2211                           ytl = 0;\r
2212                         if (yth>=PORTTILESHIGH)\r
2213                           yth = PORTTILESHIGH-1;\r
2214 \r
2215                         if (xtl>xth || ytl>yth)\r
2216                                 continue;\r
2217 \r
2218                 //\r
2219                 // see if it's visable area covers any non 0 update tiles\r
2220                 //\r
2221                         updatespot = baseupdatespot = updateptr + uwidthtable[ytl] + xtl;\r
2222                         updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2223 \r
2224                         if (sprite->updatecount)\r
2225                         {\r
2226                                 sprite->updatecount--;                  // the sprite was just placed,\r
2227                                 goto redraw;                                    // so draw it for sure\r
2228                         }\r
2229 \r
2230                         for (y=ytl;y<=yth;y++)\r
2231                         {\r
2232                                 for (x=xtl;x<=xth;x++)\r
2233                                         if (*updatespot++)\r
2234                                                 goto redraw;\r
2235                                 updatespot += updatedelta;              // down to next line\r
2236                         }\r
2237                         continue;                                                       // no need to update\r
2238 \r
2239 redraw:\r
2240                 //\r
2241                 // set the tiles it covers to 3, because those tiles are being\r
2242                 // updated\r
2243                 //\r
2244                         updatespot = baseupdatespot;\r
2245                         for (y=ytl;y<=yth;y++)\r
2246                         {\r
2247                                 for (x=xtl;x<=xth;x++)\r
2248                                         *updatespot++ = 3;\r
2249                                 updatespot += updatedelta;              // down to next line\r
2250                         }\r
2251                 //\r
2252                 // draw it!\r
2253                 //\r
2254                         height = sprite->height;\r
2255                         sourceofs = sprite->sourceofs;\r
2256                         if (porty<0)\r
2257                         {\r
2258                                 height += porty;                                        // clip top off\r
2259                                 sourceofs -= porty*sprite->width;\r
2260                                 porty = 0;\r
2261                         }\r
2262                         else if (porty+height>PORTSCREENHIGH)\r
2263                         {\r
2264                                 height = PORTSCREENHIGH - porty;    // clip bottom off\r
2265                         }\r
2266 \r
2267                         dest = bufferofs + ylookup[porty] + portx;\r
2268 \r
2269                         switch (sprite->draw)\r
2270                         {\r
2271                         case spritedraw:\r
2272                                 VW_MaskBlock(grsegs[sprite->grseg], sourceofs,\r
2273                                         dest,sprite->width,height,sprite->planesize);\r
2274                                 break;\r
2275 \r
2276                         case maskdraw:\r
2277                                 break;\r
2278 \r
2279                         }\r
2280 #ifdef PROFILE\r
2281                         updatecount++;\r
2282 #endif\r
2283 \r
2284 \r
2285                 }\r
2286         }\r
2287 }\r
2288 \r
2289 \r
2290 /*\r
2291 =====================\r
2292 =\r
2293 = RF_Refresh        CGA\r
2294 =\r
2295 = All routines will draw at the port at bufferofs, possibly copying from\r
2296 = the port at masterofs.  The EGA version then page flips, while the\r
2297 = CGA version updates the screen from the buffer port.\r
2298 =\r
2299 = Screenpage is the currently displayed page, not the one being drawn\r
2300 = Otherpage is the page to be worked with now\r
2301 =\r
2302 =====================\r
2303 */\r
2304 \r
2305 void RF_Refresh (void)\r
2306 {\r
2307         long newtime;\r
2308 \r
2309         RFL_AnimateTiles ();\r
2310 \r
2311 //\r
2312 // update newly scrolled on tiles and animated tiles from the master screen\r
2313 //\r
2314         RFL_UpdateTiles ();\r
2315         RFL_EraseBlocks ();\r
2316 \r
2317 //\r
2318 // Update is all 0 except where sprites have changed or new area has\r
2319 // been scrolled on.  Go through all sprites and update the ones that cover\r
2320 // a non 0 update tile\r
2321 //\r
2322         RFL_UpdateSprites ();\r
2323 \r
2324 //\r
2325 // if the main program has a refresh hook set, call their function before\r
2326 // displaying the new page\r
2327 //\r
2328         if (refreshvector)\r
2329                 refreshvector();\r
2330 \r
2331 //\r
2332 // update everything to the screen\r
2333 //\r
2334         VW_CGAFullUpdate ();\r
2335 \r
2336 //\r
2337 // calculate tics since last refresh for adaptive timing\r
2338 //\r
2339         if (lasttimecount > TimeCount)\r
2340                 lasttimecount = TimeCount;              // if the game was paused a LONG time\r
2341         do\r
2342         {\r
2343                 newtime = TimeCount;\r
2344                 tics = newtime-lasttimecount;\r
2345         } while (tics<MINTICS);\r
2346         lasttimecount = newtime;\r
2347 \r
2348 #ifdef PROFILE\r
2349         itoa (tics,str,10);\r
2350         strcat (str,"\t");\r
2351         ltoa (TimeCount,str2,10);\r
2352         strcat (str,str2);\r
2353         strcat (str,"\t");\r
2354         ltoa (LocalTime,str2,10);\r
2355         strcat (str,str2);\r
2356         strcat (str,"\n");\r
2357         write (profile,str,strlen(str));\r
2358 #endif\r
2359         if (tics>MAXTICS)\r
2360                 tics = MAXTICS;\r
2361 \r
2362 }\r
2363 \r
2364 #endif          // GRMODE == CGAGR\r
2365 //===============================\r
2366 /*\r
2367 ; Keen Dreams Source Code\r
2368 ; Copyright (C) 2014 Javier M. Chavez\r
2369 ;\r
2370 ; This program is free software; you can redistribute it and/or modify\r
2371 ; it under the terms of the GNU General Public License as published by\r
2372 ; the Free Software Foundation; either version 2 of the License, or\r
2373 ; (at your option) any later version.\r
2374 ;\r
2375 ; This program is distributed in the hope that it will be useful,\r
2376 ; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
2377 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
2378 ; GNU General Public License for more details.\r
2379 ;\r
2380 ; You should have received a copy of the GNU General Public License along\r
2381 ; with this program; if not, write to the Free Software Foundation, Inc.,\r
2382 ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
2383 \r
2384 ; ID_RF_A.ASM\r
2385 \r
2386 IDEAL\r
2387 MODEL   MEDIUM,C\r
2388 \r
2389 INCLUDE "ID_ASM.EQU"\r
2390 \r
2391 CACHETILES      = 1             ;enable master screen tile caching\r
2392 \r
2393 ;============================================================================\r
2394 \r
2395 TILESWIDE       =       21\r
2396 TILESHIGH       =       14\r
2397 \r
2398 UPDATESIZE      =       (TILESWIDE+1)*TILESHIGH+1\r
2399 \r
2400 DATASEG\r
2401 \r
2402 EXTRN   screenseg:WORD\r
2403 EXTRN   updateptr:WORD\r
2404 EXTRN   updatestart:WORD\r
2405 EXTRN   masterofs:WORD          ;start of master tile port\r
2406 EXTRN   bufferofs:WORD          ;start of current buffer port\r
2407 EXTRN   screenstart:WORD        ;starts of three screens (0/1/master) in EGA mem\r
2408 EXTRN   grsegs:WORD\r
2409 EXTRN   mapsegs:WORD\r
2410 EXTRN   originmap:WORD\r
2411 EXTRN   updatemapofs:WORD\r
2412 EXTRN   tilecache:WORD\r
2413 EXTRN   tinf:WORD                       ;seg pointer to map header and tile info\r
2414 EXTRN   blockstarts:WORD        ;offsets from bufferofs for each update block\r
2415 \r
2416 planemask       db      ?\r
2417 planenum        db      ?\r
2418 \r
2419 CODESEG\r
2420 \r
2421 screenstartcs   dw      ?               ;in code segment for accesability\r
2422 \r
2423 \r
2424 \r
2425 \r
2426 IFE GRMODE-CGAGR\r
2427 ;============================================================================\r
2428 ;\r
2429 ; CGA refresh routines\r
2430 ;\r
2431 ;============================================================================\r
2432 \r
2433 TILEWIDTH       =       4\r
2434 \r
2435 ;=================\r
2436 ;\r
2437 ; RFL_NewTile\r
2438 ;\r
2439 ; Draws a composit two plane tile to the master screen and sets the update\r
2440 ; spot to 1 in both update pages, forcing the tile to be copied to the\r
2441 ; view pages the next two refreshes\r
2442 ;\r
2443 ; Called to draw newlly scrolled on strips and animating tiles\r
2444 ;\r
2445 ;=================\r
2446 \r
2447 PROC    RFL_NewTile     updateoffset:WORD\r
2448 PUBLIC  RFL_NewTile\r
2449 USES    SI,DI\r
2450 \r
2451 ;\r
2452 ; mark both update lists at this spot\r
2453 ;\r
2454         mov     di,[updateoffset]\r
2455 \r
2456         mov     bx,[updateptr]                  ;start of update matrix\r
2457         mov     [BYTE bx+di],1\r
2458 \r
2459         mov     dx,SCREENWIDTH-TILEWIDTH                ;add to get to start of next line\r
2460 \r
2461 ;\r
2462 ; set di to the location in screenseg to draw the tile\r
2463 ;\r
2464         shl     di,1\r
2465         mov     si,[updatemapofs+di]    ;offset in map from origin\r
2466         add     si,[originmap]\r
2467         mov     di,[blockstarts+di]             ;screen location for tile\r
2468         add     di,[masterofs]\r
2469 \r
2470 ;\r
2471 ; set BX to the foreground tile number and SI to the background number\r
2472 ; If either BX or SI = 0xFFFF, the tile does not need to be masked together\r
2473 ; as one of the planes totally eclipses the other\r
2474 ;\r
2475         mov     es,[mapsegs+2]                  ;foreground plane\r
2476         mov     bx,[es:si]\r
2477         mov     es,[mapsegs]                    ;background plane\r
2478         mov     si,[es:si]\r
2479 \r
2480         mov     es,[screenseg]\r
2481 \r
2482         or      bx,bx\r
2483         jz      @@singletile\r
2484         jmp     @@maskeddraw                    ;draw both together\r
2485 \r
2486 ;=============\r
2487 ;\r
2488 ; Draw single background tile from main memory\r
2489 ;\r
2490 ;=============\r
2491 \r
2492 @@singletile:\r
2493         shl     si,1\r
2494         mov     ds,[grsegs+STARTTILE16*2+si]\r
2495 \r
2496         xor     si,si                                   ;block is segment aligned\r
2497 \r
2498 REPT    15\r
2499         movsw\r
2500         movsw\r
2501         add     di,dx\r
2502 ENDM\r
2503         movsw\r
2504         movsw\r
2505 \r
2506         mov     ax,ss\r
2507         mov     ds,ax                                   ;restore turbo's data segment\r
2508         ret\r
2509 \r
2510 \r
2511 ;=========\r
2512 ;\r
2513 ; Draw a masked tile combo\r
2514 ; Interupts are disabled and the stack segment is reassigned\r
2515 ;\r
2516 ;=========\r
2517 @@maskeddraw:\r
2518         cli                                                     ; don't allow ints when SS is set\r
2519         shl     bx,1\r
2520         mov     ss,[grsegs+STARTTILE16M*2+bx]\r
2521         shl     si,1\r
2522         mov     ds,[grsegs+STARTTILE16*2+si]\r
2523 \r
2524         xor     si,si                                   ;first word of tile data\r
2525 \r
2526 REPT    16\r
2527         mov     ax,[si]                                 ;background tile\r
2528         and     ax,[ss:si]                              ;mask\r
2529         or      ax,[ss:si+64]                   ;masked data\r
2530         stosw\r
2531         mov     ax,[si+2]                               ;background tile\r
2532         and     ax,[ss:si+2]                    ;mask\r
2533         or      ax,[ss:si+66]                   ;masked data\r
2534         stosw\r
2535         add     si,4\r
2536         add     di,dx\r
2537 ENDM\r
2538 \r
2539         mov     ax,@DATA\r
2540         mov     ss,ax\r
2541         sti\r
2542         mov     ds,ax\r
2543         ret\r
2544 ENDP\r
2545 \r
2546 ENDIF\r
2547 \r
2548 \r
2549 \r
2550 IFE GRMODE-EGAGR\r
2551 ;===========================================================================\r
2552 ;\r
2553 ; EGA refresh routines\r
2554 ;\r
2555 ;===========================================================================\r
2556 \r
2557 TILEWIDTH       =       2\r
2558 \r
2559 ;=================\r
2560 ;\r
2561 ; RFL_NewTile\r
2562 ;\r
2563 ; Draws a composit two plane tile to the master screen and sets the update\r
2564 ; spot to 1 in both update pages, forcing the tile to be copied to the\r
2565 ; view pages the next two refreshes\r
2566 ;\r
2567 ; Called to draw newlly scrolled on strips and animating tiles\r
2568 ;\r
2569 ; Assumes write mode 0\r
2570 ;\r
2571 ;=================\r
2572 \r
2573 PROC    RFL_NewTile     updateoffset:WORD\r
2574 PUBLIC  RFL_NewTile\r
2575 USES    SI,DI\r
2576 \r
2577 ;\r
2578 ; mark both update lists at this spot\r
2579 ;\r
2580         mov     di,[updateoffset]\r
2581 \r
2582         mov     bx,[updatestart]                ;page 0 pointer\r
2583         mov     [BYTE bx+di],1\r
2584         mov     bx,[updatestart+2]              ;page 1 pointer\r
2585         mov     [BYTE bx+di],1\r
2586 \r
2587 ;\r
2588 ; set screenstartcs to the location in screenseg to draw the tile\r
2589 ;\r
2590         shl     di,1\r
2591         mov     si,[updatemapofs+di]    ;offset in map from origin\r
2592         add     si,[originmap]\r
2593         mov     di,[blockstarts+di]             ;screen location for tile\r
2594         add     di,[masterofs]\r
2595         mov     [cs:screenstartcs],di\r
2596 \r
2597 ;\r
2598 ; set BX to the foreground tile number and SI to the background number\r
2599 ; If either BX or SI = 0xFFFF, the tile does not need to be masked together\r
2600 ; as one of the planes totally eclipses the other\r
2601 ;\r
2602         mov     es,[mapsegs+2]                  ;foreground plane\r
2603         mov     bx,[es:si]\r
2604         mov     es,[mapsegs]                    ;background plane\r
2605         mov     si,[es:si]\r
2606 \r
2607         mov     es,[screenseg]\r
2608         mov     dx,SC_INDEX                             ;for stepping through map mask planes\r
2609 \r
2610         or      bx,bx\r
2611         jz      @@singletile\r
2612         jmp     @@maskeddraw                    ;draw both together\r
2613 \r
2614 ;=========\r
2615 ;\r
2616 ; No foreground tile, so draw a single background tile.\r
2617 ; Use the master screen cache if possible\r
2618 ;\r
2619 ;=========\r
2620 @@singletile:\r
2621 \r
2622         mov     bx,SCREENWIDTH-2                ;add to get to start of next line\r
2623         shl     si,1\r
2624 \r
2625 IFE CACHETILES\r
2626         jmp     @@singlemain\r
2627 ENDIF\r
2628 \r
2629         mov     ax,[tilecache+si]\r
2630         or      ax,ax\r
2631         jz      @@singlemain\r
2632 ;=============\r
2633 ;\r
2634 ; Draw single tile from cache\r
2635 ;\r
2636 ;=============\r
2637 \r
2638         mov     si,ax\r
2639 \r
2640         mov     ax,SC_MAPMASK + 15*256  ;all planes\r
2641         WORDOUT\r
2642 \r
2643         mov     dx,GC_INDEX\r
2644         mov     ax,GC_MODE + 1*256              ;write mode 1\r
2645         WORDOUT\r
2646 \r
2647         mov     di,[cs:screenstartcs]\r
2648         mov     ds,[screenseg]\r
2649 \r
2650 REPT    15\r
2651         movsb\r
2652         movsb\r
2653         add     si,bx\r
2654         add     di,bx\r
2655 ENDM\r
2656         movsb\r
2657         movsb\r
2658 \r
2659         xor     ah,ah                                   ;write mode 0\r
2660         WORDOUT\r
2661 \r
2662         mov     ax,ss\r
2663         mov     ds,ax                                   ;restore turbo's data segment\r
2664         ret\r
2665 \r
2666 ;=============\r
2667 ;\r
2668 ; Draw single tile from main memory\r
2669 ;\r
2670 ;=============\r
2671 \r
2672 @@singlemain:\r
2673         mov     ax,[cs:screenstartcs]\r
2674         mov     [tilecache+si],ax               ;next time it can be drawn from here with latch\r
2675         mov     ds,[grsegs+STARTTILE16*2+si]\r
2676 \r
2677         xor     si,si                                   ;block is segment aligned\r
2678 \r
2679         mov     ax,SC_MAPMASK+0001b*256 ;map mask for plane 0\r
2680 \r
2681         mov     cx,4                                    ;draw four planes\r
2682 @@planeloop:\r
2683         mov     dx,SC_INDEX\r
2684         WORDOUT\r
2685 \r
2686         mov     di,[cs:screenstartcs]   ;start at same place in all planes\r
2687 \r
2688 REPT    15\r
2689         movsw\r
2690         add     di,bx\r
2691 ENDM\r
2692         movsw\r
2693 \r
2694         shl     ah,1                                    ;shift plane mask over for next plane\r
2695         loop    @@planeloop\r
2696 \r
2697         mov     ax,ss\r
2698         mov     ds,ax                                   ;restore turbo's data segment\r
2699         ret\r
2700 \r
2701 \r
2702 ;=========\r
2703 ;\r
2704 ; Draw a masked tile combo\r
2705 ; Interupts are disabled and the stack segment is reassigned\r
2706 ;\r
2707 ;=========\r
2708 @@maskeddraw:\r
2709         cli                                                     ; don't allow ints when SS is set\r
2710         shl     bx,1\r
2711         mov     ss,[grsegs+STARTTILE16M*2+bx]\r
2712         shl     si,1\r
2713         mov     ds,[grsegs+STARTTILE16*2+si]\r
2714 \r
2715         xor     si,si                                   ;first word of tile data\r
2716 \r
2717         mov     ax,SC_MAPMASK+0001b*256 ;map mask for plane 0\r
2718 \r
2719         mov     di,[cs:screenstartcs]\r
2720 @@planeloopm:\r
2721         WORDOUT\r
2722 tileofs         =       0\r
2723 lineoffset      =       0\r
2724 REPT    16\r
2725         mov     bx,[si+tileofs]                 ;background tile\r
2726         and     bx,[ss:tileofs]                 ;mask\r
2727         or      bx,[ss:si+tileofs+32]   ;masked data\r
2728         mov     [es:di+lineoffset],bx\r
2729 tileofs         =       tileofs + 2\r
2730 lineoffset      =       lineoffset + SCREENWIDTH\r
2731 ENDM\r
2732         add     si,32\r
2733         shl     ah,1                                    ;shift plane mask over for next plane\r
2734         cmp     ah,10000b\r
2735         je      @@done                                  ;drawn all four planes\r
2736         jmp     @@planeloopm\r
2737 \r
2738 @@done:\r
2739         mov     ax,@DATA\r
2740         mov     ss,ax\r
2741         sti\r
2742         mov     ds,ax\r
2743         ret\r
2744 ENDP\r
2745 \r
2746 ENDIF\r
2747 \r
2748 IFE GRMODE-VGAGR\r
2749 ;============================================================================\r
2750 ;\r
2751 ; VGA refresh routines\r
2752 ;\r
2753 ;============================================================================\r
2754 \r
2755 \r
2756 ENDIF\r
2757 \r
2758 \r
2759 ;============================================================================\r
2760 ;\r
2761 ; reasonably common refresh routines\r
2762 ;\r
2763 ;============================================================================\r
2764 \r
2765 \r
2766 ;=================\r
2767 ;\r
2768 ; RFL_UpdateTiles\r
2769 ;\r
2770 ; Scans through the update matrix pointed to by updateptr, looking for 1s.\r
2771 ; A 1 represents a tile that needs to be copied from the master screen to the\r
2772 ; current screen (a new row or an animated tiled).  If more than one adjacent\r
2773 ; tile in a horizontal row needs to be copied, they will be copied as a group.\r
2774 ;\r
2775 ; Assumes write mode 1\r
2776 ;\r
2777 ;=================\r
2778 \r
2779 \r
2780 ; AX    0/1 for scasb, temp for segment register transfers\r
2781 ; BX    width for block copies\r
2782 ; CX    REP counter\r
2783 ; DX    line width deltas\r
2784 ; SI    source for copies\r
2785 ; DI    scas dest / movsb dest\r
2786 ; BP    pointer to UPDATETERMINATE\r
2787 ;\r
2788 ; DS\r
2789 ; ES\r
2790 ; SS\r
2791 \r
2792 PROC    RFL_UpdateTiles\r
2793 PUBLIC  RFL_UpdateTiles\r
2794 USES    SI,DI,BP\r
2795 \r
2796         jmp     SHORT @@realstart\r
2797 @@done:\r
2798 ;\r
2799 ; all tiles have been scanned\r
2800 ;\r
2801         ret\r
2802 \r
2803 @@realstart:\r
2804         mov     di,[updateptr]\r
2805         mov     bp,(TILESWIDE+1)*TILESHIGH+1\r
2806         add     bp,di                                   ; when di = bx, all tiles have been scanned\r
2807         push    di\r
2808         mov     cx,-1                                   ; definately scan the entire thing\r
2809 \r
2810 ;\r
2811 ; scan for a 1 in the update list, meaning a tile needs to be copied\r
2812 ; from the master screen to the current screen\r
2813 ;\r
2814 @@findtile:\r
2815         pop     di                                              ; place to continue scaning from\r
2816         mov     ax,ss\r
2817         mov     es,ax                                   ; search in the data segment\r
2818         mov     ds,ax\r
2819         mov al,1\r
2820         repne   scasb\r
2821         cmp     di,bp\r
2822         je      @@done\r
2823 \r
2824         cmp     [BYTE di],al\r
2825         jne     @@singletile\r
2826         jmp     @@tileblock\r
2827 \r
2828 ;============\r
2829 ;\r
2830 ; copy a single tile\r
2831 ;\r
2832 ;============\r
2833 EVEN\r
2834 @@singletile:\r
2835         inc     di                                              ; we know the next tile is nothing\r
2836         push    di                                      ; save off the spot being scanned\r
2837         sub     di,[updateptr]\r
2838         shl     di,1\r
2839         mov     di,[blockstarts-4+di]   ; start of tile location on screen\r
2840         mov     si,di\r
2841         add     di,[bufferofs]                  ; dest in current screen\r
2842         add     si,[masterofs]                  ; source in master screen\r
2843 \r
2844         mov     dx,SCREENWIDTH-TILEWIDTH\r
2845         mov     ax,[screenseg]\r
2846         mov     ds,ax\r
2847         mov     es,ax\r
2848 \r
2849 ;--------------------------\r
2850 \r
2851 IFE GRMODE-CGAGR\r
2852 \r
2853 REPT    15\r
2854         movsw\r
2855         movsw\r
2856         add     si,dx\r
2857         add     di,dx\r
2858 ENDM\r
2859         movsw\r
2860         movsw\r
2861 \r
2862 ENDIF\r
2863 \r
2864 ;--------------------------\r
2865 \r
2866 IFE GRMODE-EGAGR\r
2867 \r
2868 REPT    15\r
2869         movsb\r
2870         movsb\r
2871         add     si,dx\r
2872         add     di,dx\r
2873 ENDM\r
2874         movsb\r
2875         movsb\r
2876 \r
2877 ENDIF\r
2878 \r
2879 ;--------------------------\r
2880 \r
2881         jmp     @@findtile\r
2882 \r
2883 ;============\r
2884 ;\r
2885 ; more than one tile in a row needs to be updated, so do it as a group\r
2886 ;\r
2887 ;============\r
2888 EVEN\r
2889 @@tileblock:\r
2890         mov     dx,di                                   ; hold starting position + 1 in dx\r
2891         inc     di                                              ; we know the next tile also gets updated\r
2892         repe    scasb                           ; see how many more in a row\r
2893         push    di                                      ; save off the spot being scanned\r
2894 \r
2895         mov     bx,di\r
2896         sub     bx,dx                                   ; number of tiles in a row\r
2897         shl     bx,1                                    ; number of bytes / row\r
2898 \r
2899         mov     di,dx                                   ; lookup position of start tile\r
2900         sub     di,[updateptr]\r
2901         shl     di,1\r
2902         mov     di,[blockstarts-2+di]   ; start of tile location\r
2903         mov     si,di\r
2904         add     di,[bufferofs]                  ; dest in current screen\r
2905         add     si,[masterofs]                  ; source in master screen\r
2906 \r
2907         mov     dx,SCREENWIDTH\r
2908         sub     dx,bx                                   ; offset to next line on screen\r
2909 IFE GRMODE-CGAGR\r
2910         sub     dx,bx                                   ; bx is words wide in CGA tiles\r
2911 ENDIF\r
2912 \r
2913         mov     ax,[screenseg]\r
2914         mov     ds,ax\r
2915         mov     es,ax\r
2916 \r
2917 REPT    15\r
2918         mov     cx,bx\r
2919 IFE GRMODE-CGAGR\r
2920         rep     movsw\r
2921 ENDIF\r
2922 IFE GRMODE-EGAGR\r
2923         rep     movsb\r
2924 ENDIF\r
2925         add     si,dx\r
2926         add     di,dx\r
2927 ENDM\r
2928         mov     cx,bx\r
2929 IFE GRMODE-CGAGR\r
2930         rep     movsw\r
2931 ENDIF\r
2932 IFE GRMODE-EGAGR\r
2933         rep     movsb\r
2934 ENDIF\r
2935 \r
2936         dec     cx                                              ; was 0 from last rep movsb, now $ffff for scasb\r
2937         jmp     @@findtile\r
2938 \r
2939 ENDP\r
2940 \r
2941 \r
2942 ;============================================================================\r
2943 \r
2944 \r
2945 ;=================\r
2946 ;\r
2947 ; RFL_MaskForegroundTiles\r
2948 ;\r
2949 ; Scan through update looking for 3's.  If the foreground tile there is a\r
2950 ; masked foreground tile, draw it to the screen\r
2951 ;\r
2952 ;=================\r
2953 \r
2954 PROC    RFL_MaskForegroundTiles\r
2955 PUBLIC  RFL_MaskForegroundTiles\r
2956 USES    SI,DI,BP\r
2957         jmp     SHORT @@realstart\r
2958 @@done:\r
2959 ;\r
2960 ; all tiles have been scanned\r
2961 ;\r
2962         ret\r
2963 \r
2964 @@realstart:\r
2965         mov     di,[updateptr]\r
2966         mov     bp,(TILESWIDE+1)*TILESHIGH+2\r
2967         add     bp,di                                   ; when di = bx, all tiles have been scanned\r
2968         push    di\r
2969         mov     cx,-1                                   ; definately scan the entire thing\r
2970 ;\r
2971 ; scan for a 3 in the update list\r
2972 ;\r
2973 @@findtile:\r
2974         mov     ax,ss\r
2975         mov     es,ax                                   ; scan in the data segment\r
2976         mov     al,3\r
2977         pop     di                                              ; place to continue scaning from\r
2978         repne   scasb\r
2979         cmp     di,bp\r
2980         je      @@done\r
2981 \r
2982 ;============\r
2983 ;\r
2984 ; found a tile, see if it needs to be masked on\r
2985 ;\r
2986 ;============\r
2987 \r
2988         push    di\r
2989 \r
2990         sub     di,[updateptr]\r
2991         shl     di,1\r
2992         mov     si,[updatemapofs-2+di]  ; offset from originmap\r
2993         add     si,[originmap]\r
2994 \r
2995         mov     es,[mapsegs+2]                  ; foreground map plane segment\r
2996         mov     si,[es:si]                              ; foreground tile number\r
2997 \r
2998         or      si,si\r
2999         jz      @@findtile                              ; 0 = no foreground tile\r
3000 \r
3001         mov     bx,si\r
3002         add     bx,INTILE                               ;INTILE tile info table\r
3003         mov     es,[tinf]\r
3004         test    [BYTE PTR es:bx],80h            ;high bit = masked tile\r
3005         jz      @@findtile\r
3006 \r
3007 ;-------------------\r
3008 \r
3009 IFE GRMODE-CGAGR\r
3010 ;=================\r
3011 ;\r
3012 ; mask the tile CGA\r
3013 ;\r
3014 ;=================\r
3015 \r
3016         mov     di,[blockstarts-2+di]\r
3017         add     di,[bufferofs]\r
3018         mov     es,[screenseg]\r
3019         shl     si,1\r
3020         mov     ds,[grsegs+STARTTILE16M*2+si]\r
3021 \r
3022         mov     bx,64                                   ;data starts 64 bytes after mask\r
3023 \r
3024         xor     si,si\r
3025 \r
3026 lineoffset      =       0\r
3027 REPT    16\r
3028         mov     ax,[es:di+lineoffset]   ;background\r
3029         and     ax,[si]                                 ;mask\r
3030         or      ax,[si+bx]                              ;masked data\r
3031         mov     [es:di+lineoffset],ax   ;background\r
3032         inc     si\r
3033         inc     si\r
3034         mov     ax,[es:di+lineoffset+2] ;background\r
3035         and     ax,[si]                                 ;mask\r
3036         or      ax,[si+bx]                              ;masked data\r
3037         mov     [es:di+lineoffset+2],ax ;background\r
3038         inc     si\r
3039         inc     si\r
3040 lineoffset      =       lineoffset + SCREENWIDTH\r
3041 ENDM\r
3042 ENDIF\r
3043 \r
3044 ;-------------------\r
3045 \r
3046 IFE GRMODE-EGAGR\r
3047 ;=================\r
3048 ;\r
3049 ; mask the tile\r
3050 ;\r
3051 ;=================\r
3052 \r
3053         mov     [BYTE planemask],1\r
3054         mov     [BYTE planenum],0\r
3055 \r
3056         mov     di,[blockstarts-2+di]\r
3057         add     di,[bufferofs]\r
3058         mov     [cs:screenstartcs],di\r
3059         mov     es,[screenseg]\r
3060         shl     si,1\r
3061         mov     ds,[grsegs+STARTTILE16M*2+si]\r
3062 \r
3063         mov     bx,32                                   ;data starts 32 bytes after mask\r
3064 \r
3065 @@planeloopm:\r
3066         mov     dx,SC_INDEX\r
3067         mov     al,SC_MAPMASK\r
3068         mov     ah,[ss:planemask]\r
3069         WORDOUT\r
3070         mov     dx,GC_INDEX\r
3071         mov     al,GC_READMAP\r
3072         mov     ah,[ss:planenum]\r
3073         WORDOUT\r
3074 \r
3075         xor     si,si\r
3076         mov     di,[cs:screenstartcs]\r
3077 lineoffset      =       0\r
3078 REPT    16\r
3079         mov     cx,[es:di+lineoffset]   ;background\r
3080         and     cx,[si]                                 ;mask\r
3081         or      cx,[si+bx]                              ;masked data\r
3082         inc     si\r
3083         inc     si\r
3084         mov     [es:di+lineoffset],cx\r
3085 lineoffset      =       lineoffset + SCREENWIDTH\r
3086 ENDM\r
3087         add     bx,32                                   ;the mask is now further away\r
3088         inc     [ss:planenum]\r
3089         shl     [ss:planemask],1                ;shift plane mask over for next plane\r
3090         cmp     [ss:planemask],10000b   ;done all four planes?\r
3091         je      @@drawn                                 ;drawn all four planes\r
3092         jmp     @@planeloopm\r
3093 \r
3094 @@drawn:\r
3095 ENDIF\r
3096 \r
3097 ;-------------------\r
3098 \r
3099         mov     ax,ss\r
3100         mov     ds,ax\r
3101         mov     cx,-1                                   ;definately scan the entire thing\r
3102 \r
3103         jmp     @@findtile\r
3104 \r
3105 ENDP\r
3106 \r
3107 \r
3108 END\r
3109 \r
3110 */\r