]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_vl.c
106f71924ae35ac0ac2799a9688005f91dcd04fb
[16.git] / src / lib / 16_vl.c
1 /* Project 16 Source Code~\r
2  * Copyright (C) 2012-2017 sparky4 & pngwen & andrius4669 & joncampbell123 & yakui-lover\r
3  *\r
4  * This file is part of Project 16.\r
5  *\r
6  * Project 16 is free software; you can redistribute it and/or modify\r
7  * it under the terms of the GNU General Public License as published by\r
8  * the Free Software Foundation; either version 3 of the License, or\r
9  * (at your option) any later version.\r
10  *\r
11  * Project 16 is distributed in the hope that it will be useful,\r
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14  * GNU General Public License for more details.\r
15  *\r
16  * You should have received a copy of the GNU General Public License\r
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>, or\r
18  * write to the Free Software Foundation, Inc., 51 Franklin Street,\r
19  * Fifth Floor, Boston, MA 02110-1301 USA.\r
20  *\r
21  */\r
22 \r
23 #include <conio.h>\r
24 #include <stdio.h>\r
25 #include <stdlib.h>\r
26 #include "src/lib/16_vl.h"\r
27 \r
28 byte far* VGA=(byte far*) 0xA0000000;   /* this points to video memory. */\r
29 \r
30 static void fadePalette(sbyte fade, sbyte start, word iter, byte *palette);\r
31 static byte tmppal[PAL_SIZE];\r
32 \r
33 //===========================================================================\r
34 \r
35 /*\r
36 =======================\r
37 =\r
38 = VL_Startup\r
39 =\r
40 =======================\r
41 */\r
42 \r
43 void    VL_Startup (global_game_variables_t *gvar)\r
44 {\r
45         __asm   cld;\r
46 \r
47         VGAmodeX(1/*TODO other modes*/, 1, gvar);\r
48         VL_LoadPalFileCore(gvar->video.palette, gvar);\r
49         //Quit ("Improper video card!  If you really have a VGA card that I am not\ndetecting it!", gvar);\r
50 }\r
51 \r
52 \r
53 \r
54 /*\r
55 =======================\r
56 =\r
57 = VL_Shutdown\r
58 =\r
59 =======================\r
60 */\r
61 \r
62 void    VL_Shutdown (global_game_variables_t *gvar)\r
63 {\r
64         VGAmodeX(0, 1, gvar);\r
65 }\r
66 \r
67 /*\r
68 =======================\r
69 =\r
70 = VL_SetVGAPlaneMode\r
71 =\r
72 =======================\r
73 */\r
74 #if 0\r
75 void    VL_SetVGAPlaneMode (global_game_variables_t *gvar)\r
76 {\r
77         VL_vgaSetMode(VGA_256_COLOR_MODE);\r
78         VL_DePlaneVGA ();\r
79         VGAMAPMASK(15);\r
80         VL_SetLineWidth (40, &gvar->video.ofs);\r
81 }\r
82 #endif\r
83 \r
84 //===========================================================================\r
85 \r
86 /*\r
87 =================\r
88 =\r
89 = VL_ClearVideo\r
90 =\r
91 = Fill the entire video buffer with a given color\r
92 =\r
93 =================\r
94 */\r
95 \r
96 void VL_ClearVideo (byte color)\r
97 {\r
98         __asm {\r
99                 mov     dx,GC_INDEX\r
100                 mov     al,GC_MODE\r
101                 out     dx,al\r
102                 inc     dx\r
103                 in      al,dx\r
104                 and     al,0xfc                         // write mode 0 to store directly to video\r
105                 out     dx,al\r
106 \r
107                 mov     dx,SC_INDEX\r
108                 mov     ax,SC_MAPMASK+15*256\r
109                 out     dx,ax                           // write through all four planes\r
110 \r
111                 mov     ax,SCREENSEG\r
112                 mov     es,ax\r
113                 mov     al,[color]\r
114                 mov     ah,al\r
115                 mov     cx,0x8000                       // 0x8000 words, clearing 8 video bytes/word\r
116                 xor     di,di\r
117                 rep     stosw\r
118         }\r
119 }\r
120 \r
121 /*\r
122 =============================================================================\r
123 \r
124                         VGA REGISTER MANAGEMENT ROUTINES\r
125 \r
126 =============================================================================\r
127 */\r
128 \r
129 \r
130 /*\r
131 =================\r
132 =\r
133 = VL_DePlaneVGA\r
134 =\r
135 =================\r
136 */\r
137 #if 0\r
138 void VL_DePlaneVGA (void)\r
139 {\r
140 \r
141 //\r
142 // change CPU addressing to non linear mode\r
143 //\r
144 \r
145 //\r
146 // turn off chain 4 and odd/even\r
147 //\r
148         outportb (SC_INDEX,SC_MEMMODE);\r
149         outportb (SC_INDEX+1,(inportb(SC_INDEX+1)&~8)|4);\r
150 \r
151         outportb (SC_INDEX,SC_MAPMASK);         // leave this set throughought\r
152 \r
153 //\r
154 // turn off odd/even and set write mode 0\r
155 //\r
156         outportb (GC_INDEX,GC_MODE);\r
157         outportb (GC_INDEX+1,inportb(GC_INDEX+1)&~0x13);\r
158 \r
159 //\r
160 // turn off chain\r
161 //\r
162         outportb (GC_INDEX,GC_MISCELLANEOUS);\r
163         outportb (GC_INDEX+1,inportb(GC_INDEX+1)&~2);\r
164 \r
165 //\r
166 // clear the entire buffer space, because int 10h only did 16 k / plane\r
167 //\r
168         VL_ClearVideo (0);\r
169 \r
170 //\r
171 // change CRTC scanning from doubleword to byte mode, allowing >64k scans\r
172 //\r
173         outportb (CRTC_INDEX,CRTC_UNDERLINE);\r
174         outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1)&~0x40);\r
175 \r
176         outportb (CRTC_INDEX,CRTC_MODE);\r
177         outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1)|0x40);\r
178 }\r
179 #endif\r
180 //===========================================================================\r
181 \r
182 /*\r
183 ====================\r
184 =\r
185 = VL_SetSplitScreen\r
186 =\r
187 ====================\r
188 */\r
189 \r
190 void VL_SetSplitScreen (int linenum)\r
191 {\r
192         VL_WaitVBL (1);\r
193         linenum=linenum*2-1;\r
194         outportb (CRTC_INDEX,CRTC_LINECOMPARE);\r
195         outportb (CRTC_INDEX+1,linenum % 256);\r
196         outportb (CRTC_INDEX,CRTC_OVERFLOW);\r
197         outportb (CRTC_INDEX+1, 1+16*(linenum/256));\r
198         outportb (CRTC_INDEX,CRTC_MAXSCANLINE);\r
199         outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1) & (255-64));\r
200 }\r
201 \r
202 /////////////////////////////////////////////////////////////////////////////\r
203 //                                                                                                                      //\r
204 // setvideo() - This function Manages the video modes                                           //\r
205 //                                                                                                                      //\r
206 /////////////////////////////////////////////////////////////////////////////\r
207 void VGAmodeX(sword vq, boolean cmem, global_game_variables_t *gv)\r
208 {\r
209         union REGS in, out;\r
210 \r
211         switch (vq)\r
212         {\r
213                 case 0: // deinit the video\r
214                         // change to the video mode we were in before we switched to mode 13h\r
215                         if(gv->video.VL_Started)\r
216                         {\r
217                                 modexLeave();\r
218                                 in.h.ah = 0x00;\r
219                                 in.h.al = gv->video.old_mode;\r
220                                 int86(0x10, &in, &out);\r
221                         }\r
222                         gv->video.VL_Started=0;\r
223                 break;\r
224                 default: // init the video\r
225                         if(gv->video.VL_Started)\r
226                                 return;\r
227                         if(!gv->video.VL_Initiated)\r
228                                 TL_VidInit(gv);\r
229                         // get old video mode\r
230                         //in.h.ah = 0xf;\r
231                         //int86(0x10, &in, &out);\r
232                         gv->video.old_mode = VL_vgaGetMode();//out.h.al;\r
233                         // enter mode\r
234                         modexEnter(vq, cmem, gv);\r
235                 break;\r
236         }\r
237 }\r
238 \r
239 //---------------------------------------------------\r
240 //\r
241 // Use the bios to set the current video mode\r
242 //\r
243 \r
244 /*static */void\r
245 VL_vgaSetMode(byte mode)\r
246 {\r
247         union REGS regs;\r
248 \r
249         regs.h.ah = SET_MODE;\r
250         regs.h.al = mode;\r
251         int86(VIDEO_INT, &regs, &regs);\r
252 }\r
253 \r
254 //---------------------------------------------------\r
255 //\r
256 // Use the bios to get the current video mode\r
257 //\r
258 \r
259 byte\r
260 VL_vgaGetMode(void)\r
261 {\r
262         return int10_getmode();\r
263 }\r
264 \r
265 /* -========================= Entry  Points ==========================- */\r
266 void modexEnter(sword vq, boolean cmem, global_game_variables_t *gv)\r
267 {\r
268         //word i;\r
269         struct vga_mode_params cm;\r
270         //int CRTParmCount;\r
271 \r
272         VL_vgaSetMode(VGA_256_COLOR_MODE);\r
273         vga_enable_256color_modex();\r
274 \r
275         update_state_from_vga();\r
276         vga_read_crtc_mode(&cm);\r
277 \r
278         /* reprogram the CRT controller */\r
279         //outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */\r
280         //outp(CRTC_DATA, 0x7f);  /* get current write protect on varios regs */\r
281 \r
282         switch(vq)\r
283         {\r
284                 case 1:\r
285                 case 8: //320x240 no buffer\r
286                         //CRTParmCount = sizeof(ModeX_320x240regs) / sizeof(ModeX_320x240regs[0]);\r
287                         /*for(i=0; i<CRTParmCount; i++) {\r
288                                 outpw(CRTC_INDEX, ModeX_320x240regs[i]);\r
289                         }*/\r
290                         // width and height //\r
291                         gv->video.page[0].sw = vga_state.vga_width = 320; // VGA lib currently does not update this\r
292                         gv->video.page[0].sh = vga_state.vga_height = 240; // VGA lib currently does not update this\r
293                         // virtual width and height. match screen, at first //\r
294                         gv->video.page[0].height = gv->video.page[0].sh;\r
295                         gv->video.page[0].width = gv->video.page[0].sw;\r
296 \r
297                         // mode X BYTE mode\r
298                         cm.word_mode = 0;\r
299                         cm.dword_mode = 0;\r
300                         // 320x240 mode 60Hz\r
301                         cm.horizontal_total=0x5f + 5; /* CRTC[0]                         -5 */\r
302                         cm.horizontal_display_end=0x4f + 1; /* CRTC[1]     -1 */\r
303                         cm.horizontal_blank_start=0x50 + 1; /* CRTC[2] */\r
304 //                      cm.horizontal_blank_end=0x82 + 1;   /* CRTC[3] bit 0-4 & CRTC[5] bit 7 *///skewing ^^;\r
305                         cm.horizontal_start_retrace=0x54;/* CRTC[4] */\r
306                         cm.horizontal_end_retrace=0x80; /* CRTC[5] bit 0-4 */\r
307                         //cm.horizontal_start_delay_after_total=0x3e; /* CRTC[3] bit 5-6 */\r
308                         //cm.horizontal_start_delay_after_retrace=0x41; /* CRTC[5] bit 5-6 */\r
309                         cm.vertical_total = 0x20D + 2;\r
310                         cm.vertical_start_retrace = 0x1EA;\r
311                         cm.vertical_end_retrace = 0x1EC;\r
312                         cm.vertical_display_end = 480;\r
313                         cm.vertical_blank_start = 0x1E7 + 1;\r
314                         cm.vertical_blank_end = 0x206 + 1;\r
315                         cm.clock_select = 0; /* misc register = 0xE3  25MHz */\r
316                         cm.vsync_neg = 1;\r
317                         cm.hsync_neg = 1;\r
318                         cm.offset = (vga_state.vga_width / (4 * 2)); // 320 wide (40 x 4 pixel groups x 2)\r
319                         break;\r
320                 case 2: // TODO: 160x120 according to ModeX_160x120regs\r
321                         return;\r
322                 case 3: // TODO: 160x120 according to ModeX_320x200regs\r
323                         return;\r
324                 case 4: // TODO: 160x120 according to ModeX_192x144regs\r
325                         return;\r
326                 case 5: // TODO: 160x120 according to ModeX_256x192regs\r
327                         return;\r
328                 default:\r
329                         return;\r
330         }\r
331 \r
332         vga_state.vga_stride = cm.offset * 2;\r
333         vga_write_crtc_mode(&cm,0);\r
334 \r
335         // clear video memory //\r
336         switch (cmem)\r
337         {\r
338                 case 1:\r
339                 {\r
340 #if 0\r
341                         dword far*ptr=(dword far*)vga_state.vga_graphics_ram;//VGA;       // used for faster screen clearing //\r
342                         vga_write_sequencer(2/*map mask register*/,0xf/*all 4 planes*/);\r
343                         for(i = 0;i < 0x4000; i++) ptr[i] = 0x0000; // 0x4000 x dword = 64KB\r
344                         // fix up the palette and everything //\r
345                         modexPalBlack();        //reset the palette~//\r
346 #endif\r
347                         //\r
348                         // clear the entire buffer space, because int 10h only did 16 k / plane\r
349                         //\r
350                         VL_ClearVideo (0);\r
351                 }\r
352                 break;\r
353         }\r
354 //--    VL_SetLineWidth (cm.offset, gv);\r
355         //gv->video.ofs.displayofs = 0;\r
356         //gv->video.ofs.bufferofs = gv->video.page[0].width*gv->video.page[0].height;//gvar->video.page[0].pagesize;\r
357         gv->video.curr_mode=vq;\r
358         gv->video.VL_Started=1;\r
359 }\r
360 \r
361 void modexLeave(void)\r
362 {\r
363         // VGAmodeX restores original mode and palette\r
364         VL_vgaSetMode(TEXT_MODE);\r
365 }\r
366 \r
367 #if 0\r
368 page_t\r
369 modexDefaultPage(page_t *p)\r
370 {\r
371         page_t page;\r
372         /* default page values */\r
373         //page.data = VGA;\r
374         //page.data = (byte far *)(vga_state.vga_graphics_ram);\r
375         page.data = (vga_state.vga_graphics_ram);\r
376         page.dx = 0;\r
377         page.dy = 0;\r
378         page.sw = p->sw;\r
379         page.sh = p->sh;\r
380         page.width = p->sw;\r
381         page.height = p->sh;\r
382         page.ti.tw = page.sw/TILEWH;\r
383         page.ti.th = page.sh/TILEWH;\r
384         page.ti.tilesw=page.width/TILEWH;\r
385         page.ti.tilesh=page.height/TILEWH;\r
386         page.ti.tilemidposscreenx = page.ti.tw/2;\r
387         page.ti.tilemidposscreeny = (page.ti.th/2)+1;\r
388         page.stridew=page.width/4;\r
389         page.pagesize = (word)(page.stridew)*page.height;\r
390         page.pi=page.width*4;\r
391         page.id = 0;\r
392         if(ggvv->video.curr_mode = 1)\r
393         {\r
394                 page.width += TILEWHD;\r
395                 page.height += TILEWHD;\r
396         }\r
397         return page;\r
398 }\r
399 #endif\r
400 page_t\r
401 modexDefaultPage(page_t *p, global_game_variables_t *gvar)\r
402 {\r
403         page_t page;\r
404 \r
405         /* default page values */\r
406         //page.data = VGA;\r
407         //page.data = (byte far *)(vga_state.vga_graphics_ram);\r
408         page.data = (vga_state.vga_graphics_ram);\r
409         page.dx = 0;\r
410         page.dy = 0;\r
411         page.sw = p->sw;\r
412         page.sh = p->sh;\r
413         page.width = p->sw;\r
414         page.height = p->sh;\r
415         if(gvar->video.curr_mode == 1)\r
416 {       page.width += TILEWHD;\r
417         page.height += TILEWHD; }\r
418         page.ti.tw = page.sw/TILEWH;\r
419         page.ti.th = page.sh/TILEWH;\r
420         page.ti.tilesw=page.width/TILEWH;\r
421         page.ti.tilesh=page.height/TILEWH;\r
422         page.ti.tilemidposscreenx = page.ti.tw/2;\r
423         page.ti.tilemidposscreeny = (page.ti.th/2)+1;\r
424         page.stridew=page.width/4;\r
425         page.pagesize = (word)(page.stridew)*page.height;\r
426         page.pi=page.width*4;\r
427         page.id = 0;\r
428 \r
429         return page;\r
430 }\r
431 \r
432 /* returns the next page in contiguous memory\r
433  * the next page will be the same size as p, by default\r
434  */\r
435 page_t\r
436 modexNextPage(page_t *p) {\r
437         page_t result;\r
438 \r
439         result.data = p->data + (p->pagesize);\r
440         result.dx = p->dx;      // not used anymore we use page[0].dx\r
441         result.dy = p->dy;      // not used anymore we use page[0].dy\r
442         result.sw = p->sw;\r
443         result.sh = p->sh;\r
444         result.width = p->width;\r
445         result.height = p->height;\r
446         result.ti.tw = p->ti.tw;\r
447         result.ti.th = p->ti.th;\r
448         result.ti.tilesw = p->ti.tilesw;\r
449         result.ti.tilesh = p->ti.tilesh;\r
450         result.stridew=p->stridew;\r
451         result.pagesize = p->pagesize;\r
452         result.pi=result.width*4;\r
453         result.id = p->id+1;\r
454 \r
455         return result;\r
456 }\r
457 \r
458 //next page with defined dimentions~\r
459 page_t\r
460 modexNextPageFlexibleSize(page_t *p, word x, word y)\r
461 {\r
462         page_t result;\r
463 \r
464         result.data = p->data + (p->pagesize);  /* compute the offset */\r
465         result.dx = 0;  // not used anymore we use page[0].dx\r
466         result.dy = 0;  // not used anymore we use page[0].dy\r
467         result.sw = x;\r
468         result.sh = y;\r
469         result.width = x;\r
470         result.height = y;\r
471         result.ti.tw = result.sw/TILEWH;\r
472         result.ti.th = result.sh/TILEWH;\r
473         result.ti.tilesw=result.width/TILEWH;\r
474         result.ti.tilesh=result.height/TILEWH;\r
475         result.id = p->id+1;\r
476         result.stridew=result.width/4;//p->sw/4;\r
477         result.pagesize = (word)(result.stridew)*result.height;\r
478 /*      switch(result.id)\r
479         {\r
480                 case 2:\r
481                         result.pi=p->width*4;\r
482                 break;\r
483                 case 3:\r
484                         result.pi=p->pi;\r
485                 break;\r
486         }*/\r
487         result.pi=result.width*4;\r
488 \r
489         return result;\r
490 }\r
491 \r
492 void modexCalcVmemRemain(video_t *video)\r
493 {\r
494         byte i;\r
495         //printf("\n\n  1st vmem_remain=%u\n", video->vmem_remain);\r
496         for(i=0; i<video->num_of_pages; i++)\r
497         {\r
498                 video->vmem_remain-=video->page[i].pagesize;\r
499                 //printf("              [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);\r
500                 //printf("              [%u], vmem_remain=%u\n", i, video->vmem_remain);\r
501         }\r
502 }\r
503 \r
504 void VL_Initofs(video_t *video)\r
505 {\r
506         if(!video->vga_state.bgps)\r
507         {\r
508                 video->ofs.offscreen_ofs =      video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);\r
509                 video->ofs.pattern_ofs =        (uint16_t)video->page[2].data;\r
510         }else{\r
511                 video->ofs.offscreen_ofs =      0;\r
512                 video->ofs.pattern_ofs =        0;//(uint16_t)video->page[0].data;\r
513         }\r
514 }\r
515 \r
516 void modexHiganbanaPageSetup(global_game_variables_t *gvar)\r
517 {\r
518         gvar->video.vmem_remain=65535U;\r
519         gvar->video.num_of_pages=0;\r
520         (gvar->video.page[0]) = modexDefaultPage(&(gvar->video.page[0]), gvar); gvar->video.num_of_pages++;     //gvar->video.page[0].width += (TILEWHD); gvar->video.page[0].height += (TILEWHD);\r
521         (gvar->video.page[1]) = modexNextPage(&(gvar->video.page[0]));  gvar->video.num_of_pages++;\r
522 //0000  (gvar->video.page[2]) = modexNextPageFlexibleSize(&(gvar->video.page[1]), (gvar->video.page[0]).width, TILEWH*4);               gvar->video.num_of_pages++;\r
523 //0000  (gvar->video.page[3]) = (gvar->video.page[2]);          gvar->video.num_of_pages++;\r
524 ////    (gvar->video.page[2]) = modexNextPageFlexibleSize(&(gvar->video.page[1]), TILEWH*4, TILEWH*4);          gvar->video.num_of_pages++;\r
525 ////    (gvar->video.page[3]) = modexNextPageFlexibleSize(&(gvar->video.page[2]), gvar->video.page[0].sw, 208); gvar->video.num_of_pages++;\r
526         (gvar->video.page[2]) = modexNextPageFlexibleSize(&(gvar->video.page[1]), gvar->video.page[0].width, 96);       gvar->video.num_of_pages++;\r
527         (gvar->video.page[3]) = modexNextPageFlexibleSize(&(gvar->video.page[2]), gvar->video.page[0].width, 96);       gvar->video.num_of_pages++;\r
528         modexCalcVmemRemain(&gvar->video);\r
529 \r
530         gvar->video.sp=gvar->video.p =  0;      //showpage\r
531         gvar->video.dorender =  1;                      //render\r
532         gvar->video.vh=gvar->video.page[0].height+gvar->video.page[1].height+gvar->video.page[2].height+gvar->video.page[3].height;\r
533 \r
534         VL_Initofs(&gvar->video);\r
535         //doslib origi var\r
536         gvar->video.vga_state.omemptr=                  vga_state.vga_graphics_ram;\r
537         gvar->video.vga_state.vga_draw_stride=  vga_state.vga_draw_stride;\r
538         gvar->video.vga_state.vga_draw_stride_limit=    vga_state.vga_draw_stride_limit;\r
539         //sprite render switch and bgpreservation switch\r
540         gvar->video.vga_state.rss=      1;\r
541         gvar->video.vga_state.bgps=     1;\r
542 \r
543         //setup the buffersize\r
544         gvar->video.page[0].dx=gvar->video.page[0].dy=\r
545                 gvar->video.page[1].dx=gvar->video.page[1].dy=TILEWH;   // 1 tile size buffer\r
546         gvar->video.page[2].dx=gvar->video.page[2].dy=\r
547                 gvar->video.page[3].dx=gvar->video.page[3].dy=0;                // cache pages are buffer wwww\r
548 }\r
549 \r
550 //\r
551 // move page to appropriate part and show it\r
552 //\r
553 void\r
554 modexShowPage(page_t *page) {\r
555         word high_address, low_address, offset;\r
556         byte crtcOffset;\r
557 \r
558         /* calculate offset */\r
559         offset = (word) page->data;\r
560         offset += page[0].dy * (page->width >> 2 );\r
561         offset += page[0].dx >> 2;\r
562 \r
563         /* calculate crtcOffset according to virtual width */\r
564         crtcOffset = page->width >> 3;\r
565 \r
566         high_address = HIGH_ADDRESS | (offset & 0xff00);\r
567         low_address  = LOW_ADDRESS  | (offset << 8);\r
568 \r
569         /* wait for appropriate timing and then program CRTC */\r
570 //+=+=                                                                          while ((inp(STATUS_REGISTER_1) & DISPLAY_ENABLE));\r
571         outpw(CRTC_INDEX, high_address);\r
572         outpw(CRTC_INDEX, low_address);\r
573         outp(CRTC_INDEX, 0x13);\r
574         outp(CRTC_DATA, crtcOffset);\r
575 \r
576         /* wait for one retrace */\r
577 //+=+=                                                                          while (!(inp(STATUS_REGISTER_1) & VRETRACE));\r
578 \r
579         /* do PEL panning here */\r
580         outp(AC_INDEX, 0x33);\r
581         outp(AC_INDEX, (page[0].dx & 0x03) << 1);\r
582 }\r
583 \r
584 //args: page, vertical sync switch, screen resolution switch, page0 switch\r
585 void\r
586 VL_ShowPage(page_t *page, boolean vsync, boolean sr)\r
587 {\r
588         word high_address, low_address, offset;\r
589         byte crtcOffset;\r
590 \r
591         // calculate offset\r
592         offset = (word) page->data;\r
593         offset += page->dy * (page->width >> 2 );\r
594         offset += page->dx >> 2;\r
595 \r
596         // calculate crtcOffset according to virtual width\r
597         switch(sr)\r
598         {\r
599                 case 1:\r
600                         crtcOffset = page->sw >> 3;\r
601                 break;\r
602                 default:\r
603                 case 0:\r
604                         crtcOffset = page->width >> 3;\r
605                 break;\r
606         }\r
607 \r
608         high_address = HIGH_ADDRESS | (offset & 0xff00);\r
609         low_address  = LOW_ADDRESS  | (offset << 8);\r
610 \r
611         // wait for appropriate timing and then program CRTC\r
612         if(vsync) while ((inp(STATUS_REGISTER_1) & DISPLAY_ENABLE));\r
613         outpw(CRTC_INDEX, high_address);\r
614         outpw(CRTC_INDEX, low_address);\r
615         outp(CRTC_INDEX, 0x13);\r
616         outp(CRTC_DATA, crtcOffset);\r
617 \r
618         // wait for one retrace\r
619         if(vsync) while (!(inp(STATUS_REGISTER_1) & VRETRACE));\r
620 \r
621         // do PEL panning here\r
622         outp(AC_INDEX, 0x33);\r
623         outp(AC_INDEX, (page->dx & 0x03) << 1);\r
624         vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;\r
625         vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;\r
626 }\r
627 \r
628 //=============================================================================\r
629 \r
630 void\r
631 modexPanPage(page_t *page, int dx, int dy) {\r
632         page[0].dx = dx;\r
633         page[0].dy = dy;\r
634 }\r
635 \r
636 void\r
637 modexSelectPlane(byte plane) {\r
638         outp(SC_INDEX, SC_MAPMASK);       /* select plane */\r
639         outp(SC_DATA,  plane);\r
640 }\r
641 \r
642 void\r
643 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)\r
644 {\r
645         word pageOff = (word) page->data;\r
646         word xoff=(x>>2);                                                       // xoffset that begins each row\r
647         word poffset = pageOff + y*(page->stridew) + xoff;      // starting offset\r
648         word scanCount=w>>2;                                            // number of iterations per row (excluding right clip)\r
649         word nextRow = page->stridew-scanCount-1;               // loc of next row\r
650         LRCLIPDEF\r
651         byte left = lclip[x&0x03];\r
652         byte right = rclip[(x+w)&0x03];\r
653 \r
654         // handle the case which requires an extra group\r
655         if((x & 0x03) && !((x+w) & 0x03)) {\r
656                 right=0x0f;\r
657         }\r
658 \r
659         //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);\r
660 \r
661         __asm {\r
662                 PUSHF\r
663                 PUSH ES\r
664                 PUSH AX\r
665                 PUSH BX\r
666                 PUSH CX\r
667                 PUSH DX\r
668                 PUSH SI\r
669                 PUSH DI\r
670                 MOV AX, SCREEN_SEG        ; go to the VGA memory\r
671                 MOV ES, AX\r
672                 MOV DI, poffset  ; go to the first pixel\r
673                 MOV DX, SC_INDEX        ; point to the map mask\r
674                 MOV AL, SC_MAPMASK\r
675                 OUT DX, AL\r
676                 INC DX\r
677                 MOV AL, color      ; get ready to write colors\r
678         SCAN_START:\r
679                 MOV CX, scanCount          ; count the line\r
680                 MOV BL, AL                ; remember color\r
681                 MOV AL, left            ; do the left clip\r
682                 OUT DX, AL                ; set the left clip\r
683                 MOV AL, BL                ; restore color\r
684                 STOSB              ; write the color\r
685                 DEC CX\r
686                 JZ SCAN_DONE            ; handle 1 group stuff\r
687 \r
688                 ;-- write the main body of the scanline\r
689                 MOV BL, AL                ; remember color\r
690                 MOV AL, 0x0f            ; write to all pixels\r
691                 OUT DX, AL\r
692                 MOV AL, BL                ; restore color\r
693                 REP STOSB                  ; write the color\r
694         SCAN_DONE:\r
695                 MOV BL, AL                ; remeber color\r
696                 MOV AL, right\r
697                 OUT DX, AL                ; do the right clip\r
698                 MOV AL, BL                ; restore color\r
699                 STOSB              ; write pixel\r
700                 ADD DI, nextRow  ; go to the next row\r
701                 DEC h\r
702                 JNZ SCAN_START\r
703                 POP DI\r
704                 POP SI\r
705                 POP DX\r
706                 POP CX\r
707                 POP BX\r
708                 POP AX\r
709                 POP ES\r
710                 POPF\r
711         }\r
712 }\r
713 \r
714 /* moved to src/lib/modex16/16render.c */\r
715 \r
716 /* copy a region of video memory from one page to another.\r
717  * It assumes that the left edge of the tile is the same on both\r
718  * regions and the memory areas do not overlap.\r
719  */\r
720 void\r
721 modexCopyPageRegion(page_t *dest, page_t *src,\r
722                         word sx, word sy,\r
723                         word dx, word dy,\r
724                         word width, word height)\r
725 {\r
726         word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);\r
727         word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);\r
728         word scans      = vga_state.vga_stride+8;                               //++++0000 the quick and dirty fix of the major issue with p16 video display wwww\r
729         word nextSrcRow = src->stridew - scans - 1;\r
730         word nextDestRow = dest->stridew - scans - 1;\r
731         LRCLIPDEF\r
732         byte left = lclip[sx&0x03];\r
733         byte right = rclip[(sx+width)&0x03];\r
734 \r
735         // handle the case which requires an extra group\r
736         if((sx & 0x03) && !((sx+width) & 0x03)) {\r
737                 right=0x0f;\r
738         }\r
739 \r
740 //      printf("modexCopyPageRegion(src->stridew=%u, dest->stridew=%u, sx=%u, sy=%u, dx=%u, dy=%u, width=%u, height=%u, left=%u, right=%u)\n", src->stridew, dest->stridew, sx, sy, dx, dy, width, height, left, right);\r
741 \r
742         __asm {\r
743                 PUSHF\r
744                 PUSH ES\r
745                 PUSH AX\r
746                 PUSH BX\r
747                 PUSH CX\r
748                 PUSH DX\r
749                 PUSH SI\r
750                 PUSH DI\r
751 \r
752                 MOV AX, SCREEN_SEG        ; work in the vga space\r
753                 MOV ES, AX                ;\r
754                 MOV DI, doffset  ;\r
755                 MOV SI, soffset  ;\r
756 \r
757                 MOV DX, GC_INDEX        ; turn off cpu bits\r
758                 MOV AX, 0008h      ;\r
759                 OUT DX, AX\r
760 \r
761                 MOV AX, SC_INDEX        ; point to the mask register\r
762                 MOV DX, AX                ;\r
763                 MOV AL, SC_MAPMASK      ;\r
764                 OUT DX, AL                ;\r
765                 INC DX            ;\r
766 \r
767         ROW_START:\r
768                 PUSH DS\r
769                 MOV AX, ES\r
770                 MOV DS, AX\r
771                 MOV CX, scans      ; the number of latches\r
772 \r
773                 MOV AL, left            ; do the left column\r
774                 OUT DX, AL                ;\r
775                 MOVSB              ;\r
776                 DEC CX            ;\r
777 \r
778                 MOV AL, 0fh              ; do the inner columns\r
779                 OUT DX, AL\r
780                 REP MOVSB                  ; copy the pixels\r
781 \r
782                 MOV AL, right      ; do the right column\r
783                 OUT DX, AL\r
784                 MOVSB\r
785                 POP DS\r
786 \r
787                 MOV AX, SI                ; go the start of the next row\r
788                 ADD AX, nextSrcRow        ;\r
789                 MOV SI, AX                ;\r
790                 MOV AX, DI                ;\r
791                 ADD AX, nextDestRow      ;\r
792                 MOV DI, AX                ;\r
793 \r
794                 DEC height                ; do the rest of the actions\r
795                 JNZ ROW_START      ;\r
796 \r
797                 MOV DX, GC_INDEX+1        ; go back to CPU data\r
798                 MOV AL, 0ffh            ; none from latches\r
799                 OUT DX, AL                ;\r
800 \r
801                 POP DI\r
802                 POP SI\r
803                 POP DX\r
804                 POP CX\r
805                 POP BX\r
806                 POP AX\r
807                 POP ES\r
808                 POPF\r
809         }\r
810 }\r
811 \r
812 //check 16_vl_1.c\r
813 \r
814 /* fade and flash */\r
815 void\r
816 modexFadeOn(word fade, byte *palette) {\r
817         fadePalette(-fade, 64, 64/fade+1, palette);\r
818 }\r
819 \r
820 \r
821 void\r
822 modexFadeOff(word fade, byte *palette) {\r
823         fadePalette(fade, 0, 64/fade+1, palette);\r
824 }\r
825 \r
826 \r
827 void\r
828 modexFlashOn(word fade, byte *palette) {\r
829         fadePalette(fade, -64, 64/fade+1, palette);\r
830 }\r
831 \r
832 \r
833 void\r
834 modexFlashOff(word fade, byte *palette) {\r
835         fadePalette(-fade, 0, 64/fade+1, palette);\r
836 }\r
837 \r
838 \r
839 static void\r
840 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {\r
841         word i;\r
842         byte dim = start;\r
843 \r
844         /* handle the case where we just update */\r
845         if(iter == 0) {\r
846         modexPalUpdate(palette);\r
847         return;\r
848         }\r
849 \r
850         while(iter > 0) {  /* FadeLoop */\r
851         for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */\r
852                 tmppal[i] = palette[i] - dim;\r
853                 if(tmppal[i] > 127) {\r
854                 tmppal[i] = 0;\r
855                 } else if(tmppal[i] > 63) {\r
856                 tmppal[i] = 63;\r
857                 }\r
858         }\r
859         modexPalUpdate(tmppal);\r
860         iter--;\r
861         dim += fade;\r
862         }\r
863 }\r
864 \r
865 \r
866 // save and load\r
867 void modexPalSave(byte *palette)\r
868 {\r
869         int  i;\r
870 \r
871         outp(PAL_READ_REG, 0);                  // start at palette entry 0\r
872         for(i=0; i<PAL_SIZE; i++)\r
873         {\r
874                 palette[i] = inp(PAL_DATA_REG); // read the palette data\r
875         }\r
876 }\r
877 \r
878 \r
879 /*byte *\r
880 modexNewPal() {\r
881         byte *ptr;\r
882         ptr = mAlloc(PAL_SIZE);\r
883 \r
884         // handle errors\r
885         if(!ptr) {\r
886                 printf("Could not Allocate palette.\n");\r
887         }\r
888 \r
889         return ptr;\r
890 }*/\r
891 \r
892 \r
893 void\r
894 modexLoadPalFile(byte *filename, byte *palette) {\r
895         FILE *file;\r
896         byte *ptr;\r
897 \r
898         // free the palette if it exists\r
899         //if(*palette) { free(*palette); }\r
900 \r
901         // allocate the new palette\r
902         //*palette = modexNewPal();\r
903 \r
904         // open the file\r
905         file = fopen(filename, "rb");\r
906         if(!file) {\r
907                 printf("Could not open palette file: %s\n", filename);\r
908         }\r
909 \r
910         /* read the file */\r
911         ptr = palette;\r
912         while(!feof(file)) {\r
913         *ptr++ = fgetc(file);\r
914         }\r
915 \r
916         fclose(file);\r
917 }\r
918 \r
919 #define COREPALSIZE 9//27       //3*9\r
920 \r
921 void VLL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, word palsize, global_game_variables_t *gvar)\r
922 {\r
923         int fd;\r
924         byte *newpalette;\r
925 \r
926         fd = open(filename,O_RDONLY|O_BINARY);\r
927         if (fd >= 0) {\r
928                 read(fd,palette,        palsize*3);\r
929                 close(fd);\r
930 \r
931                 if(palsize==COREPALSIZE) newpalette = palette; else{    //if core then load it\r
932                 newpalette = &palette[3];                       //skip overscan color\r
933                 if(!o) o++;\r
934                 }\r
935                 VL_UpdatePaletteWrite(newpalette, o, palsize, gvar);\r
936         }\r
937 }\r
938 \r
939 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)\r
940 {\r
941         VLL_LoadPalFilewithoffset(filename, palette,\r
942                 0,                      //overwrite core/system palette\r
943 //              COREPALSIZE,    //preserved core/system palette\r
944                 PAL_SIZE/3, gvar);\r
945 }\r
946 \r
947 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)\r
948 {\r
949         VLL_LoadPalFilewithoffset("data/16.pal", palette, 0, COREPALSIZE, gvar);\r
950 }\r
951 \r
952 void VL_UpdatePaletteWrite(byte *palette, word o, word p, global_game_variables_t *gvar)\r
953 {\r
954         word i;\r
955 \r
956         vga_palette_lseek(o);\r
957         for (i=0;i < p-o;i++)\r
958                 vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);\r
959 \r
960         VL_PaletteSync(gvar);\r
961 }\r
962 \r
963 void VL_PaletteSync(global_game_variables_t *gvar)\r
964 {\r
965         modexPalSave(&gvar->video.palette);\r
966 }\r
967 \r
968 void\r
969 modexSavePalFile(char *filename, byte *pal) {\r
970         //unsigned int i;\r
971         FILE *file;\r
972 \r
973         /* open the file for writing */\r
974         file = fopen(filename, "wb");\r
975         if(!file) {\r
976         printf("Could not open %s for writing\n", filename);\r
977         }\r
978 \r
979         /* write the data to the file */\r
980         fwrite(pal, 1, PAL_SIZE, file);\r
981         fclose(file);\r
982 }\r
983 \r
984 \r
985 /* blanking */\r
986 void\r
987 modexPalBlack() {\r
988         fadePalette(-1, 64, 1, tmppal);\r
989 }\r
990 \r
991 \r
992 void\r
993 modexPalWhite() {\r
994         fadePalette(-1, -64, 1, tmppal);\r
995 }\r
996 \r
997 \r
998 /* utility */\r
999 //moved to 16_vlpal.c\r
1000 \r
1001 void\r
1002 modexPalUpdate(byte *p)\r
1003 {\r
1004         int i;\r
1005         //modexWaitBorder();\r
1006         vga_wait_for_vsync();\r
1007         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
1008         for(i=0; i<PAL_SIZE/2; i++)\r
1009         {\r
1010                 outp(PAL_DATA_REG, p[i]);\r
1011         }\r
1012         //modexWaitBorder();      /* waits one retrace -- less flicker */\r
1013         vga_wait_for_vsync();\r
1014         for(; i<PAL_SIZE; i++)\r
1015         {\r
1016                 outp(PAL_DATA_REG, p[(i)]);\r
1017         }\r
1018 }\r
1019 \r
1020 void\r
1021 //modexPalUpdate0(byte *p)\r
1022 VL_modexPalScramble(byte *p)\r
1023 {\r
1024         int i;\r
1025         //modexWaitBorder();\r
1026         vga_wait_for_vsync();\r
1027         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
1028         for(i=0; i<PAL_SIZE/2; i++)\r
1029         {\r
1030                 outp(PAL_DATA_REG, rand());\r
1031         }\r
1032         //modexWaitBorder();      /* waits one retrace -- less flicker */\r
1033         vga_wait_for_vsync();\r
1034         for(; i<PAL_SIZE; i++)\r
1035         {\r
1036                 outp(PAL_DATA_REG, rand());\r
1037         }\r
1038 }\r
1039 \r
1040 word\r
1041 VL_modexPalOverscan(byte *p, word col)\r
1042 {\r
1043         int i;\r
1044         //modexWaitBorder();\r
1045         vga_wait_for_vsync();\r
1046         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
1047         for(i=col; i<(3+col); i++)\r
1048         {\r
1049                 outp(PAL_DATA_REG, p[i]);\r
1050         }\r
1051 //      modexPalSave(p);\r
1052         return col;\r
1053 }\r
1054 \r
1055 //check 16_vl_1.c\r
1056 \r
1057 void modexputPixel(page_t *page, int x, int y, byte color)\r
1058 {\r
1059         word pageOff = (word) page->data;\r
1060         /* Each address accesses four neighboring pixels, so set\r
1061            Write Plane Enable according to which pixel we want\r
1062            to modify.  The plane is determined by the two least\r
1063            significant bits of the x-coordinate: */\r
1064         modexSelectPlane(PLANE(x));\r
1065         //outp(SC_INDEX, 0x02);\r
1066         //outp(SC_DATA, 0x01 << (x & 3));\r
1067 \r
1068         /* The offset of the pixel into the video segment is\r
1069            offset = (width * y + x) / 4, and write the given\r
1070            color to the plane we selected above.  Heed the active\r
1071            page start selection. */\r
1072         VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;\r
1073 \r
1074 }\r
1075 \r
1076 byte modexgetPixel(page_t *page, int x, int y)\r
1077 {\r
1078         word pageOff = (word) page->data;\r
1079         /* Select the plane from which we must read the pixel color: */\r
1080         outpw(GC_INDEX, 0x04);\r
1081         outpw(GC_INDEX+1, x & 3);\r
1082 \r
1083         return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];\r
1084 \r
1085 }\r
1086 \r
1087 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)\r
1088 {\r
1089         /* vertical drawing routine by joncampbell123.\r
1090          *\r
1091          * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.\r
1092          * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.\r
1093          *\r
1094          * NTS: addr defines what VGA memory address we use, "x" is redundant except to specify which of the 4 pixels we select in the map mask register. */\r
1095         word rows = romFonts[t].charSize;\r
1096         word drawaddr;\r
1097         word colm, row;\r
1098         byte fontbyte;\r
1099         byte plane;\r
1100         byte m1,m2;\r
1101 \r
1102         plane = x & 3;\r
1103         m1 = 0x80; // left half\r
1104         m2 = 0x08; // right half\r
1105         for (colm=0;colm < 4;colm++) {\r
1106                 drawaddr = addr;\r
1107                 modexSelectPlane(PLANE(plane));\r
1108                 for (row=0;row < rows;row++) {\r
1109                         fontbyte = romFontsData.l[row];\r
1110                         vga_state.vga_graphics_ram[drawaddr  ] = (fontbyte & m1) ? col : bgcol;\r
1111                         vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;\r
1112                         drawaddr += page->width >> 2;\r
1113                 }\r
1114 \r
1115                 m1 >>= 1;\r
1116                 m2 >>= 1;\r
1117                 if ((++plane) == 4) {\r
1118                         addr++;\r
1119                         plane = 0;\r
1120                 }\r
1121         }\r
1122 }\r
1123 \r
1124 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word color, word bgcolor, boolean vidsw, const byte *str)\r
1125 {\r
1126         word s, o, w;\r
1127         word x_draw;\r
1128         //word addr = (word) romFontsData.l;\r
1129         word addrq;\r
1130         word addrr;\r
1131         byte c;\r
1132 \r
1133         switch(vidsw)\r
1134         {\r
1135                 case 0:\r
1136                         printf("%s\n", str);\r
1137                 break;\r
1138                 case 1:\r
1139                         if(tlsw){ x-=page->tlx; y-=page->tly; }\r
1140                         x_draw = x>>2;\r
1141                         addrq = (page->stridew) * y + (word)(x_draw) +\r
1142                                 ((word)page->data);\r
1143                         addrr = addrq;\r
1144                         s=romFonts[t].seg;\r
1145                         o=romFonts[t].off;\r
1146                         w=romFonts[t].charSize;\r
1147                         romFontsData.chw=0;\r
1148 \r
1149                         for(; *str != '\0'; str++)\r
1150                         {\r
1151                                 c = (*str);\r
1152                                 if(c=='\n')\r
1153                                 {\r
1154                                         x = x_draw;\r
1155                                         romFontsData.chw = 0;\r
1156                                         addrq += (page->stridew) * 8;\r
1157                                         addrr = addrq;\r
1158                                         y += 8;\r
1159                                         continue;\r
1160                                 }\r
1161 \r
1162                         // load the character into romFontsData.l\r
1163                         // no need for inline assembly!\r
1164                         // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.\r
1165                                 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);\r
1166                                 modexDrawChar(page, x_draw/*for mode X planar use*/, t, color, bgcolor, addrr);\r
1167                                 x_draw += 8; /* track X for edge of screen */\r
1168                                 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */\r
1169                         }\r
1170                         //printf("print xy:%dx%d        tlxy:%dx%d\n", x, y, page->tlx, page->tly);\r
1171                 break;\r
1172         }\r
1173 }\r
1174 \r
1175 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)\r
1176 {\r
1177         word i, s, o, w, j, xp;\r
1178         byte l[1024];\r
1179         word addr = (word) l;\r
1180         word chw=0;\r
1181         byte c;\r
1182 \r
1183         switch(t)\r
1184         {\r
1185                 case 0:\r
1186                         w=14;\r
1187                 break;\r
1188                 case 1:\r
1189                         w=8;\r
1190                 break;\r
1191                 case 2:\r
1192                         w=8;\r
1193                 break;\r
1194                 case 3:\r
1195                         w=16;\r
1196                 break;\r
1197                 default:\r
1198                         t=3;\r
1199                         w=16;\r
1200                 break;\r
1201         }\r
1202 \r
1203         s=romFonts[t].seg;\r
1204         o=romFonts[t].off;\r
1205 \r
1206         for(; *str != '\0'; str++)\r
1207         {\r
1208         c = (*str);\r
1209         if((c=='\n'/* || c=="\\r
1210 "*/)/* || chw>=page->width*/)\r
1211         {\r
1212                 chw=0;\r
1213                 y+=w;\r
1214                 continue;\r
1215         }\r
1216         //load the letter 'A'\r
1217         __asm {\r
1218                 PUSHF\r
1219                 PUSH ES\r
1220                 PUSH AX\r
1221                 PUSH BX\r
1222                 PUSH CX\r
1223                 PUSH DX\r
1224                 PUSH SI\r
1225                 PUSH DI\r
1226 \r
1227                 MOV DI, addr\r
1228                 MOV SI, o\r
1229                 MOV ES, s\r
1230                 SUB AH, AH\r
1231                 MOV AL, c       ; the letter\r
1232                 MOV CX, w\r
1233                 MUL CX\r
1234                 ADD SI, AX      ;the address of charcter\r
1235         L1:     MOV AX, ES:SI\r
1236                 MOV DS:DI, AX\r
1237                 INC SI\r
1238                 INC DI\r
1239                 DEC CX\r
1240                 JNZ L1\r
1241 \r
1242                 POP DI\r
1243                 POP SI\r
1244                 POP DX\r
1245                 POP CX\r
1246                 POP BX\r
1247                 POP AX\r
1248                 POP ES\r
1249                 POPF\r
1250         }\r
1251 \r
1252                 for(i=0; i<w; i++)\r
1253                 {\r
1254                         j=1<<8;\r
1255                         xp=0;\r
1256                         while(j)\r
1257                         {\r
1258                                 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);\r
1259                                 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);\r
1260                                 xp++;\r
1261                                 j>>=1;\r
1262                         }\r
1263                 }\r
1264                 chw += xp;\r
1265         }\r
1266 }\r
1267 \r
1268 /* palette dump on display! */\r
1269 void modexpdump(nibble pagenum, global_game_variables_t *gvar)\r
1270 {\r
1271         int mult=(QUADWH);\r
1272         int palq=(mult)*TILEWH;\r
1273         int palcol=0;\r
1274         int palx, paly;\r
1275         for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){\r
1276                 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){\r
1277                                 modexClearRegion(&gvar->video.page[pagenum], palx+TILEWH, paly+TILEWH, mult, mult, palcol);\r
1278                         palcol++;\r
1279                 }\r
1280         }\r
1281         modexPalSave(gvar->video.palette);\r
1282 }\r
1283 #if 0\r
1284 /////////////////////////////////////////////////////////////////////////////\r
1285 //                                                                                                                                               //\r
1286 // cls() - This clears the screen to the specified color, on the VGA or on //\r
1287 //               the Virtual screen.                                                                                     //\r
1288 //                                                                                                                                               //\r
1289 /////////////////////////////////////////////////////////////////////////////\r
1290 void modexcls(page_t *page, byte color, byte *Where)\r
1291 {\r
1292         //modexClearRegion(page, 0, 0, page->width, page->height, color);\r
1293         /* set map mask to all 4 planes */\r
1294         outpw(SC_INDEX, 0xff02);\r
1295         //_fmemset(VGA, color, 16000);\r
1296         _fmemset(Where, color, page->stridew*page->height);\r
1297 }\r
1298 #endif\r
1299 //\r
1300 // pattern filler from joncampbell123's code\r
1301 //\r
1302 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)\r
1303 {\r
1304         unsigned int i,j,o,     d,h,s;\r
1305         word w;\r
1306 \r
1307         switch(sw)\r
1308         {\r
1309                 case 0:\r
1310                         w=vga_state.vga_width;\r
1311                         d=0;\r
1312                         s=vga_state.vga_stride;\r
1313                         switch(allsw)\r
1314                         {\r
1315                                 case 0:\r
1316                                         h=vga_state.vga_height;\r
1317                                 break;\r
1318                                 case 1:\r
1319                                         h=video->vh;\r
1320                                 break;\r
1321                         }\r
1322                 break;\r
1323                 default:\r
1324                         w=video->page[pn].width;\r
1325                         d=(0x10000UL - (uint16_t)video->page[pn].data);\r
1326                         s=video->page[pn].stridew;\r
1327                         switch(allsw)\r
1328                         {\r
1329                                 case 0:\r
1330                                         h=video->page[pn].height;\r
1331                                 break;\r
1332                                 case 1:\r
1333                                         if(!pn) h=video->vh;\r
1334                                         else h=video->page[pn].height;\r
1335                                 break;\r
1336                         }\r
1337                 break;\r
1338         }\r
1339 \r
1340         /* fill screen/pattern with a distinctive pattern */\r
1341         for (i=0;i < w;i++) {\r
1342                 o = (i >> 2) + d;\r
1343                 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));\r
1344                 for (j=0;j < h;j++,o += s)\r
1345                         vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!\r
1346         }\r
1347 }\r
1348 \r
1349 void\r
1350 modexWaitBorder() {\r
1351         while(inp(STATUS_REGISTER_1)  & 8)  {\r
1352         // spin\r
1353         }\r
1354 \r
1355         while(!(inp(STATUS_REGISTER_1)  & 8))  {\r
1356         //spin\r
1357         }\r
1358 }\r
1359 \r
1360 void\r
1361 modexWaitBorder_start()\r
1362 {\r
1363         while(inp(STATUS_REGISTER_1)  & 8)  {\r
1364         // spin\r
1365         }\r
1366 \r
1367 }\r
1368 \r
1369 void\r
1370 modexWaitBorder_end()\r
1371 {\r
1372         while(!(inp(STATUS_REGISTER_1)  & 8))  {\r
1373         // spin\r
1374         }\r
1375 \r
1376 }\r
1377 \r
1378 //===========================================================================\r
1379 \r
1380 //\r
1381 // printings of video memory information\r
1382 //\r
1383 void VL_PrintmodexmemInfo(video_t *v)\r
1384 {\r
1385         byte i;\r
1386 \r
1387 //      printf("========================================\n");\r
1388         printf("VL_PrintmodexmemInfo:\n");\r
1389 //      printf("========================================\n");\r
1390         printf("  Virtual Screen: %dx", v->page[0].width);      printf("%d      ", v->page[0].height);  printf("Tile: %dx", v->page[0].ti.tilesw);              printf("%d", v->page[0].ti.tilesh);     printf("=((Virtual Screen)/16)\n");\r
1391         printf("          Screen: %dx", v->page[0].sw);         printf("%d      ", v->page[0].sh);              printf("Tile: %dx", v->page[0].ti.tw);                  printf("%d", v->page[0].ti.th);         printf("=((Screen)/16)\n");\r
1392         printf("  stride: %u ", vga_state.vga_stride);\r
1393         printf("draw_stride: %u ", vga_state.vga_draw_stride);\r
1394         printf("draw_stride_limit: %u\n", vga_state.vga_draw_stride_limit);\r
1395 \r
1396         if(v->vmem_remain)\r
1397                 printf("  Free Video Memory: %u\n", v->vmem_remain);\r
1398         if(v->num_of_pages)\r
1399         {\r
1400         printf("  page");\r
1401                 for(i=0; i<v->num_of_pages;i++)\r
1402                 {\r
1403                         printf("        [%u]=", i);\r
1404                         printf("(%Fp)", (v->page[i].data));\r
1405                         printf(" size=%u        ", v->page[i].pagesize);\r
1406                         printf("w=%-3lu  h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);\r
1407                         printf("sw=%-3lu  sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);\r
1408                         printf("pi=%u", v->page[i].pi);\r
1409                         printf("\n");\r
1410                 }\r
1411         }\r
1412 }\r