]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_rf.c
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[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 (global_game_variables_t *gvar)\r
363 {\r
364 //      if (grmode == EGAGR)\r
365 //      {\r
366                 screenpage = 0;\r
367                 otherpage = 1;\r
368                 gvar->video.ofs.pan.panx = gvar->video.ofs.pan.pany = gvar->video.ofs.pan.pansx = gvar->video.ofs.pan.pansy = gvar->video.ofs.pan.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         gvar->video.ofs.pan.panx = (originxglobal>>G_P_SHIFT) & 15;\r
920         gvar->video.ofs.pan.pansx = gvar->video.ofs.pan.panx & 8;\r
921         gvar->video.ofs.pan.pany = gvar->video.ofs.pan.pansy = (originyglobal>>G_P_SHIFT) & 15;\r
922 //      gvar->video.ofs.pan.panadjust = gvar->video.ofs.pan.panx/8 + gvar->video.ofs.ylookup[gvar->video.ofs.pan.pany];\r
923         gvar->video.ofs.pan.panadjust = gvar->video.ofs.pan.panx/8 + (gvar->video.ofs.pan.pany*gvar->video.page[0].stridew);\r
924 /*#endif\r
925 \r
926 #if GRMODE == CGAGR\r
927         gvar->video.ofs.pan.panx = (originxglobal>>G_P_SHIFT) & 15;\r
928         gvar->video.ofs.pan.pansx = gvar->video.ofs.pan.panx & 12;\r
929         gvar->video.ofs.pan.pany = gvar->video.ofs.pan.pansy = (originyglobal>>G_P_SHIFT) & 15;\r
930         gvar->video.ofs.pan.panadjust = gvar->video.ofs.pan.pansx/4 + gvar->video.ofs.ylookup[gvar->video.ofs.pan.pansy];\r
931 #endif\r
932         */\r
933 \r
934 }\r
935 \r
936 \r
937 /*\r
938 =================\r
939 =\r
940 = RFL_ClearScrollBlocks\r
941 =\r
942 =================\r
943 */\r
944 \r
945 void RFL_ClearScrollBlocks (void)\r
946 {\r
947         gvar->video.ofs.pan.hscrollblocks = gvar->video.ofs.pan.vscrollblocks = 0;\r
948 }\r
949 \r
950 \r
951 /*\r
952 =================\r
953 =\r
954 = RF_SetScrollBlock\r
955 =\r
956 = Sets a horizontal or vertical scroll block\r
957 = a horizontal block is ----, meaning it blocks up/down movement\r
958 =\r
959 =================\r
960 */\r
961 \r
962 void RF_SetScrollBlock (int x, int y, boolean horizontal)\r
963 {\r
964         if (horizontal)\r
965         {\r
966                 gvar->video.ofs.pan.hscrolledge[gvar->video.ofs.pan.hscrollblocks] = y;\r
967                 if (gvar->video.ofs.pan.hscrollblocks++ == MAXSCROLLEDGES)\r
968                         Quit (gvar, "RF_SetScrollBlock: Too many horizontal scroll blocks");\r
969         }\r
970         else\r
971         {\r
972                 gvar->video.ofs.pan.vscrolledge[gvar->video.ofs.pan.vscrollblocks] = x;\r
973                 if (gvar->video.ofs.pan.vscrollblocks++ == MAXSCROLLEDGES)\r
974                         Quit (gvar, "RF_SetScrollBlock: Too many vertical scroll blocks");\r
975         }\r
976 }\r
977 \r
978 \r
979 /*\r
980 =================\r
981 =\r
982 = RFL_BoundScroll\r
983 =\r
984 = Bound a given x/y movement to scroll blocks\r
985 =\r
986 =================\r
987 */\r
988 \r
989 void RFL_BoundScroll (int x, int y)\r
990 {\r
991         int     check,newxtile,newytile;\r
992 \r
993         originxglobal += x;\r
994         originyglobal += y;\r
995 \r
996         newxtile= originxglobal >> G_T_SHIFT;\r
997         newytile = originyglobal >> G_T_SHIFT;\r
998 \r
999         if (x>0)\r
1000         {\r
1001                 newxtile+=SCREENTILESWIDE;\r
1002                 for (check=0;check<gvar->video.ofs.pan.vscrollblocks;check++)\r
1003                         if (gvar->video.ofs.pan.vscrolledge[check] == newxtile)\r
1004                         {\r
1005                                 originxglobal = originxglobal&0xff00;\r
1006                                 break;\r
1007                         }\r
1008         }\r
1009         else if (x<0)\r
1010         {\r
1011                 for (check=0;check<gvar->video.ofs.pan.vscrollblocks;check++)\r
1012                         if (gvar->video.ofs.pan.vscrolledge[check] == newxtile)\r
1013                         {\r
1014                                 originxglobal = (originxglobal&0xff00)+0x100;\r
1015                                 break;\r
1016                         }\r
1017         }\r
1018 \r
1019 \r
1020         if (y>0)\r
1021         {\r
1022                 newytile+=SCREENTILESHIGH;\r
1023                 for (check=0;check<gvar->video.ofs.pan.hscrollblocks;check++)\r
1024                         if (gvar->video.ofs.pan.hscrolledge[check] == newytile)\r
1025                         {\r
1026                                 originyglobal = originyglobal&0xff00;\r
1027                                 break;\r
1028                         }\r
1029         }\r
1030         else if (y<0)\r
1031         {\r
1032                 for (check=0;check<gvar->video.ofs.pan.hscrollblocks;check++)\r
1033                         if (gvar->video.ofs.pan.hscrolledge[check] == newytile)\r
1034                         {\r
1035                                 originyglobal = (originyglobal&0xff00)+0x100;\r
1036                                 break;\r
1037                         }\r
1038         }\r
1039 \r
1040 \r
1041         RFL_CalcOriginStuff (originxglobal, originyglobal);\r
1042 }\r
1043 \r
1044 \r
1045 //===========================================================================\r
1046 \r
1047 /*\r
1048 =====================\r
1049 =\r
1050 = RF_SetRefreshHook\r
1051 =\r
1052 =====================\r
1053 */\r
1054 \r
1055 void RF_SetRefreshHook (void (*func) (void) )\r
1056 {\r
1057         refreshvector = func;\r
1058 }\r
1059 \r
1060 \r
1061 //===========================================================================\r
1062 \r
1063 /*\r
1064 =================\r
1065 =\r
1066 = RFL_NewRow\r
1067 =\r
1068 = Bring a new row of tiles onto the port, spawning animating tiles\r
1069 =\r
1070 =================\r
1071 */\r
1072 \r
1073 void    RFL_NewRow (int dir)\r
1074 {\r
1075         unsigned count,updatespot,updatestep;\r
1076         int             x,y,xstep,ystep;\r
1077 \r
1078         switch (dir)\r
1079         {\r
1080         case 0:         // top row\r
1081                 updatespot = 0;\r
1082                 updatestep = 1;\r
1083                 x = originxtile;\r
1084                 y = originytile;\r
1085                 xstep = 1;\r
1086                 ystep = 0;\r
1087                 count = PORTTILESWIDE;\r
1088                 break;\r
1089 \r
1090         case 1:         // right row\r
1091                 updatespot = PORTTILESWIDE-1;\r
1092                 updatestep = UPDATEWIDE;\r
1093                 x = originxtile + PORTTILESWIDE-1;\r
1094                 y = originytile;\r
1095                 xstep = 0;\r
1096                 ystep = 1;\r
1097                 count = PORTTILESHIGH;\r
1098                 break;\r
1099 \r
1100         case 2:         // bottom row\r
1101                 updatespot = UPDATEWIDE*(PORTTILESHIGH-1);\r
1102                 updatestep = 1;\r
1103                 x = originxtile;\r
1104                 y = originytile + PORTTILESHIGH-1;\r
1105                 xstep = 1;\r
1106                 ystep = 0;\r
1107                 count = PORTTILESWIDE;\r
1108                 break;\r
1109 \r
1110         case 3:         // left row\r
1111                 updatespot = 0;\r
1112                 updatestep = UPDATEWIDE;\r
1113                 x = originxtile;\r
1114                 y = originytile;\r
1115                 xstep = 0;\r
1116                 ystep = 1;\r
1117                 count = PORTTILESHIGH;\r
1118                 break;\r
1119         default:\r
1120                 Quit (gvar, "RFL_NewRow: Bad dir!");\r
1121         }\r
1122 \r
1123         while (count--)\r
1124         {\r
1125                 RFL_NewTile(updatespot);\r
1126                 RFL_CheckForAnimTile (x,y);\r
1127                 updatespot+=updatestep;\r
1128                 x+=xstep;\r
1129                 y+=ystep;\r
1130         }\r
1131 }\r
1132 \r
1133 //===========================================================================\r
1134 \r
1135 /*\r
1136 =====================\r
1137 =\r
1138 = RF_ForceRefresh\r
1139 =\r
1140 =====================\r
1141 */\r
1142 \r
1143 void RF_ForceRefresh (void)\r
1144 {\r
1145         RF_NewPosition (originxglobal,originyglobal);\r
1146         RF_Refresh ();\r
1147         RF_Refresh ();\r
1148 }\r
1149 \r
1150 //===========================================================================\r
1151 \r
1152 /*\r
1153 =====================\r
1154 =\r
1155 = RF_MapToMap\r
1156 =\r
1157 = Copies a block of tiles (all three planes) from one point\r
1158 = in the map to another, accounting for animating tiles\r
1159 =\r
1160 =====================\r
1161 */\r
1162 /*++++\r
1163 void RF_MapToMap (unsigned srcx, unsigned srcy,\r
1164                                   unsigned destx, unsigned desty,\r
1165                                   unsigned width, unsigned height)\r
1166 {\r
1167         int                     x,y;\r
1168         unsigned        source,destofs,xspot,yspot;\r
1169         unsigned        linedelta,p0,p1,p2,updatespot;\r
1170         unsigned        far *source0, far *source1, far *source2;\r
1171         unsigned        far *dest0, far *dest1, far *dest2;\r
1172         boolean         changed;\r
1173 \r
1174         RFL_RemoveAnimsInBlock (destx,desty,width,height);\r
1175 \r
1176         source = mapbwidthtable[srcy]/2 + srcx;\r
1177 \r
1178         source0 = mapsegs[0]+source;\r
1179         source1 = mapsegs[1]+source;\r
1180         source2 = mapsegs[2]+source;\r
1181 \r
1182         destofs = mapbwidthtable[desty]/2 + destx;\r
1183         destofs -= source;\r
1184 \r
1185         linedelta = mapwidth - width;\r
1186 \r
1187         for (y=0;y<height;y++,source0+=linedelta,source1+=linedelta,source2+=linedelta)\r
1188                 for (x=0;x<width;x++,source0++,source1++,source2++)\r
1189                 {\r
1190                         p0 = *source0;\r
1191                         p1 = *source1;\r
1192                         p2 = *source2;\r
1193 \r
1194                         dest0 = source0 + destofs;\r
1195                         dest1 = source1 + destofs;\r
1196                         dest2 = source2 + destofs;\r
1197 \r
1198 //\r
1199 // only make a new tile if it is different\r
1200 //\r
1201                         if (p0 != *dest0 || p1 != *dest1 || p2 != *dest2)\r
1202                         {\r
1203                                 *dest0 = p0;\r
1204                                 *dest1 = p1;\r
1205                                 *dest2 = p2;\r
1206                                 changed = true;\r
1207                         }\r
1208                         else\r
1209                                 changed = false;\r
1210 \r
1211 //\r
1212 // if tile is on the view port\r
1213 //\r
1214                         xspot = destx+x-originxtile;\r
1215                         yspot = desty+y-originytile;\r
1216                         if (yspot < PORTTILESHIGH && xspot < PORTTILESWIDE)\r
1217                         {\r
1218                                 if (changed)\r
1219                                 {\r
1220                                         updatespot = uwidthtable[yspot]+xspot;\r
1221                                         RFL_NewTile(updatespot);\r
1222                                 }\r
1223                                 RFL_CheckForAnimTile (destx+x,desty+y);\r
1224                         }\r
1225                 }\r
1226 }\r
1227 */\r
1228 //===========================================================================\r
1229 \r
1230 \r
1231 /*\r
1232 =====================\r
1233 =\r
1234 = RF_MemToMap\r
1235 =\r
1236 = Copies a string of tiles from main memory to the map,\r
1237 = accounting for animating tiles\r
1238 =\r
1239 =====================\r
1240 */\r
1241 /*++++\r
1242 void RF_MemToMap (unsigned far *source, unsigned plane,\r
1243                                   unsigned destx, unsigned desty,\r
1244                                   unsigned width, unsigned height)\r
1245 {\r
1246         int                     x,y;\r
1247         unsigned        xspot,yspot;\r
1248         unsigned        linedelta,updatespot;\r
1249         unsigned        far *dest,old,new;\r
1250         boolean         changed;\r
1251 \r
1252         RFL_RemoveAnimsInBlock (destx,desty,width,height);\r
1253 \r
1254         dest = mapsegs[plane] + mapbwidthtable[desty]/2 + destx;\r
1255 \r
1256         linedelta = mapwidth - width;\r
1257 \r
1258         for (y=0;y<height;y++,dest+=linedelta)\r
1259                 for (x=0;x<width;x++)\r
1260                 {\r
1261                         old = *dest;\r
1262                         new = *source++;\r
1263                         if (old != new)\r
1264                         {\r
1265                                 *dest = new;\r
1266                                 changed = true;\r
1267                         }\r
1268                         else\r
1269                                 changed = false;\r
1270 \r
1271                         dest++;\r
1272                         xspot = destx+x-originxtile;\r
1273                         yspot = desty+y-originytile;\r
1274                         if (yspot < PORTTILESHIGH && xspot < PORTTILESWIDE)\r
1275                         {\r
1276                                 if (changed)\r
1277                                 {\r
1278                                         updatespot = uwidthtable[yspot]+xspot;\r
1279                                         RFL_NewTile(updatespot);\r
1280                                 }\r
1281                                 RFL_CheckForAnimTile (destx+x,desty+y);\r
1282                         }\r
1283                 }\r
1284 }*/\r
1285 \r
1286 //===========================================================================\r
1287 \r
1288 \r
1289 /*\r
1290 =====================\r
1291 =\r
1292 = RFL_BoundNewOrigin\r
1293 =\r
1294 = Copies a string of tiles from main memory to the map,\r
1295 = accounting for animating tiles\r
1296 =\r
1297 =====================\r
1298 */\r
1299 \r
1300 void RFL_BoundNewOrigin (unsigned orgx,unsigned orgy)\r
1301 {\r
1302         int     check,edge;\r
1303 \r
1304 //\r
1305 // calculate new origin related globals\r
1306 //\r
1307         if (orgx<originxmin)\r
1308           orgx=originxmin;\r
1309         else if (orgx>originxmax)\r
1310           orgx=originxmax;\r
1311 \r
1312         if (orgy<originymin)\r
1313           orgy=originymin;\r
1314         else if (orgy>originymax)\r
1315           orgy=originymax;\r
1316 \r
1317         originxtile = orgx>>G_T_SHIFT;\r
1318         originytile = orgy>>G_T_SHIFT;\r
1319 \r
1320         for (check=0;check<gvar->video.ofs.pan.vscrollblocks;check++)\r
1321         {\r
1322                 edge = gvar->video.ofs.pan.vscrolledge[check];\r
1323                 if (edge>=originxtile && edge <=originxtile+10)\r
1324                 {\r
1325                         orgx = (edge+1)*TILEGLOBAL;\r
1326                         break;\r
1327                 }\r
1328                 if (edge>=originxtile+11 && edge <=originxtile+20)\r
1329                 {\r
1330                         orgx = (edge-20)*TILEGLOBAL;\r
1331                         break;\r
1332                 }\r
1333         }\r
1334 \r
1335         for (check=0;check<gvar->video.ofs.pan.hscrollblocks;check++)\r
1336         {\r
1337                 edge = gvar->video.ofs.pan.hscrolledge[check];\r
1338                 if (edge>=originytile && edge <=originytile+6)\r
1339                 {\r
1340                         orgy = (edge+1)*TILEGLOBAL;\r
1341                         break;\r
1342                 }\r
1343                 if (edge>=originytile+7 && edge <=originytile+13)\r
1344                 {\r
1345                         orgy = (edge-13)*TILEGLOBAL;\r
1346                         break;\r
1347                 }\r
1348         }\r
1349 \r
1350 \r
1351         RFL_CalcOriginStuff (orgx,orgy);\r
1352 }\r
1353 \r
1354 \r
1355 //===========================================================================\r
1356 \r
1357 /*\r
1358 =====================\r
1359 =\r
1360 = RF_ClearBlock\r
1361 =\r
1362 = Posts erase blocks to clear a certain area of the screen to the master\r
1363 = screen, to erase text or something draw directly to the screen\r
1364 =\r
1365 = Parameters in pixels, but erasure is byte bounded\r
1366 =\r
1367 =====================\r
1368 */\r
1369 \r
1370 void RF_ClearBlock (int x, int y, int width, int height)\r
1371 {\r
1372 //      eraseblocktype block;\r
1373 \r
1374 #if GRMODE == EGAGR\r
1375         block.screenx = x/8+originxscreen;\r
1376         block.screeny = y+originyscreen;\r
1377         block.width = (width+(x&7)+7)/8;\r
1378         block.height = height;\r
1379         memcpy (eraselistptr[0]++,&block,sizeof(block));\r
1380         memcpy (eraselistptr[1]++,&block,sizeof(block));\r
1381 #endif\r
1382 \r
1383 #if GRMODE == CGAGR\r
1384         block.screenx = x/4+originxscreen;\r
1385         block.screeny = y+originyscreen;\r
1386         block.width = (width+(x&3)+3)/4;\r
1387         block.height = height;\r
1388         memcpy (eraselistptr[0]++,&block,sizeof(block));\r
1389 #endif\r
1390 \r
1391 }\r
1392 \r
1393 //===========================================================================\r
1394 \r
1395 /*\r
1396 =====================\r
1397 =\r
1398 = RF_RedrawBlock\r
1399 =\r
1400 = Causes a number of tiles to be redrawn to the master screen and updated\r
1401 =\r
1402 = Parameters in pixels, but erasure is tile bounded\r
1403 =\r
1404 =====================\r
1405 */\r
1406 \r
1407 void RF_RedrawBlock (int x, int y, int width, int height)\r
1408 {\r
1409         int     xx,yy,xl,xh,yl,yh;\r
1410 \r
1411         xl=(x+gvar->video.ofs.pan.panx)/16;\r
1412         xh=(x+gvar->video.ofs.pan.panx+width+15)/16;\r
1413         yl=(y+gvar->video.ofs.pan.pany)/16;\r
1414         yh=(y+gvar->video.ofs.pan.pany+height+15)/16;\r
1415         for (yy=yl;yy<=yh;yy++)\r
1416                 for (xx=xl;xx<=xh;xx++)\r
1417                         RFL_NewTile (yy*UPDATEWIDE+xx);\r
1418 }\r
1419 \r
1420 \r
1421 //===========================================================================\r
1422 \r
1423 /*\r
1424 =====================\r
1425 =\r
1426 = RF_CalcTics\r
1427 =\r
1428 =====================\r
1429 */\r
1430 \r
1431 void RF_CalcTics (void)\r
1432 {\r
1433         long    newtime;//,oldtimecount;\r
1434         word TimeCount = *clockw;\r
1435 \r
1436 //\r
1437 // calculate tics since last refresh for adaptive timing\r
1438 //\r
1439         if (lasttimecount > TimeCount)\r
1440                 TimeCount = lasttimecount;              // if the game was paused a LONG time\r
1441 \r
1442 /*++++  if (DemoMode)                                   // demo recording and playback needs\r
1443         {                                                               // to be constant\r
1444 //\r
1445 // take DEMOTICS or more tics, and modify Timecount to reflect time taken\r
1446 //\r
1447                 oldtimecount = lasttimecount;\r
1448                 while (TimeCount<oldtimecount+DEMOTICS*2)\r
1449                 ;\r
1450                 lasttimecount = oldtimecount + DEMOTICS;\r
1451                 TimeCount = lasttimecount + DEMOTICS;\r
1452                 tics = DEMOTICS;\r
1453         }\r
1454         else\r
1455         {*/\r
1456 //\r
1457 // non demo, so report actual time\r
1458 //\r
1459                 do\r
1460                 {\r
1461                         newtime = TimeCount;\r
1462                         tics = newtime-lasttimecount;\r
1463                 } while (tics<MINTICS);\r
1464                 lasttimecount = newtime;\r
1465 \r
1466 #ifdef PROFILE\r
1467                         strcpy (scratch,"\tTics:");\r
1468                         itoa (tics,str,10);\r
1469                         strcat (scratch,str);\r
1470                         strcat (scratch,"\n");\r
1471                         write (profilehandle,scratch,strlen(scratch));\r
1472 #endif\r
1473 \r
1474                 if (tics>MAXTICS)\r
1475                 {\r
1476                         TimeCount -= (tics-MAXTICS);\r
1477                         tics = MAXTICS;\r
1478                 }\r
1479 //      }\r
1480 }\r
1481 \r
1482 /*\r
1483 =============================================================================\r
1484 \r
1485                                         EGA specific routines\r
1486 \r
1487 =============================================================================\r
1488 */\r
1489 \r
1490 #if GRMODE == EGAGR\r
1491 \r
1492 /*\r
1493 =====================\r
1494 =\r
1495 = RF_FindFreeBuffer\r
1496 =\r
1497 = Finds the start of unused, non visable buffer space\r
1498 =\r
1499 =====================\r
1500 */\r
1501 \r
1502 unsigned RF_FindFreeBuffer (void)\r
1503 {\r
1504         unsigned        spot,i,j;\r
1505         boolean         ok;\r
1506 \r
1507         for (i=0;i<3;i++)\r
1508         {\r
1509                 spot = screenstart[i]+SCREENSPACE;\r
1510                 ok = true;\r
1511                 for (j=0;j<3;j++)\r
1512                         if (spot == screenstart[j])\r
1513                         {\r
1514                                 ok = false;\r
1515                                 break;\r
1516                         }\r
1517                 if (ok)\r
1518                         return spot;\r
1519         }\r
1520 \r
1521         return 0;       // never get here...\r
1522 }\r
1523 \r
1524 //===========================================================================\r
1525 \r
1526 /*\r
1527 =====================\r
1528 =\r
1529 = RF_NewPosition EGA\r
1530 =\r
1531 =====================\r
1532 */\r
1533 \r
1534 void RF_NewPosition (unsigned x, unsigned y)\r
1535 {\r
1536         int mx,my;\r
1537         byte    *page0ptr,*page1ptr;\r
1538         unsigned        updatenum;\r
1539 \r
1540         RFL_BoundNewOrigin (x,y);\r
1541 \r
1542 // calculate new origin related globals\r
1543 //\r
1544         RFL_CalcOriginStuff (x,y);\r
1545 \r
1546 //\r
1547 // clear out all animating tiles\r
1548 //\r
1549         RFL_InitAnimList ();\r
1550 \r
1551 //\r
1552 // set up the new update arrays at base position\r
1553 //\r
1554         memset (tilecache,0,sizeof(tilecache));         // old cache is invalid\r
1555 \r
1556         updatestart[0] = baseupdatestart[0];\r
1557         updatestart[1] = baseupdatestart[1];\r
1558         updateptr = updatestart[otherpage];\r
1559 \r
1560         page0ptr = updatestart[0]+PORTTILESWIDE;        // used to stick "0"s after rows\r
1561         page1ptr = updatestart[1]+PORTTILESWIDE;\r
1562 \r
1563         updatenum = 0;                          // start at first visable tile\r
1564 \r
1565         for (my=0;my<PORTTILESHIGH;my++)\r
1566         {\r
1567                 for (mx=0;mx<PORTTILESWIDE;mx++)\r
1568                 {\r
1569                         RFL_NewTile(updatenum);                 // puts "1"s in both pages\r
1570                         RFL_CheckForAnimTile(mx+originxtile,my+originytile);\r
1571                         updatenum++;\r
1572                 }\r
1573                 updatenum++;\r
1574                 *page0ptr = *page1ptr = 0; // set a 0 at end of a line of tiles\r
1575                 page0ptr+=(PORTTILESWIDE+1);\r
1576                 page1ptr+=(PORTTILESWIDE+1);\r
1577         }\r
1578         *(word *)(page0ptr-PORTTILESWIDE)\r
1579                 = *(word *)(page1ptr-PORTTILESWIDE) = UPDATETERMINATE;\r
1580 }\r
1581 \r
1582 //===========================================================================\r
1583 \r
1584 /*\r
1585 =================\r
1586 =\r
1587 = RFL_OldRow EGA\r
1588 =\r
1589 = Uncache the trailing row of tiles\r
1590 =\r
1591 =================\r
1592 */\r
1593 \r
1594 void    RFL_OldRow (unsigned updatespot,unsigned count,unsigned step)\r
1595 {\r
1596 \r
1597 asm     mov     si,[updatespot]                 // pointer inside each map plane\r
1598 asm     mov     cx,[count]                              // number of tiles to clear\r
1599 asm     mov     dx,[step]                               // move to next tile\r
1600 asm     mov     es,[WORD PTR mapsegs]                   // background plane\r
1601 asm     mov     ds,[WORD PTR mapsegs+2]                 // foreground plane\r
1602 \r
1603 clearcache:\r
1604 asm     mov     bx,[si]\r
1605 asm     or      bx,bx\r
1606 asm     jnz     blockok                                 // if a foreground tile, block wasn't cached\r
1607 asm     mov     bx,[es:si]\r
1608 asm     shl     bx,1\r
1609 asm     mov     [WORD PTR ss:tilecache+bx],0  //tile is no longer in master screen cache\r
1610 blockok:\r
1611 asm     add     si,dx\r
1612 asm     loop    clearcache\r
1613 \r
1614 asm     mov     ax,ss\r
1615 asm     mov     ds,ax\r
1616 \r
1617 }\r
1618 \r
1619 \r
1620 /*\r
1621 =====================\r
1622 =\r
1623 = RF_Scroll  EGA\r
1624 =\r
1625 = Move the origin x/y global coordinates, readjust the screen panning, and\r
1626 = scroll if needed.  If the scroll distance is greater than one tile, the\r
1627 = entire screen will be redrawn (this could be generalized, but scrolling\r
1628 = more than one tile per refresh is a bad idea!).\r
1629 =\r
1630 =====================\r
1631 */\r
1632 \r
1633 void RF_Scroll (int x, int y)\r
1634 {\r
1635         long            neworgx,neworgy;\r
1636         int                     i,deltax,deltay,absdx,absdy;\r
1637         int                     oldxt,oldyt,move,yy;\r
1638         unsigned        updatespot;\r
1639         byte            *update0,*update1;\r
1640         unsigned        oldgvar->video.ofs.pan.panx,oldgvar->video.ofs.pan.panadjust,oldoriginmap,oldscreen,newscreen,screencopy;\r
1641         int                     screenmove;\r
1642 \r
1643         oldxt = originxtile;\r
1644         oldyt = originytile;\r
1645         oldoriginmap = originmap;\r
1646         oldgvar->video.ofs.pan.panadjust = gvar->video.ofs.pan.panadjust;\r
1647         oldgvar->video.ofs.pan.panx = gvar->video.ofs.pan.panx;\r
1648 \r
1649         RFL_CalcOriginStuff ((long)originxglobal + x,(long)originyglobal + y);\r
1650 \r
1651         deltax = originxtile - oldxt;\r
1652         absdx = abs(deltax);\r
1653         deltay = originytile - oldyt;\r
1654         absdy = abs(deltay);\r
1655 \r
1656         if (absdx>1 || absdy>1)\r
1657         {\r
1658         //\r
1659         // scrolled more than one tile, so start from scratch\r
1660         //\r
1661                 RF_NewPosition(originxglobal,originyglobal);\r
1662                 return;\r
1663         }\r
1664 \r
1665         if (!absdx && !absdy)\r
1666                 return;                                 // the screen has not scrolled an entire tile\r
1667 \r
1668 \r
1669 //\r
1670 // adjust screens and handle SVGA crippled compatability mode\r
1671 //\r
1672         screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;\r
1673         for (i=0;i<3;i++)\r
1674         {\r
1675                 screenstart[i]+= screenmove;\r
1676                 if (compatability && screenstart[i] > (0x10000l-SCREENSPACE) )\r
1677                 {\r
1678                         //\r
1679                         // move the screen to the opposite end of the buffer\r
1680                         //\r
1681                         screencopy = screenmove>0 ? FREEEGAMEM : -FREEEGAMEM;\r
1682                         oldscreen = screenstart[i] - screenmove;\r
1683                         newscreen = oldscreen + screencopy;\r
1684                         screenstart[i] = newscreen + screenmove;\r
1685 //++++                  VW_ScreenToScreen (oldscreen,newscreen,\r
1686                                 PORTTILESWIDE*2,PORTTILESHIGH*16);\r
1687 \r
1688 //++++                  if (i==screenpage)\r
1689 //++++                          VL_SetScreen(newscreen+oldgvar->video.ofs.pan.panadjust,oldgvar->video.ofs.pan.panx & xpanmask);\r
1690                 }\r
1691         }\r
1692         bufferofs = screenstart[otherpage];\r
1693         displayofs = screenstart[screenpage];\r
1694         masterofs = screenstart[2];\r
1695 \r
1696 \r
1697 //\r
1698 // float the update regions\r
1699 //\r
1700         move = deltax;\r
1701         if (deltay==1)\r
1702           move += UPDATEWIDE;\r
1703         else if (deltay==-1)\r
1704           move -= UPDATEWIDE;\r
1705 \r
1706         updatestart[0]+=move;\r
1707         updatestart[1]+=move;\r
1708 \r
1709 //\r
1710 // draw the new tiles just scrolled on to the master screen, and\r
1711 // mark them as needing to be copied to each screen next refreshes\r
1712 // Make sure a zero is at the end of each row in update\r
1713 //\r
1714 \r
1715         if (deltax)\r
1716         {\r
1717                 if (deltax==1)\r
1718                 {\r
1719                         RFL_NewRow (1);                 // new right row\r
1720                         RFL_OldRow (oldoriginmap,PORTTILESHIGH,mapbyteswide);\r
1721                         RFL_RemoveAnimsOnX (originxtile-1);\r
1722                 }\r
1723                 else\r
1724                 {\r
1725                         RFL_NewRow (3);                 // new left row\r
1726                         RFL_OldRow (oldoriginmap+(PORTTILESWIDE-1)*2,PORTTILESHIGH\r
1727                         ,mapbyteswide);\r
1728                         RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);\r
1729                 }\r
1730 \r
1731                 update0 = updatestart[0]+PORTTILESWIDE;\r
1732                 update1 = updatestart[1]+PORTTILESWIDE;\r
1733                 for     (yy=0;yy<PORTTILESHIGH;yy++)\r
1734                 {\r
1735                         *update0 = *update1 = 0;        // drop a 0 at end of each row\r
1736                         update0+=UPDATEWIDE;\r
1737                         update1+=UPDATEWIDE;\r
1738                 }\r
1739         }\r
1740 \r
1741 //----------------\r
1742 \r
1743         if (deltay)\r
1744         {\r
1745                 if (deltay==1)\r
1746                 {\r
1747                         RFL_NewRow (2);                 // new bottom row\r
1748                         RFL_OldRow (oldoriginmap,PORTTILESWIDE,2);\r
1749                         updatespot = UPDATEWIDE*(PORTTILESHIGH-1);\r
1750                         RFL_RemoveAnimsOnY (originytile-1);\r
1751                 }\r
1752                 else\r
1753                 {\r
1754                         RFL_NewRow (0);                 // new top row\r
1755                         RFL_OldRow (oldoriginmap+mapbwidthtable[PORTTILESHIGH-1]\r
1756                         ,PORTTILESWIDE,2);\r
1757                         updatespot = 0;\r
1758                         RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);\r
1759                 }\r
1760 \r
1761                 *(updatestart[0]+updatespot+PORTTILESWIDE) =\r
1762                         *(updatestart[1]+updatespot+PORTTILESWIDE) = 0;\r
1763         }\r
1764 \r
1765 //----------------\r
1766 \r
1767         //\r
1768         // place a new terminator\r
1769         //\r
1770         update0 = updatestart[0]+UPDATEWIDE*PORTTILESHIGH-1;\r
1771         update1 = updatestart[1]+UPDATEWIDE*PORTTILESHIGH-1;\r
1772         *update0++ = *update1++ = 0;\r
1773         *(unsigned *)update0 = *(unsigned *)update1 = UPDATETERMINATE;\r
1774 }\r
1775 \r
1776 //===========================================================================\r
1777 \r
1778 /*\r
1779 =====================\r
1780 =\r
1781 = RF_PlaceSprite   EGA\r
1782 =\r
1783 =====================\r
1784 */\r
1785 \r
1786 void RF_PlaceSprite (void **user,unsigned globalx,unsigned globaly,\r
1787         unsigned spritenumber, drawtype draw, int priority)\r
1788 {\r
1789         spritelisttype  register *sprite,*next;\r
1790         spritetabletype far *spr;\r
1791         spritetype _seg *block;\r
1792         unsigned        shift,pixx;\r
1793         char            str[80],str2[10];\r
1794 \r
1795         if (!spritenumber || spritenumber == (unsigned)-1)\r
1796         {\r
1797                 RF_RemoveSprite (user);\r
1798                 return;\r
1799         }\r
1800 \r
1801         sprite = (spritelisttype *)*user;\r
1802 \r
1803         if      (sprite)\r
1804         {\r
1805         // sprite allready exists in the list, so we can use it's block\r
1806 \r
1807         //\r
1808         // post an erase block to both pages by copying screenx,screeny,width,height\r
1809         // both pages may not need to be erased if the sprite just changed last frame\r
1810         //\r
1811                 if (sprite->updatecount<2)\r
1812                 {\r
1813                         if (!sprite->updatecount)\r
1814                                 memcpy (eraselistptr[otherpage]++,sprite,sizeof(eraseblocktype));\r
1815                         memcpy (eraselistptr[screenpage]++,sprite,sizeof(eraseblocktype));\r
1816                 }\r
1817 \r
1818                 if (priority != sprite->priority)\r
1819                 {\r
1820                 // sprite mvoed to another priority, so unlink the old one and\r
1821                 // relink it in the new priority\r
1822 \r
1823                         next = sprite->nextsprite;                      // cut old links\r
1824                         if (next)\r
1825                                 next->prevptr = sprite->prevptr;\r
1826                         *sprite->prevptr = next;\r
1827                         goto linknewspot;\r
1828                 }\r
1829         }\r
1830         else\r
1831         {\r
1832         // this is a brand new sprite, so allocate a block from the array\r
1833 \r
1834                 if (!spritefreeptr)\r
1835                         Quit (gvar, "RF_PlaceSprite: No free spots in spritearray!");\r
1836 \r
1837                 sprite = spritefreeptr;\r
1838                 spritefreeptr = spritefreeptr->nextsprite;\r
1839 \r
1840 linknewspot:\r
1841                 next = prioritystart[priority];         // stick it in new spot\r
1842                 if (next)\r
1843                         next->prevptr = &sprite->nextsprite;\r
1844                 sprite->nextsprite = next;\r
1845                 prioritystart[priority] = sprite;\r
1846                 sprite->prevptr = &prioritystart[priority];\r
1847         }\r
1848 \r
1849 //\r
1850 // write the new info to the sprite\r
1851 //\r
1852         spr = &spritetable[spritenumber-STARTSPRITES];\r
1853         block = (spritetype _seg *)grsegs[spritenumber];\r
1854 \r
1855         if (!block)\r
1856         {\r
1857                 strcpy (str,"RF_PlaceSprite: Placed an uncached sprite:");\r
1858                 itoa (spritenumber,str2,10);\r
1859                 strcat (str,str2);\r
1860                 Quit (str);\r
1861         }\r
1862 \r
1863         globaly+=spr->orgy;\r
1864         globalx+=spr->orgx;\r
1865 \r
1866         pixx = globalx >> G_SY_SHIFT;\r
1867         shift = (pixx&7)/2;\r
1868 \r
1869         sprite->screenx = pixx >> (G_EGASX_SHIFT-G_SY_SHIFT);\r
1870         sprite->screeny = globaly >> G_SY_SHIFT;\r
1871         sprite->width = block->width[shift];\r
1872         sprite->height = spr->height;\r
1873         sprite->grseg = spritenumber;\r
1874         sprite->sourceofs = block->sourceoffset[shift];\r
1875         sprite->planesize = block->planesize[shift];\r
1876         sprite->draw = draw;\r
1877         sprite->priority = priority;\r
1878         sprite->tilex = sprite->screenx >> SX_T_SHIFT;\r
1879         sprite->tiley = sprite->screeny >> SY_T_SHIFT;\r
1880         sprite->tilewide = ( (sprite->screenx + sprite->width -1) >> SX_T_SHIFT )\r
1881                 - sprite->tilex + 1;\r
1882         sprite->tilehigh = ( (sprite->screeny + sprite->height -1) >> SY_T_SHIFT )\r
1883                 - sprite->tiley + 1;\r
1884 \r
1885         sprite->updatecount = 2;                // draw on next two refreshes\r
1886 \r
1887 // save the sprite pointer off in the user's pointer so it can be moved\r
1888 // again later\r
1889 \r
1890         *user = sprite;\r
1891 }\r
1892 \r
1893 //===========================================================================\r
1894 \r
1895 /*\r
1896 =====================\r
1897 =\r
1898 = RF_RemoveSprite  EGA\r
1899 =\r
1900 =====================\r
1901 */\r
1902 \r
1903 void RF_RemoveSprite (void **user)\r
1904 {\r
1905         spritelisttype  *sprite,*next;\r
1906 \r
1907         sprite = (spritelisttype *)*user;\r
1908         if (!sprite)\r
1909                 return;\r
1910 \r
1911 //\r
1912 // post an erase block to both pages by copying screenx,screeny,width,height\r
1913 // both pages may not need to be erased if the sprite just changed last frame\r
1914 //\r
1915         if (sprite->updatecount<2)\r
1916         {\r
1917                 if (!sprite->updatecount)\r
1918                         memcpy (eraselistptr[otherpage]++,sprite,sizeof(eraseblocktype));\r
1919                 memcpy (eraselistptr[screenpage]++,sprite,sizeof(eraseblocktype));\r
1920         }\r
1921 \r
1922 //\r
1923 // unlink the sprite node\r
1924 //\r
1925         next = sprite->nextsprite;\r
1926         if (next)                                               // if (!next), sprite is last in chain\r
1927                 next->prevptr = sprite->prevptr;\r
1928         *sprite->prevptr = next;\r
1929 \r
1930 //\r
1931 // add it back to the free list\r
1932 //\r
1933         sprite->nextsprite = spritefreeptr;\r
1934         spritefreeptr = sprite;\r
1935 \r
1936 //\r
1937 // null the users pointer, so next time that actor gets placed, it will\r
1938 // allocate a new block\r
1939 //\r
1940 \r
1941         *user = 0;\r
1942 }\r
1943 \r
1944 \r
1945 //===========================================================================\r
1946 \r
1947 \r
1948 /*\r
1949 ====================\r
1950 =\r
1951 = RFL_EraseBlocks  EGA\r
1952 =\r
1953 = Write mode 1 should be set\r
1954 =\r
1955 ====================\r
1956 */\r
1957 \r
1958 void RFL_EraseBlocks (void)\r
1959 {\r
1960         eraseblocktype  *block,*done;\r
1961         int                     screenxh,screenyh;\r
1962         unsigned        pos,xtl,ytl,xth,yth,x,y;\r
1963         byte            *updatespot;\r
1964         unsigned        updatedelta;\r
1965         unsigned        erasecount;\r
1966 \r
1967 #ifdef PROFILE\r
1968         erasecount = 0;\r
1969 #endif\r
1970 \r
1971         block = otherpage ? &eraselist[1][0] : &eraselist[0][0];\r
1972 \r
1973         done = eraselistptr[otherpage];\r
1974 \r
1975         while (block != done)\r
1976         {\r
1977 \r
1978         //\r
1979         // clip the block to the current screen view\r
1980         //\r
1981                 block->screenx -= originxscreen;\r
1982                 block->screeny -= originyscreen;\r
1983 \r
1984                 if (block->screenx < 0)\r
1985                 {\r
1986                         block->width += block->screenx;\r
1987                         if (block->width<1)\r
1988                                 goto next;\r
1989                         block->screenx = 0;\r
1990                 }\r
1991 \r
1992                 if (block->screeny < 0)\r
1993                 {\r
1994                         block->height += block->screeny;\r
1995                         if (block->height<1)\r
1996                                 goto next;\r
1997                         block->screeny = 0;\r
1998                 }\r
1999 \r
2000                 screenxh = block->screenx + block->width;\r
2001                 screenyh = block->screeny + block->height;\r
2002 \r
2003                 if (screenxh > EGAPORTSCREENWIDE)\r
2004                 {\r
2005                         block->width = EGAPORTSCREENWIDE-block->screenx;\r
2006                         screenxh = block->screenx + block->width;\r
2007                 }\r
2008 \r
2009                 if (screenyh > PORTSCREENHIGH)\r
2010                 {\r
2011                         block->height = PORTSCREENHIGH-block->screeny;\r
2012                         screenyh = block->screeny + block->height;\r
2013                 }\r
2014 \r
2015                 if (block->width<1 || block->height<1)\r
2016                         goto next;\r
2017 \r
2018         //\r
2019         // erase the block by copying from the master screen\r
2020         //\r
2021                 pos = gvar->video.ofs.ylookup[block->screeny]+block->screenx;\r
2022 //++++          VW_ScreenToScreen (masterofs+pos,bufferofs+pos,\r
2023                         block->width,block->height);\r
2024 \r
2025         //\r
2026         // put 2s in update where the block was, to force sprites to update\r
2027         //\r
2028                 xtl = block->screenx >> SX_T_SHIFT;\r
2029                 xth = (block->screenx+block->width-1) >> SX_T_SHIFT;\r
2030                 ytl = block->screeny >> SY_T_SHIFT;\r
2031                 yth = (block->screeny+block->height-1) >> SY_T_SHIFT;\r
2032 \r
2033                 updatespot = updateptr + uwidthtable[ytl] + xtl;\r
2034                 updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2035 \r
2036                 for (y=ytl;y<=yth;y++)\r
2037                 {\r
2038                         for (x=xtl;x<=xth;x++)\r
2039                                 *updatespot++ = 2;\r
2040                         updatespot += updatedelta;              // down to next line\r
2041                 }\r
2042 #ifdef PROFILE\r
2043                 erasecount++;\r
2044 #endif\r
2045 \r
2046 next:\r
2047                 block++;\r
2048         }\r
2049         eraselistptr[otherpage] = otherpage ? &eraselist[1][0] : &eraselist[0][0];\r
2050 #ifdef PROFILE\r
2051         strcpy (scratch,"\tErase:");\r
2052         itoa (erasecount,str,10);\r
2053         strcat (scratch,str);\r
2054         write (profilehandle,scratch,strlen(scratch));\r
2055 #endif\r
2056 \r
2057 }\r
2058 \r
2059 \r
2060 /*\r
2061 ====================\r
2062 =\r
2063 = RFL_UpdateSprites EGA\r
2064 =\r
2065 = NOTE: Implement vertical clipping!\r
2066 =\r
2067 ====================\r
2068 */\r
2069 \r
2070 void RFL_UpdateSprites (void)\r
2071 {\r
2072         spritelisttype  *sprite;\r
2073         int     portx,porty,x,y,xtl,xth,ytl,yth;\r
2074         int     priority;\r
2075         unsigned dest;\r
2076         byte            *updatespot,*baseupdatespot;\r
2077         unsigned        updatedelta;\r
2078         unsigned        updatecount;\r
2079         unsigned        height,sourceofs;\r
2080 \r
2081 #ifdef PROFILE\r
2082         updatecount = 0;\r
2083 #endif\r
2084 \r
2085         for (priority=0;priority<PRIORITIES;priority++)\r
2086         {\r
2087                 if (priority==MASKEDTILEPRIORITY)\r
2088                         RFL_MaskForegroundTiles ();\r
2089 \r
2090                 for (sprite = prioritystart[priority]; sprite ;\r
2091                         sprite = (spritelisttype *)sprite->nextsprite)\r
2092                 {\r
2093                 //\r
2094                 // see if the sprite has any visable area in the port\r
2095                 //\r
2096 \r
2097                         portx = sprite->screenx - originxscreen;\r
2098                         porty = sprite->screeny - originyscreen;\r
2099                         xtl = portx >> SX_T_SHIFT;\r
2100                         xth = (portx + sprite->width-1) >> SX_T_SHIFT;\r
2101                         ytl = porty >> SY_T_SHIFT;\r
2102                         yth = (porty + sprite->height-1) >> SY_T_SHIFT;\r
2103 \r
2104                         if (xtl<0)\r
2105                           xtl = 0;\r
2106                         if (xth>=PORTTILESWIDE)\r
2107                           xth = PORTTILESWIDE-1;\r
2108                         if (ytl<0)\r
2109                           ytl = 0;\r
2110                         if (yth>=PORTTILESHIGH)\r
2111                           yth = PORTTILESHIGH-1;\r
2112 \r
2113                         if (xtl>xth || ytl>yth)\r
2114                                 continue;\r
2115 \r
2116                 //\r
2117                 // see if it's visable area covers any non 0 update tiles\r
2118                 //\r
2119                         updatespot = baseupdatespot = updateptr + uwidthtable[ytl] + xtl;\r
2120                         updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2121 \r
2122                         if (sprite->updatecount)\r
2123                         {\r
2124                                 sprite->updatecount--;                  // the sprite was just placed,\r
2125                                 goto redraw;                                    // so draw it for sure\r
2126                         }\r
2127 \r
2128                         for (y=ytl;y<=yth;y++)\r
2129                         {\r
2130                                 for (x=xtl;x<=xth;x++)\r
2131                                         if (*updatespot++)\r
2132                                                 goto redraw;\r
2133                                 updatespot += updatedelta;              // down to next line\r
2134                         }\r
2135                         continue;                                                       // no need to update\r
2136 \r
2137 redraw:\r
2138                 //\r
2139                 // set the tiles it covers to 3, because those tiles are being\r
2140                 // updated\r
2141                 //\r
2142                         updatespot = baseupdatespot;\r
2143                         for (y=ytl;y<=yth;y++)\r
2144                         {\r
2145                                 for (x=xtl;x<=xth;x++)\r
2146                                         *updatespot++ = 3;\r
2147                                 updatespot += updatedelta;              // down to next line\r
2148                         }\r
2149                 //\r
2150                 // draw it!\r
2151                 //\r
2152                         height = sprite->height;\r
2153                         sourceofs = sprite->sourceofs;\r
2154                         if (porty<0)\r
2155                         {\r
2156                                 height += porty;                                        // clip top off\r
2157                                 sourceofs -= porty*sprite->width;\r
2158                                 porty = 0;\r
2159                         }\r
2160                         else if (porty+height>PORTSCREENHIGH)\r
2161                         {\r
2162                                 height = PORTSCREENHIGH - porty;    // clip bottom off\r
2163                         }\r
2164 \r
2165                         dest = bufferofs + gvar->video.ofs.ylookup[porty] + portx;\r
2166 \r
2167                         switch (sprite->draw)\r
2168                         {\r
2169                         case spritedraw:\r
2170 //++++                          VW_MaskBlock(grsegs[sprite->grseg], sourceofs,\r
2171                                         dest,sprite->width,height,sprite->planesize);\r
2172                                 break;\r
2173 \r
2174                         case maskdraw:\r
2175                                 break;\r
2176 \r
2177                         }\r
2178 #ifdef PROFILE\r
2179                         updatecount++;\r
2180 #endif\r
2181 \r
2182 \r
2183                 }\r
2184         }\r
2185 #ifdef PROFILE\r
2186         strcpy (scratch,"\tSprites:");\r
2187         itoa (updatecount,str,10);\r
2188         strcat (scratch,str);\r
2189         write (profilehandle,scratch,strlen(scratch));\r
2190 #endif\r
2191 \r
2192 }\r
2193 \r
2194 \r
2195 /*\r
2196 =====================\r
2197 =\r
2198 = RF_Refresh   EGA\r
2199 =\r
2200 = All routines will draw at the port at bufferofs, possibly copying from\r
2201 = the port at masterofs.  The EGA version then page flips, while the\r
2202 = CGA version updates the screen from the buffer port.\r
2203 =\r
2204 = Screenpage is the currently displayed page, not the one being drawn\r
2205 = Otherpage is the page to be worked with now\r
2206 =\r
2207 =====================\r
2208 */\r
2209 \r
2210 void RF_Refresh (void)\r
2211 {\r
2212         byte    *newupdate;\r
2213 \r
2214         updateptr = updatestart[otherpage];\r
2215 \r
2216         RFL_AnimateTiles ();            // DEBUG\r
2217 \r
2218 //\r
2219 // update newly scrolled on tiles and animated tiles from the master screen\r
2220 //\r
2221         EGAWRITEMODE(1);\r
2222         EGAMAPMASK(15);\r
2223         RFL_UpdateTiles ();\r
2224         RFL_EraseBlocks ();\r
2225 \r
2226 //\r
2227 // Update is all 0 except where sprites have changed or new area has\r
2228 // been scrolled on.  Go through all sprites and update the ones that cover\r
2229 // a non 0 update tile\r
2230 //\r
2231         EGAWRITEMODE(0);\r
2232         RFL_UpdateSprites ();\r
2233 \r
2234 //\r
2235 // if the main program has a refresh hook set, call their function before\r
2236 // displaying the new page\r
2237 //\r
2238         if (refreshvector)\r
2239                 refreshvector();\r
2240 \r
2241 //\r
2242 // display the changed screen\r
2243 //\r
2244         VL_SetScreen(bufferofs+gvar->video.ofs.pan.panadjust,gvar->video.ofs.pan.panx & xpanmask);\r
2245 \r
2246 //\r
2247 // prepare for next refresh\r
2248 //\r
2249 // Set the update array to the middle position and clear it out to all "0"s\r
2250 // with an UPDATETERMINATE at the end\r
2251 //\r
2252         updatestart[otherpage] = newupdate = baseupdatestart[otherpage];\r
2253 asm     mov     ax,ds\r
2254 asm     mov     es,ax\r
2255 asm     xor     ax,ax\r
2256 asm     mov     cx,(UPDATESCREENSIZE-2)/2\r
2257 asm     mov     di,[newupdate]\r
2258 asm     rep     stosw\r
2259 asm     mov     [WORD PTR es:di],UPDATETERMINATE\r
2260 \r
2261         screenpage ^= 1;\r
2262         otherpage ^= 1;\r
2263         bufferofs = screenstart[otherpage];\r
2264         displayofs = screenstart[screenpage];\r
2265 \r
2266 //\r
2267 // calculate tics since last refresh for adaptive timing\r
2268 //\r
2269         RF_CalcTics ();\r
2270 }\r
2271 \r
2272 #endif          // GRMODE == EGAGR\r
2273 \r
2274 /*\r
2275 =============================================================================\r
2276 \r
2277                                         CGA specific routines\r
2278 \r
2279 =============================================================================\r
2280 */\r
2281 \r
2282 #if GRMODE == CGAGR\r
2283 \r
2284 \r
2285 /*\r
2286 =====================\r
2287 =\r
2288 = RF_NewPosition   CGA\r
2289 =\r
2290 =====================\r
2291 */\r
2292 \r
2293 void RF_NewPosition (unsigned x, unsigned y)\r
2294 {\r
2295         int mx,my;\r
2296         byte    *spotptr;\r
2297         unsigned        updatenum;\r
2298 \r
2299         RFL_BoundNewOrigin (x,y);\r
2300 \r
2301 // calculate new origin related globals\r
2302 //\r
2303         RFL_CalcOriginStuff (x,y);\r
2304 \r
2305 //\r
2306 // clear out all animating tiles\r
2307 //\r
2308         RFL_InitAnimList ();\r
2309 \r
2310 //\r
2311 // set up the new update arrays at base position\r
2312 //\r
2313         updateptr = baseupdateptr;\r
2314 \r
2315         spotptr = updateptr + PORTTILESWIDE;    // used to stick "0"s after rows\r
2316 \r
2317         updatenum = 0;                          // start at first visable tile\r
2318 \r
2319         for (my=0;my<PORTTILESHIGH;my++)\r
2320         {\r
2321                 for (mx=0;mx<PORTTILESWIDE;mx++)\r
2322                 {\r
2323                         RFL_NewTile(updatenum);                 // puts "1"s in both pages\r
2324                         RFL_CheckForAnimTile(mx+originxtile,my+originytile);\r
2325                         updatenum++;\r
2326                 }\r
2327                 updatenum++;\r
2328                 *spotptr = 0; // set a 0 at end of a line of tiles\r
2329                 spotptr +=(PORTTILESWIDE+1);\r
2330         }\r
2331         *(word *)(spotptr-PORTTILESWIDE) = UPDATETERMINATE;\r
2332 }\r
2333 \r
2334 \r
2335 /*\r
2336 =====================\r
2337 =\r
2338 = RF_Scroll       CGA\r
2339 =\r
2340 = Move the origin x/y global coordinates, readjust the screen panning, and\r
2341 = scroll if needed.  If the scroll distance is greater than one tile, the\r
2342 = entire screen will be redrawn (this could be generalized, but scrolling\r
2343 = more than one tile per refresh is a bad idea!).\r
2344 =\r
2345 =====================\r
2346 */\r
2347 \r
2348 void RF_Scroll (int x, int y)\r
2349 {\r
2350         long            neworgx,neworgy;\r
2351         int                     i,deltax,deltay,absdx,absdy;\r
2352         int                     oldxt,oldyt,move,yy;\r
2353         unsigned        updatespot;\r
2354         byte            *spotptr;\r
2355         unsigned        oldoriginmap,oldscreen,newscreen,screencopy;\r
2356         int                     screenmove;\r
2357 \r
2358         oldxt = originxtile;\r
2359         oldyt = originytile;\r
2360 \r
2361         RFL_CalcOriginStuff ((long)originxglobal + x,(long)originyglobal + y);\r
2362 \r
2363         deltax = originxtile - oldxt;\r
2364         absdx = abs(deltax);\r
2365         deltay = originytile - oldyt;\r
2366         absdy = abs(deltay);\r
2367 \r
2368         if (absdx>1 || absdy>1)\r
2369         {\r
2370         //\r
2371         // scrolled more than one tile, so start from scratch\r
2372         //\r
2373                 RF_NewPosition(originxglobal,originyglobal);\r
2374                 return;\r
2375         }\r
2376 \r
2377         if (!absdx && !absdy)\r
2378                 return;                                 // the screen has not scrolled an entire tile\r
2379 \r
2380 \r
2381 //\r
2382 // float screens\r
2383 //\r
2384         screenmove = deltay*16*SCREENWIDTH + deltax*TILEWIDTH;\r
2385         bufferofs += screenmove;\r
2386         masterofs += screenmove;\r
2387 \r
2388 \r
2389 //\r
2390 // float the update regions\r
2391 //\r
2392         move = deltax;\r
2393         if (deltay==1)\r
2394           move += UPDATEWIDE;\r
2395         else if (deltay==-1)\r
2396           move -= UPDATEWIDE;\r
2397 \r
2398         updateptr+=move;\r
2399 \r
2400 //\r
2401 // draw the new tiles just scrolled on to the master screen, and\r
2402 // mark them as needing to be copied to each screen next refreshes\r
2403 // Make sure a zero is at the end of each row in update\r
2404 //\r
2405 \r
2406         if (deltax)\r
2407         {\r
2408                 if (deltax==1)\r
2409                 {\r
2410                         RFL_NewRow (1);                 // new right row\r
2411                         RFL_RemoveAnimsOnX (originxtile-1);\r
2412                 }\r
2413                 else\r
2414                 {\r
2415                         RFL_NewRow (3);                 // new left row\r
2416                         RFL_RemoveAnimsOnX (originxtile+PORTTILESWIDE);\r
2417                 }\r
2418 \r
2419                 spotptr = updateptr+PORTTILESWIDE;\r
2420                 for     (yy=0;yy<PORTTILESHIGH;yy++)\r
2421                 {\r
2422                         *spotptr = 0;           // drop a 0 at end of each row\r
2423                         spotptr+=UPDATEWIDE;\r
2424                 }\r
2425         }\r
2426 \r
2427 //----------------\r
2428 \r
2429         if (deltay)\r
2430         {\r
2431                 if (deltay==1)\r
2432                 {\r
2433                         RFL_NewRow (2);                 // new bottom row\r
2434                         *(updateptr+UPDATEWIDE*(PORTTILESHIGH-1)+PORTTILESWIDE) = 0;\r
2435                         RFL_RemoveAnimsOnY (originytile-1);\r
2436                 }\r
2437                 else\r
2438                 {\r
2439                         RFL_NewRow (0);                 // new top row\r
2440                         *(updateptr+PORTTILESWIDE) = 0;\r
2441                         RFL_RemoveAnimsOnY (originytile+PORTTILESHIGH);\r
2442                 }\r
2443         }\r
2444 \r
2445 //----------------\r
2446 \r
2447         //\r
2448         // place a new terminator\r
2449         //\r
2450         spotptr = updateptr+UPDATEWIDE*PORTTILESHIGH-1;\r
2451         *spotptr++ = 0;\r
2452         *(unsigned *)spotptr = UPDATETERMINATE;\r
2453 }\r
2454 \r
2455 /*\r
2456 =====================\r
2457 =\r
2458 = RF_PlaceSprite  CGA\r
2459 =\r
2460 =====================\r
2461 */\r
2462 \r
2463 void RF_PlaceSprite (void **user,unsigned globalx,unsigned globaly,\r
2464         unsigned spritenumber, drawtype draw, int priority)\r
2465 {\r
2466         spritelisttype  register *sprite,*next;\r
2467         spritetabletype far *spr;\r
2468         spritetype _seg *block;\r
2469         unsigned        shift,pixx;\r
2470         char            str[80],str2[10];\r
2471 \r
2472         if (!spritenumber || spritenumber == (unsigned)-1)\r
2473         {\r
2474                 RF_RemoveSprite (user);\r
2475                 return;\r
2476         }\r
2477 \r
2478         sprite = (spritelisttype *)*user;\r
2479 \r
2480         if      (sprite)\r
2481         {\r
2482         // sprite allready exists in the list, so we can use it's block\r
2483 \r
2484         //\r
2485         // post an erase block to erase the old position by copying\r
2486         // screenx,screeny,width,height\r
2487         //\r
2488                 if (!sprite->updatecount)               // may not have been drawn at all yet\r
2489                         memcpy (eraselistptr[0]++,sprite,sizeof(eraseblocktype));\r
2490 \r
2491                 if (priority != sprite->priority)\r
2492                 {\r
2493                 // sprite moved to another priority, so unlink the old one and\r
2494                 // relink it in the new priority\r
2495 \r
2496                         next = sprite->nextsprite;                      // cut old links\r
2497                         if (next)\r
2498                                 next->prevptr = sprite->prevptr;\r
2499                         *sprite->prevptr = next;\r
2500                         goto linknewspot;\r
2501                 }\r
2502         }\r
2503         else\r
2504         {\r
2505         // this is a brand new sprite, so allocate a block from the array\r
2506 \r
2507                 if (!spritefreeptr)\r
2508                         Quit (gvar, "RF_PlaceSprite: No free spots in spritearray!");\r
2509 \r
2510                 sprite = spritefreeptr;\r
2511                 spritefreeptr = spritefreeptr->nextsprite;\r
2512 \r
2513 linknewspot:\r
2514                 next = prioritystart[priority];         // stick it in new spot\r
2515                 if (next)\r
2516                         next->prevptr = &sprite->nextsprite;\r
2517                 sprite->nextsprite = next;\r
2518                 prioritystart[priority] = sprite;\r
2519                 sprite->prevptr = &prioritystart[priority];\r
2520         }\r
2521 \r
2522 //\r
2523 // write the new info to the sprite\r
2524 //\r
2525         spr = &spritetable[spritenumber-STARTSPRITES];\r
2526         block = (spritetype _seg *)grsegs[spritenumber];\r
2527 \r
2528         if (!block)\r
2529         {\r
2530                 strcpy (str,"RF_PlaceSprite: Placed an uncached sprite!");\r
2531                 itoa (spritenumber,str2,10);\r
2532                 strcat (str,str2);\r
2533                 Quit (str);\r
2534         }\r
2535 \r
2536 \r
2537         globaly+=spr->orgy;\r
2538         globalx+=spr->orgx;\r
2539 \r
2540         sprite->screenx = globalx >> G_CGASX_SHIFT;\r
2541         sprite->screeny = globaly >> G_SY_SHIFT;\r
2542         sprite->width = block->width[0];\r
2543         sprite->height = spr->height;\r
2544         sprite->grseg = spritenumber;\r
2545         sprite->sourceofs = block->sourceoffset[0];\r
2546         sprite->planesize = block->planesize[0];\r
2547         sprite->draw = draw;\r
2548         sprite->priority = priority;\r
2549         sprite->tilex = sprite->screenx >> SX_T_SHIFT;\r
2550         sprite->tiley = sprite->screeny >> SY_T_SHIFT;\r
2551         sprite->tilewide = ( (sprite->screenx + sprite->width -1) >> SX_T_SHIFT )\r
2552                 - sprite->tilex + 1;\r
2553         sprite->tilehigh = ( (sprite->screeny + sprite->height -1) >> SY_T_SHIFT )\r
2554                 - sprite->tiley + 1;\r
2555 \r
2556         sprite->updatecount = 1;                // draw on next refresh\r
2557 \r
2558 // save the sprite pointer off in the user's pointer so it can be moved\r
2559 // again later\r
2560 \r
2561         *user = sprite;\r
2562 }\r
2563 \r
2564 //===========================================================================\r
2565 \r
2566 /*\r
2567 =====================\r
2568 =\r
2569 = RF_RemoveSprite CGA\r
2570 =\r
2571 =====================\r
2572 */\r
2573 \r
2574 void RF_RemoveSprite (void **user)\r
2575 {\r
2576         spritelisttype  *sprite,*next;\r
2577 \r
2578         sprite = (spritelisttype *)*user;\r
2579         if (!sprite)\r
2580                 return;\r
2581 \r
2582 //\r
2583 // post an erase block to erase the old position by copying\r
2584 // screenx,screeny,width,height\r
2585 //\r
2586         if (!sprite->updatecount)\r
2587         {\r
2588                 memcpy (eraselistptr[0]++,sprite,sizeof(eraseblocktype));\r
2589         }\r
2590 \r
2591 //\r
2592 // unlink the sprite node\r
2593 //\r
2594         next = sprite->nextsprite;\r
2595         if (next)                                               // if (!next), sprite is last in chain\r
2596                 next->prevptr = sprite->prevptr;\r
2597         *sprite->prevptr = next;\r
2598 \r
2599 //\r
2600 // add it back to the free list\r
2601 //\r
2602         sprite->nextsprite = spritefreeptr;\r
2603         spritefreeptr = sprite;\r
2604 \r
2605 //\r
2606 // null the users pointer, so next time that actor gets placed, it will\r
2607 // allocate a new block\r
2608 //\r
2609 \r
2610         *user = 0;\r
2611 }\r
2612 \r
2613 \r
2614 /*\r
2615 ====================\r
2616 =\r
2617 = RFL_EraseBlocks CGA\r
2618 =\r
2619 = Write mode 1 should be set\r
2620 =\r
2621 ====================\r
2622 */\r
2623 \r
2624 void RFL_EraseBlocks (void)\r
2625 {\r
2626         eraseblocktype  *block,*done;\r
2627         int                     screenxh,screenyh;\r
2628         unsigned        pos,xtl,ytl,xth,yth,x,y;\r
2629         byte            *updatespot;\r
2630         unsigned        updatedelta;\r
2631 \r
2632         block = &eraselist[0][0];\r
2633 \r
2634         done = eraselistptr[0];\r
2635 \r
2636         while (block != done)\r
2637         {\r
2638 \r
2639         //\r
2640         // clip the block to the current screen view\r
2641         //\r
2642                 block->screenx -= originxscreen;\r
2643                 block->screeny -= originyscreen;\r
2644 \r
2645                 if (block->screenx < 0)\r
2646                 {\r
2647                         block->width += block->screenx;\r
2648                         if (block->width<1)\r
2649                                 goto next;\r
2650                         block->screenx = 0;\r
2651                 }\r
2652 \r
2653                 if (block->screeny < 0)\r
2654                 {\r
2655                         block->height += block->screeny;\r
2656                         if (block->height<1)\r
2657                                 goto next;\r
2658                         block->screeny = 0;\r
2659                 }\r
2660 \r
2661                 screenxh = block->screenx + block->width;\r
2662                 screenyh = block->screeny + block->height;\r
2663 \r
2664                 if (screenxh > CGAPORTSCREENWIDE)\r
2665                 {\r
2666                         block->width = CGAPORTSCREENWIDE-block->screenx;\r
2667                         screenxh = block->screenx + block->width;\r
2668                 }\r
2669 \r
2670                 if (screenyh > PORTSCREENHIGH)\r
2671                 {\r
2672                         block->height = PORTSCREENHIGH-block->screeny;\r
2673                         screenyh = block->screeny + block->height;\r
2674                 }\r
2675 \r
2676                 if (block->width<1 || block->height<1)\r
2677                         goto next;\r
2678 \r
2679         //\r
2680         // erase the block by copying from the master screen\r
2681         //\r
2682 //----          pos = gvar->video.ofs.ylookup[block->screeny]+block->screenx;\r
2683                 pos = (block->screeny*gvar->video.page[0].stridew)+block->screenx;\r
2684                 block->width = (block->width + (pos&1) + 1)& ~1;\r
2685                 pos &= ~1;                              // make sure a word copy gets used\r
2686 //++++          VW_ScreenToScreen (masterofs+pos,bufferofs+pos,\r
2687                         block->width,block->height);\r
2688 \r
2689         //\r
2690         // put 2s in update where the block was, to force sprites to update\r
2691         //\r
2692                 xtl = block->screenx >> SX_T_SHIFT;\r
2693                 xth = (block->screenx+block->width-1) >> SX_T_SHIFT;\r
2694                 ytl = block->screeny >> SY_T_SHIFT;\r
2695                 yth = (block->screeny+block->height-1) >> SY_T_SHIFT;\r
2696 \r
2697                 updatespot = updateptr + uwidthtable[ytl] + xtl;\r
2698                 updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2699 \r
2700                 for (y=ytl;y<=yth;y++)\r
2701                 {\r
2702                         for (x=xtl;x<=xth;x++)\r
2703                                 *updatespot++ = 2;\r
2704                         updatespot += updatedelta;              // down to next line\r
2705                 }\r
2706 \r
2707 next:\r
2708                 block++;\r
2709         }\r
2710         eraselistptr[0] = &eraselist[0][0];\r
2711 }\r
2712 \r
2713 \r
2714 /*\r
2715 ====================\r
2716 =\r
2717 = RFL_UpdateSprites      CGA\r
2718 =\r
2719 = NOTE: Implement vertical clipping!\r
2720 =\r
2721 ====================\r
2722 */\r
2723 \r
2724 void RFL_UpdateSprites (void)\r
2725 {\r
2726         spritelisttype  *sprite;\r
2727         int     portx,porty,x,y,xtl,xth,ytl,yth;\r
2728         int     priority;\r
2729         unsigned dest;\r
2730         byte            *updatespot,*baseupdatespot;\r
2731         unsigned        updatedelta;\r
2732 \r
2733         unsigned        updatecount;\r
2734         unsigned        height,sourceofs;\r
2735 \r
2736 #ifdef PROFILE\r
2737         updatecount = 0;\r
2738 #endif\r
2739 \r
2740 \r
2741         for (priority=0;priority<PRIORITIES;priority++)\r
2742         {\r
2743                 if (priority==MASKEDTILEPRIORITY)\r
2744                         RFL_MaskForegroundTiles ();\r
2745 \r
2746                 for (sprite = prioritystart[priority]; sprite ;\r
2747                         sprite = (spritelisttype *)sprite->nextsprite)\r
2748                 {\r
2749                 //\r
2750                 // see if the sprite has any visable area in the port\r
2751                 //\r
2752 \r
2753                         portx = sprite->screenx - originxscreen;\r
2754                         porty = sprite->screeny - originyscreen;\r
2755                         xtl = portx >> SX_T_SHIFT;\r
2756                         xth = (portx + sprite->width-1) >> SX_T_SHIFT;\r
2757                         ytl = porty >> SY_T_SHIFT;\r
2758                         yth = (porty + sprite->height-1) >> SY_T_SHIFT;\r
2759 \r
2760                         if (xtl<0)\r
2761                           xtl = 0;\r
2762                         if (xth>=PORTTILESWIDE)\r
2763                           xth = PORTTILESWIDE-1;\r
2764                         if (ytl<0)\r
2765                           ytl = 0;\r
2766                         if (yth>=PORTTILESHIGH)\r
2767                           yth = PORTTILESHIGH-1;\r
2768 \r
2769                         if (xtl>xth || ytl>yth)\r
2770                                 continue;\r
2771 \r
2772                 //\r
2773                 // see if it's visable area covers any non 0 update tiles\r
2774                 //\r
2775                         updatespot = baseupdatespot = updateptr + uwidthtable[ytl] + xtl;\r
2776                         updatedelta = UPDATEWIDE - (xth-xtl+1);\r
2777 \r
2778                         if (sprite->updatecount)\r
2779                         {\r
2780                                 sprite->updatecount--;                  // the sprite was just placed,\r
2781                                 goto redraw;                                    // so draw it for sure\r
2782                         }\r
2783 \r
2784                         for (y=ytl;y<=yth;y++)\r
2785                         {\r
2786                                 for (x=xtl;x<=xth;x++)\r
2787                                         if (*updatespot++)\r
2788                                                 goto redraw;\r
2789                                 updatespot += updatedelta;              // down to next line\r
2790                         }\r
2791                         continue;                                                       // no need to update\r
2792 \r
2793 redraw:\r
2794                 //\r
2795                 // set the tiles it covers to 3, because those tiles are being\r
2796                 // updated\r
2797                 //\r
2798                         updatespot = baseupdatespot;\r
2799                         for (y=ytl;y<=yth;y++)\r
2800                         {\r
2801                                 for (x=xtl;x<=xth;x++)\r
2802                                         *updatespot++ = 3;\r
2803                                 updatespot += updatedelta;              // down to next line\r
2804                         }\r
2805                 //\r
2806                 // draw it!\r
2807                 //\r
2808                         height = sprite->height;\r
2809                         sourceofs = sprite->sourceofs;\r
2810                         if (porty<0)\r
2811                         {\r
2812                                 height += porty;                                        // clip top off\r
2813                                 sourceofs -= porty*sprite->width;\r
2814                                 porty = 0;\r
2815                         }\r
2816                         else if (porty+height>PORTSCREENHIGH)\r
2817                         {\r
2818                                 height = PORTSCREENHIGH - porty;    // clip bottom off\r
2819                         }\r
2820 \r
2821                         dest = bufferofs + gvar->video.ofs.ylookup[porty] + portx;\r
2822 \r
2823                         switch (sprite->draw)\r
2824                         {\r
2825                         case spritedraw:\r
2826                                 VW_MaskBlock(grsegs[sprite->grseg], sourceofs,\r
2827                                         dest,sprite->width,height,sprite->planesize);\r
2828                                 break;\r
2829 \r
2830                         case maskdraw:\r
2831                                 break;\r
2832 \r
2833                         }\r
2834 #ifdef PROFILE\r
2835                         updatecount++;\r
2836 #endif\r
2837 \r
2838 \r
2839                 }\r
2840         }\r
2841 }\r
2842 \r
2843 \r
2844 /*\r
2845 =====================\r
2846 =\r
2847 = RF_Refresh        CGA\r
2848 =\r
2849 = All routines will draw at the port at bufferofs, possibly copying from\r
2850 = the port at masterofs.  The EGA version then page flips, while the\r
2851 = CGA version updates the screen from the buffer port.\r
2852 =\r
2853 = Screenpage is the currently displayed page, not the one being drawn\r
2854 = Otherpage is the page to be worked with now\r
2855 =\r
2856 =====================\r
2857 */\r
2858 \r
2859 void RF_Refresh (void)\r
2860 {\r
2861         long newtime;\r
2862 \r
2863         RFL_AnimateTiles ();\r
2864 \r
2865 //\r
2866 // update newly scrolled on tiles and animated tiles from the master screen\r
2867 //\r
2868         RFL_UpdateTiles ();\r
2869         RFL_EraseBlocks ();\r
2870 \r
2871 //\r
2872 // Update is all 0 except where sprites have changed or new area has\r
2873 // been scrolled on.  Go through all sprites and update the ones that cover\r
2874 // a non 0 update tile\r
2875 //\r
2876         RFL_UpdateSprites ();\r
2877 \r
2878 //\r
2879 // if the main program has a refresh hook set, call their function before\r
2880 // displaying the new page\r
2881 //\r
2882         if (refreshvector)\r
2883                 refreshvector();\r
2884 \r
2885 //\r
2886 // update everything to the screen\r
2887 //\r
2888         VW_CGAFullUpdate ();\r
2889 \r
2890 //\r
2891 // calculate tics since last refresh for adaptive timing\r
2892 //\r
2893         RF_CalcTics ();\r
2894 }\r
2895 \r
2896 #endif          // GRMODE == CGAGR\r
2897 //===============================\r
2898 /*\r
2899 ; Keen Dreams Source Code\r
2900 ; Copyright (C) 2014 Javier M. Chavez\r
2901 ;\r
2902 ; This program is free software; you can redistribute it and/or modify\r
2903 ; it under the terms of the GNU General Public License as published by\r
2904 ; the Free Software Foundation; either version 2 of the License, or\r
2905 ; (at your option) any later version.\r
2906 ;\r
2907 ; This program is distributed in the hope that it will be useful,\r
2908 ; but WITHOUT ANY WARRANTY; without even the implied warranty of\r
2909 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
2910 ; GNU General Public License for more details.\r
2911 ;\r
2912 ; You should have received a copy of the GNU General Public License along\r
2913 ; with this program; if not, write to the Free Software Foundation, Inc.,\r
2914 ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
2915 \r
2916 ; ID_RF_A.ASM\r
2917 \r
2918 IDEAL\r
2919 MODEL   MEDIUM,C\r
2920 \r
2921 INCLUDE "ID_ASM.EQU"\r
2922 \r
2923 CACHETILES      = 1             ;enable master screen tile caching\r
2924 \r
2925 ;============================================================================\r
2926 \r
2927 TILESWIDE       =       21\r
2928 TILESHIGH       =       14\r
2929 \r
2930 UPDATESIZE      =       (TILESWIDE+1)*TILESHIGH+1\r
2931 \r
2932 DATASEG\r
2933 \r
2934 EXTRN   screenseg:WORD\r
2935 EXTRN   updateptr:WORD\r
2936 EXTRN   updatestart:WORD\r
2937 EXTRN   masterofs:WORD          ;start of master tile port\r
2938 EXTRN   bufferofs:WORD          ;start of current buffer port\r
2939 EXTRN   screenstart:WORD        ;starts of three screens (0/1/master) in EGA mem\r
2940 EXTRN   grsegs:WORD\r
2941 EXTRN   mapsegs:WORD\r
2942 EXTRN   originmap:WORD\r
2943 EXTRN   updatemapofs:WORD\r
2944 EXTRN   tilecache:WORD\r
2945 EXTRN   tinf:WORD                       ;seg pointer to map header and tile info\r
2946 EXTRN   blockstarts:WORD        ;offsets from bufferofs for each update block\r
2947 \r
2948 planemask       db      ?\r
2949 planenum        db      ?\r
2950 \r
2951 CODESEG\r
2952 \r
2953 screenstartcs   dw      ?               ;in code segment for accesability\r
2954 \r
2955 \r
2956 \r
2957 \r
2958 IFE GRMODE-CGAGR\r
2959 ;============================================================================\r
2960 ;\r
2961 ; CGA refresh routines\r
2962 ;\r
2963 ;============================================================================\r
2964 \r
2965 TILEWIDTH       =       4\r
2966 \r
2967 ;=================\r
2968 ;\r
2969 ; RFL_NewTile\r
2970 ;\r
2971 ; Draws a composit two plane tile to the master screen and sets the update\r
2972 ; spot to 1 in both update pages, forcing the tile to be copied to the\r
2973 ; view pages the next two refreshes\r
2974 ;\r
2975 ; Called to draw newlly scrolled on strips and animating tiles\r
2976 ;\r
2977 ;=================\r
2978 \r
2979 PROC    RFL_NewTile     updateoffset:WORD\r
2980 PUBLIC  RFL_NewTile\r
2981 USES    SI,DI\r
2982 \r
2983 ;\r
2984 ; mark both update lists at this spot\r
2985 ;\r
2986         mov     di,[updateoffset]\r
2987 \r
2988         mov     bx,[updateptr]                  ;start of update matrix\r
2989         mov     [BYTE bx+di],1\r
2990 \r
2991         mov     dx,SCREENWIDTH-TILEWIDTH                ;add to get to start of next line\r
2992 \r
2993 ;\r
2994 ; set di to the location in screenseg to draw the tile\r
2995 ;\r
2996         shl     di,1\r
2997         mov     si,[updatemapofs+di]    ;offset in map from origin\r
2998         add     si,[originmap]\r
2999         mov     di,[blockstarts+di]             ;screen location for tile\r
3000         add     di,[masterofs]\r
3001 \r
3002 ;\r
3003 ; set BX to the foreground tile number and SI to the background number\r
3004 ; If either BX or SI = 0xFFFF, the tile does not need to be masked together\r
3005 ; as one of the planes totally eclipses the other\r
3006 ;\r
3007         mov     es,[mapsegs+2]                  ;foreground plane\r
3008         mov     bx,[es:si]\r
3009         mov     es,[mapsegs]                    ;background plane\r
3010         mov     si,[es:si]\r
3011 \r
3012         mov     es,[screenseg]\r
3013 \r
3014         or      bx,bx\r
3015         jz      @@singletile\r
3016         jmp     @@maskeddraw                    ;draw both together\r
3017 \r
3018 ;=============\r
3019 ;\r
3020 ; Draw single background tile from main memory\r
3021 ;\r
3022 ;=============\r
3023 \r
3024 @@singletile:\r
3025         shl     si,1\r
3026         mov     ds,[grsegs+STARTTILE16*2+si]\r
3027 \r
3028         xor     si,si                                   ;block is segment aligned\r
3029 \r
3030 REPT    15\r
3031         movsw\r
3032         movsw\r
3033         add     di,dx\r
3034 ENDM\r
3035         movsw\r
3036         movsw\r
3037 \r
3038         mov     ax,ss\r
3039         mov     ds,ax                                   ;restore turbo's data segment\r
3040         ret\r
3041 \r
3042 \r
3043 ;=========\r
3044 ;\r
3045 ; Draw a masked tile combo\r
3046 ; Interupts are disabled and the stack segment is reassigned\r
3047 ;\r
3048 ;=========\r
3049 @@maskeddraw:\r
3050         cli                                                     ; don't allow ints when SS is set\r
3051         shl     bx,1\r
3052         mov     ss,[grsegs+STARTTILE16M*2+bx]\r
3053         shl     si,1\r
3054         mov     ds,[grsegs+STARTTILE16*2+si]\r
3055 \r
3056         xor     si,si                                   ;first word of tile data\r
3057 \r
3058 REPT    16\r
3059         mov     ax,[si]                                 ;background tile\r
3060         and     ax,[ss:si]                              ;mask\r
3061         or      ax,[ss:si+64]                   ;masked data\r
3062         stosw\r
3063         mov     ax,[si+2]                               ;background tile\r
3064         and     ax,[ss:si+2]                    ;mask\r
3065         or      ax,[ss:si+66]                   ;masked data\r
3066         stosw\r
3067         add     si,4\r
3068         add     di,dx\r
3069 ENDM\r
3070 \r
3071         mov     ax,@DATA\r
3072         mov     ss,ax\r
3073         sti\r
3074         mov     ds,ax\r
3075         ret\r
3076 ENDP\r
3077 \r
3078 ENDIF\r
3079 \r
3080 \r
3081 \r
3082 IFE GRMODE-EGAGR\r
3083 ;===========================================================================\r
3084 ;\r
3085 ; EGA refresh routines\r
3086 ;\r
3087 ;===========================================================================\r
3088 \r
3089 TILEWIDTH       =       2\r
3090 \r
3091 ;=================\r
3092 ;\r
3093 ; RFL_NewTile\r
3094 ;\r
3095 ; Draws a composit two plane tile to the master screen and sets the update\r
3096 ; spot to 1 in both update pages, forcing the tile to be copied to the\r
3097 ; view pages the next two refreshes\r
3098 ;\r
3099 ; Called to draw newlly scrolled on strips and animating tiles\r
3100 ;\r
3101 ; Assumes write mode 0\r
3102 ;\r
3103 ;=================\r
3104 \r
3105 PROC    RFL_NewTile     updateoffset:WORD\r
3106 PUBLIC  RFL_NewTile\r
3107 USES    SI,DI\r
3108 \r
3109 ;\r
3110 ; mark both update lists at this spot\r
3111 ;\r
3112         mov     di,[updateoffset]\r
3113 \r
3114         mov     bx,[updatestart]                ;page 0 pointer\r
3115         mov     [BYTE bx+di],1\r
3116         mov     bx,[updatestart+2]              ;page 1 pointer\r
3117         mov     [BYTE bx+di],1\r
3118 \r
3119 ;\r
3120 ; set screenstartcs to the location in screenseg to draw the tile\r
3121 ;\r
3122         shl     di,1\r
3123         mov     si,[updatemapofs+di]    ;offset in map from origin\r
3124         add     si,[originmap]\r
3125         mov     di,[blockstarts+di]             ;screen location for tile\r
3126         add     di,[masterofs]\r
3127         mov     [cs:screenstartcs],di\r
3128 \r
3129 ;\r
3130 ; set BX to the foreground tile number and SI to the background number\r
3131 ; If either BX or SI = 0xFFFF, the tile does not need to be masked together\r
3132 ; as one of the planes totally eclipses the other\r
3133 ;\r
3134         mov     es,[mapsegs+2]                  ;foreground plane\r
3135         mov     bx,[es:si]\r
3136         mov     es,[mapsegs]                    ;background plane\r
3137         mov     si,[es:si]\r
3138 \r
3139         mov     es,[screenseg]\r
3140         mov     dx,SC_INDEX                             ;for stepping through map mask planes\r
3141 \r
3142         or      bx,bx\r
3143         jz      @@singletile\r
3144         jmp     @@maskeddraw                    ;draw both together\r
3145 \r
3146 ;=========\r
3147 ;\r
3148 ; No foreground tile, so draw a single background tile.\r
3149 ; Use the master screen cache if possible\r
3150 ;\r
3151 ;=========\r
3152 @@singletile:\r
3153 \r
3154         mov     bx,SCREENWIDTH-2                ;add to get to start of next line\r
3155         shl     si,1\r
3156 \r
3157 IFE CACHETILES\r
3158         jmp     @@singlemain\r
3159 ENDIF\r
3160 \r
3161         mov     ax,[tilecache+si]\r
3162         or      ax,ax\r
3163         jz      @@singlemain\r
3164 ;=============\r
3165 ;\r
3166 ; Draw single tile from cache\r
3167 ;\r
3168 ;=============\r
3169 \r
3170         mov     si,ax\r
3171 \r
3172         mov     ax,SC_MAPMASK + 15*256  ;all planes\r
3173         WORDOUT\r
3174 \r
3175         mov     dx,GC_INDEX\r
3176         mov     ax,GC_MODE + 1*256              ;write mode 1\r
3177         WORDOUT\r
3178 \r
3179         mov     di,[cs:screenstartcs]\r
3180         mov     ds,[screenseg]\r
3181 \r
3182 REPT    15\r
3183         movsb\r
3184         movsb\r
3185         add     si,bx\r
3186         add     di,bx\r
3187 ENDM\r
3188         movsb\r
3189         movsb\r
3190 \r
3191         xor     ah,ah                                   ;write mode 0\r
3192         WORDOUT\r
3193 \r
3194         mov     ax,ss\r
3195         mov     ds,ax                                   ;restore turbo's data segment\r
3196         ret\r
3197 \r
3198 ;=============\r
3199 ;\r
3200 ; Draw single tile from main memory\r
3201 ;\r
3202 ;=============\r
3203 \r
3204 @@singlemain:\r
3205         mov     ax,[cs:screenstartcs]\r
3206         mov     [tilecache+si],ax               ;next time it can be drawn from here with latch\r
3207         mov     ds,[grsegs+STARTTILE16*2+si]\r
3208 \r
3209         xor     si,si                                   ;block is segment aligned\r
3210 \r
3211         mov     ax,SC_MAPMASK+0001b*256 ;map mask for plane 0\r
3212 \r
3213         mov     cx,4                                    ;draw four planes\r
3214 @@planeloop:\r
3215         mov     dx,SC_INDEX\r
3216         WORDOUT\r
3217 \r
3218         mov     di,[cs:screenstartcs]   ;start at same place in all planes\r
3219 \r
3220 REPT    15\r
3221         movsw\r
3222         add     di,bx\r
3223 ENDM\r
3224         movsw\r
3225 \r
3226         shl     ah,1                                    ;shift plane mask over for next plane\r
3227         loop    @@planeloop\r
3228 \r
3229         mov     ax,ss\r
3230         mov     ds,ax                                   ;restore turbo's data segment\r
3231         ret\r
3232 \r
3233 \r
3234 ;=========\r
3235 ;\r
3236 ; Draw a masked tile combo\r
3237 ; Interupts are disabled and the stack segment is reassigned\r
3238 ;\r
3239 ;=========\r
3240 @@maskeddraw:\r
3241         cli                                                     ; don't allow ints when SS is set\r
3242         shl     bx,1\r
3243         mov     ss,[grsegs+STARTTILE16M*2+bx]\r
3244         shl     si,1\r
3245         mov     ds,[grsegs+STARTTILE16*2+si]\r
3246 \r
3247         xor     si,si                                   ;first word of tile data\r
3248 \r
3249         mov     ax,SC_MAPMASK+0001b*256 ;map mask for plane 0\r
3250 \r
3251         mov     di,[cs:screenstartcs]\r
3252 @@planeloopm:\r
3253         WORDOUT\r
3254 tileofs         =       0\r
3255 lineoffset      =       0\r
3256 REPT    16\r
3257         mov     bx,[si+tileofs]                 ;background tile\r
3258         and     bx,[ss:tileofs]                 ;mask\r
3259         or      bx,[ss:si+tileofs+32]   ;masked data\r
3260         mov     [es:di+lineoffset],bx\r
3261 tileofs         =       tileofs + 2\r
3262 lineoffset      =       lineoffset + SCREENWIDTH\r
3263 ENDM\r
3264         add     si,32\r
3265         shl     ah,1                                    ;shift plane mask over for next plane\r
3266         cmp     ah,10000b\r
3267         je      @@done                                  ;drawn all four planes\r
3268         jmp     @@planeloopm\r
3269 \r
3270 @@done:\r
3271         mov     ax,@DATA\r
3272         mov     ss,ax\r
3273         sti\r
3274         mov     ds,ax\r
3275         ret\r
3276 ENDP\r
3277 \r
3278 ENDIF\r
3279 \r
3280 IFE GRMODE-VGAGR\r
3281 ;============================================================================\r
3282 ;\r
3283 ; VGA refresh routines\r
3284 ;\r
3285 ;============================================================================\r
3286 \r
3287 \r
3288 ENDIF\r
3289 \r
3290 \r
3291 ;============================================================================\r
3292 ;\r
3293 ; reasonably common refresh routines\r
3294 ;\r
3295 ;============================================================================\r
3296 \r
3297 \r
3298 ;=================\r
3299 ;\r
3300 ; RFL_UpdateTiles\r
3301 ;\r
3302 ; Scans through the update matrix pointed to by updateptr, looking for 1s.\r
3303 ; A 1 represents a tile that needs to be copied from the master screen to the\r
3304 ; current screen (a new row or an animated tiled).  If more than one adjacent\r
3305 ; tile in a horizontal row needs to be copied, they will be copied as a group.\r
3306 ;\r
3307 ; Assumes write mode 1\r
3308 ;\r
3309 ;=================\r
3310 \r
3311 \r
3312 ; AX    0/1 for scasb, temp for segment register transfers\r
3313 ; BX    width for block copies\r
3314 ; CX    REP counter\r
3315 ; DX    line width deltas\r
3316 ; SI    source for copies\r
3317 ; DI    scas dest / movsb dest\r
3318 ; BP    pointer to UPDATETERMINATE\r
3319 ;\r
3320 ; DS\r
3321 ; ES\r
3322 ; SS\r
3323 \r
3324 PROC    RFL_UpdateTiles\r
3325 PUBLIC  RFL_UpdateTiles\r
3326 USES    SI,DI,BP\r
3327 \r
3328         jmp     SHORT @@realstart\r
3329 @@done:\r
3330 ;\r
3331 ; all tiles have been scanned\r
3332 ;\r
3333         ret\r
3334 \r
3335 @@realstart:\r
3336         mov     di,[updateptr]\r
3337         mov     bp,(TILESWIDE+1)*TILESHIGH+1\r
3338         add     bp,di                                   ; when di = bx, all tiles have been scanned\r
3339         push    di\r
3340         mov     cx,-1                                   ; definately scan the entire thing\r
3341 \r
3342 ;\r
3343 ; scan for a 1 in the update list, meaning a tile needs to be copied\r
3344 ; from the master screen to the current screen\r
3345 ;\r
3346 @@findtile:\r
3347         pop     di                                              ; place to continue scaning from\r
3348         mov     ax,ss\r
3349         mov     es,ax                                   ; search in the data segment\r
3350         mov     ds,ax\r
3351         mov al,1\r
3352         repne   scasb\r
3353         cmp     di,bp\r
3354         je      @@done\r
3355 \r
3356         cmp     [BYTE di],al\r
3357         jne     @@singletile\r
3358         jmp     @@tileblock\r
3359 \r
3360 ;============\r
3361 ;\r
3362 ; copy a single tile\r
3363 ;\r
3364 ;============\r
3365 EVEN\r
3366 @@singletile:\r
3367         inc     di                                              ; we know the next tile is nothing\r
3368         push    di                                      ; save off the spot being scanned\r
3369         sub     di,[updateptr]\r
3370         shl     di,1\r
3371         mov     di,[blockstarts-4+di]   ; start of tile location on screen\r
3372         mov     si,di\r
3373         add     di,[bufferofs]                  ; dest in current screen\r
3374         add     si,[masterofs]                  ; source in master screen\r
3375 \r
3376         mov     dx,SCREENWIDTH-TILEWIDTH\r
3377         mov     ax,[screenseg]\r
3378         mov     ds,ax\r
3379         mov     es,ax\r
3380 \r
3381 ;--------------------------\r
3382 \r
3383 IFE GRMODE-CGAGR\r
3384 \r
3385 REPT    15\r
3386         movsw\r
3387         movsw\r
3388         add     si,dx\r
3389         add     di,dx\r
3390 ENDM\r
3391         movsw\r
3392         movsw\r
3393 \r
3394 ENDIF\r
3395 \r
3396 ;--------------------------\r
3397 \r
3398 IFE GRMODE-EGAGR\r
3399 \r
3400 REPT    15\r
3401         movsb\r
3402         movsb\r
3403         add     si,dx\r
3404         add     di,dx\r
3405 ENDM\r
3406         movsb\r
3407         movsb\r
3408 \r
3409 ENDIF\r
3410 \r
3411 ;--------------------------\r
3412 \r
3413         jmp     @@findtile\r
3414 \r
3415 ;============\r
3416 ;\r
3417 ; more than one tile in a row needs to be updated, so do it as a group\r
3418 ;\r
3419 ;============\r
3420 EVEN\r
3421 @@tileblock:\r
3422         mov     dx,di                                   ; hold starting position + 1 in dx\r
3423         inc     di                                              ; we know the next tile also gets updated\r
3424         repe    scasb                           ; see how many more in a row\r
3425         push    di                                      ; save off the spot being scanned\r
3426 \r
3427         mov     bx,di\r
3428         sub     bx,dx                                   ; number of tiles in a row\r
3429         shl     bx,1                                    ; number of bytes / row\r
3430 \r
3431         mov     di,dx                                   ; lookup position of start tile\r
3432         sub     di,[updateptr]\r
3433         shl     di,1\r
3434         mov     di,[blockstarts-2+di]   ; start of tile location\r
3435         mov     si,di\r
3436         add     di,[bufferofs]                  ; dest in current screen\r
3437         add     si,[masterofs]                  ; source in master screen\r
3438 \r
3439         mov     dx,SCREENWIDTH\r
3440         sub     dx,bx                                   ; offset to next line on screen\r
3441 IFE GRMODE-CGAGR\r
3442         sub     dx,bx                                   ; bx is words wide in CGA tiles\r
3443 ENDIF\r
3444 \r
3445         mov     ax,[screenseg]\r
3446         mov     ds,ax\r
3447         mov     es,ax\r
3448 \r
3449 REPT    15\r
3450         mov     cx,bx\r
3451 IFE GRMODE-CGAGR\r
3452         rep     movsw\r
3453 ENDIF\r
3454 IFE GRMODE-EGAGR\r
3455         rep     movsb\r
3456 ENDIF\r
3457         add     si,dx\r
3458         add     di,dx\r
3459 ENDM\r
3460         mov     cx,bx\r
3461 IFE GRMODE-CGAGR\r
3462         rep     movsw\r
3463 ENDIF\r
3464 IFE GRMODE-EGAGR\r
3465         rep     movsb\r
3466 ENDIF\r
3467 \r
3468         dec     cx                                              ; was 0 from last rep movsb, now $ffff for scasb\r
3469         jmp     @@findtile\r
3470 \r
3471 ENDP\r
3472 \r
3473 \r
3474 ;============================================================================\r
3475 \r
3476 \r
3477 ;=================\r
3478 ;\r
3479 ; RFL_MaskForegroundTiles\r
3480 ;\r
3481 ; Scan through update looking for 3's.  If the foreground tile there is a\r
3482 ; masked foreground tile, draw it to the screen\r
3483 ;\r
3484 ;=================\r
3485 \r
3486 PROC    RFL_MaskForegroundTiles\r
3487 PUBLIC  RFL_MaskForegroundTiles\r
3488 USES    SI,DI,BP\r
3489         jmp     SHORT @@realstart\r
3490 @@done:\r
3491 ;\r
3492 ; all tiles have been scanned\r
3493 ;\r
3494         ret\r
3495 \r
3496 @@realstart:\r
3497         mov     di,[updateptr]\r
3498         mov     bp,(TILESWIDE+1)*TILESHIGH+2\r
3499         add     bp,di                                   ; when di = bx, all tiles have been scanned\r
3500         push    di\r
3501         mov     cx,-1                                   ; definately scan the entire thing\r
3502 ;\r
3503 ; scan for a 3 in the update list\r
3504 ;\r
3505 @@findtile:\r
3506         mov     ax,ss\r
3507         mov     es,ax                                   ; scan in the data segment\r
3508         mov     al,3\r
3509         pop     di                                              ; place to continue scaning from\r
3510         repne   scasb\r
3511         cmp     di,bp\r
3512         je      @@done\r
3513 \r
3514 ;============\r
3515 ;\r
3516 ; found a tile, see if it needs to be masked on\r
3517 ;\r
3518 ;============\r
3519 \r
3520         push    di\r
3521 \r
3522         sub     di,[updateptr]\r
3523         shl     di,1\r
3524         mov     si,[updatemapofs-2+di]  ; offset from originmap\r
3525         add     si,[originmap]\r
3526 \r
3527         mov     es,[mapsegs+2]                  ; foreground map plane segment\r
3528         mov     si,[es:si]                              ; foreground tile number\r
3529 \r
3530         or      si,si\r
3531         jz      @@findtile                              ; 0 = no foreground tile\r
3532 \r
3533         mov     bx,si\r
3534         add     bx,INTILE                               ;INTILE tile info table\r
3535         mov     es,[tinf]\r
3536         test    [BYTE PTR es:bx],80h            ;high bit = masked tile\r
3537         jz      @@findtile\r
3538 \r
3539 ;-------------------\r
3540 \r
3541 IFE GRMODE-CGAGR\r
3542 ;=================\r
3543 ;\r
3544 ; mask the tile CGA\r
3545 ;\r
3546 ;=================\r
3547 \r
3548         mov     di,[blockstarts-2+di]\r
3549         add     di,[bufferofs]\r
3550         mov     es,[screenseg]\r
3551         shl     si,1\r
3552         mov     ds,[grsegs+STARTTILE16M*2+si]\r
3553 \r
3554         mov     bx,64                                   ;data starts 64 bytes after mask\r
3555 \r
3556         xor     si,si\r
3557 \r
3558 lineoffset      =       0\r
3559 REPT    16\r
3560         mov     ax,[es:di+lineoffset]   ;background\r
3561         and     ax,[si]                                 ;mask\r
3562         or      ax,[si+bx]                              ;masked data\r
3563         mov     [es:di+lineoffset],ax   ;background\r
3564         inc     si\r
3565         inc     si\r
3566         mov     ax,[es:di+lineoffset+2] ;background\r
3567         and     ax,[si]                                 ;mask\r
3568         or      ax,[si+bx]                              ;masked data\r
3569         mov     [es:di+lineoffset+2],ax ;background\r
3570         inc     si\r
3571         inc     si\r
3572 lineoffset      =       lineoffset + SCREENWIDTH\r
3573 ENDM\r
3574 ENDIF\r
3575 \r
3576 ;-------------------\r
3577 \r
3578 IFE GRMODE-EGAGR\r
3579 ;=================\r
3580 ;\r
3581 ; mask the tile\r
3582 ;\r
3583 ;=================\r
3584 \r
3585         mov     [BYTE planemask],1\r
3586         mov     [BYTE planenum],0\r
3587 \r
3588         mov     di,[blockstarts-2+di]\r
3589         add     di,[bufferofs]\r
3590         mov     [cs:screenstartcs],di\r
3591         mov     es,[screenseg]\r
3592         shl     si,1\r
3593         mov     ds,[grsegs+STARTTILE16M*2+si]\r
3594 \r
3595         mov     bx,32                                   ;data starts 32 bytes after mask\r
3596 \r
3597 @@planeloopm:\r
3598         mov     dx,SC_INDEX\r
3599         mov     al,SC_MAPMASK\r
3600         mov     ah,[ss:planemask]\r
3601         WORDOUT\r
3602         mov     dx,GC_INDEX\r
3603         mov     al,GC_READMAP\r
3604         mov     ah,[ss:planenum]\r
3605         WORDOUT\r
3606 \r
3607         xor     si,si\r
3608         mov     di,[cs:screenstartcs]\r
3609 lineoffset      =       0\r
3610 REPT    16\r
3611         mov     cx,[es:di+lineoffset]   ;background\r
3612         and     cx,[si]                                 ;mask\r
3613         or      cx,[si+bx]                              ;masked data\r
3614         inc     si\r
3615         inc     si\r
3616         mov     [es:di+lineoffset],cx\r
3617 lineoffset      =       lineoffset + SCREENWIDTH\r
3618 ENDM\r
3619         add     bx,32                                   ;the mask is now further away\r
3620         inc     [ss:planenum]\r
3621         shl     [ss:planemask],1                ;shift plane mask over for next plane\r
3622         cmp     [ss:planemask],10000b   ;done all four planes?\r
3623         je      @@drawn                                 ;drawn all four planes\r
3624         jmp     @@planeloopm\r
3625 \r
3626 @@drawn:\r
3627 ENDIF\r
3628 \r
3629 ;-------------------\r
3630 \r
3631         mov     ax,ss\r
3632         mov     ds,ax\r
3633         mov     cx,-1                                   ;definately scan the entire thing\r
3634 \r
3635         jmp     @@findtile\r
3636 \r
3637 ENDP\r
3638 \r
3639 \r
3640 END\r
3641 \r
3642 */\r