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