OSDN Git Service

having the palette in the game code may help. also i added wolf3d's palette for exama...
[proj16/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         gvar->video.page[0].tlx=gvar->mv[0].tx*TILEWH;\r
550         gvar->video.page[0].tly=gvar->mv[0].ty*TILEWH;\r
551 }\r
552 \r
553 //\r
554 // move page to appropriate part and show it\r
555 //\r
556 void\r
557 modexShowPage(page_t *page) {\r
558         word high_address, low_address, offset;\r
559         byte crtcOffset;\r
560 \r
561         /* calculate offset */\r
562         offset = (word) page->data;\r
563         offset += page[0].dy * (page->width >> 2 );\r
564         offset += page[0].dx >> 2;\r
565 \r
566         /* calculate crtcOffset according to virtual width */\r
567         crtcOffset = page->width >> 3;\r
568 \r
569         high_address = HIGH_ADDRESS | (offset & 0xff00);\r
570         low_address  = LOW_ADDRESS  | (offset << 8);\r
571 \r
572         /* wait for appropriate timing and then program CRTC */\r
573 //+=+=                                                                          while ((inp(STATUS_REGISTER_1) & DISPLAY_ENABLE));\r
574         outpw(CRTC_INDEX, high_address);\r
575         outpw(CRTC_INDEX, low_address);\r
576         outp(CRTC_INDEX, 0x13);\r
577         outp(CRTC_DATA, crtcOffset);\r
578 \r
579         /* wait for one retrace */\r
580 //+=+=                                                                          while (!(inp(STATUS_REGISTER_1) & VRETRACE));\r
581 \r
582         /* do PEL panning here */\r
583         outp(AC_INDEX, 0x33);\r
584         outp(AC_INDEX, (page[0].dx & 0x03) << 1);\r
585 }\r
586 \r
587 //args: page, vertical sync switch, screen resolution switch, page0 switch\r
588 void\r
589 VL_ShowPage(page_t *page, boolean vsync, boolean sr)\r
590 {\r
591         word high_address, low_address, offset;\r
592         byte crtcOffset;\r
593 \r
594         // calculate offset\r
595         offset = (word) page->data;\r
596         offset += page->dy * (page->width >> 2 );\r
597         offset += page->dx >> 2;\r
598 \r
599         // calculate crtcOffset according to virtual width\r
600         switch(sr)\r
601         {\r
602                 case 1:\r
603                         crtcOffset = page->sw >> 3;\r
604                 break;\r
605                 default:\r
606                 case 0:\r
607                         crtcOffset = page->width >> 3;\r
608                 break;\r
609         }\r
610 \r
611         high_address = HIGH_ADDRESS | (offset & 0xff00);\r
612         low_address  = LOW_ADDRESS  | (offset << 8);\r
613 \r
614         // wait for appropriate timing and then program CRTC\r
615         if(vsync) while ((inp(STATUS_REGISTER_1) & DISPLAY_ENABLE));\r
616         outpw(CRTC_INDEX, high_address);\r
617         outpw(CRTC_INDEX, low_address);\r
618         outp(CRTC_INDEX, 0x13);\r
619         outp(CRTC_DATA, crtcOffset);\r
620 \r
621         // wait for one retrace\r
622         if(vsync) while (!(inp(STATUS_REGISTER_1) & VRETRACE));\r
623 \r
624         // do PEL panning here\r
625         outp(AC_INDEX, 0x33);\r
626         outp(AC_INDEX, (page->dx & 0x03) << 1);\r
627         vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;\r
628         vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;\r
629 }\r
630 \r
631 //=============================================================================\r
632 \r
633 void\r
634 modexPanPage(page_t *page, int dx, int dy) {\r
635         page[0].dx = dx;\r
636         page[0].dy = dy;\r
637 }\r
638 \r
639 void\r
640 modexSelectPlane(byte plane) {\r
641         outp(SC_INDEX, SC_MAPMASK);       /* select plane */\r
642         outp(SC_DATA,  plane);\r
643 }\r
644 \r
645 void\r
646 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)\r
647 {\r
648         word pageOff = (word) page->data;\r
649         word xoff=(x>>2);                                                       // xoffset that begins each row\r
650         word poffset = pageOff + y*(page->stridew) + xoff;      // starting offset\r
651         word scanCount=w>>2;                                            // number of iterations per row (excluding right clip)\r
652         word nextRow = page->stridew-scanCount-1;               // loc of next row\r
653         LRCLIPDEF\r
654         byte left = lclip[x&0x03];\r
655         byte right = rclip[(x+w)&0x03];\r
656 \r
657         // handle the case which requires an extra group\r
658         if((x & 0x03) && !((x+w) & 0x03)) {\r
659                 right=0x0f;\r
660         }\r
661 \r
662         //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);\r
663 \r
664         __asm {\r
665                 PUSHF\r
666                 PUSH ES\r
667                 PUSH AX\r
668                 PUSH BX\r
669                 PUSH CX\r
670                 PUSH DX\r
671                 PUSH SI\r
672                 PUSH DI\r
673                 MOV AX, SCREEN_SEG        ; go to the VGA memory\r
674                 MOV ES, AX\r
675                 MOV DI, poffset  ; go to the first pixel\r
676                 MOV DX, SC_INDEX        ; point to the map mask\r
677                 MOV AL, SC_MAPMASK\r
678                 OUT DX, AL\r
679                 INC DX\r
680                 MOV AL, color      ; get ready to write colors\r
681         SCAN_START:\r
682                 MOV CX, scanCount          ; count the line\r
683                 MOV BL, AL                ; remember color\r
684                 MOV AL, left            ; do the left clip\r
685                 OUT DX, AL                ; set the left clip\r
686                 MOV AL, BL                ; restore color\r
687                 STOSB              ; write the color\r
688                 DEC CX\r
689                 JZ SCAN_DONE            ; handle 1 group stuff\r
690 \r
691                 ;-- write the main body of the scanline\r
692                 MOV BL, AL                ; remember color\r
693                 MOV AL, 0x0f            ; write to all pixels\r
694                 OUT DX, AL\r
695                 MOV AL, BL                ; restore color\r
696                 REP STOSB                  ; write the color\r
697         SCAN_DONE:\r
698                 MOV BL, AL                ; remeber color\r
699                 MOV AL, right\r
700                 OUT DX, AL                ; do the right clip\r
701                 MOV AL, BL                ; restore color\r
702                 STOSB              ; write pixel\r
703                 ADD DI, nextRow  ; go to the next row\r
704                 DEC h\r
705                 JNZ SCAN_START\r
706                 POP DI\r
707                 POP SI\r
708                 POP DX\r
709                 POP CX\r
710                 POP BX\r
711                 POP AX\r
712                 POP ES\r
713                 POPF\r
714         }\r
715 }\r
716 \r
717 /* moved to src/lib/modex16/16render.c */\r
718 \r
719 /* copy a region of video memory from one page to another.\r
720  * It assumes that the left edge of the tile is the same on both\r
721  * regions and the memory areas do not overlap.\r
722  */\r
723 void\r
724 modexCopyPageRegion(page_t *dest, page_t *src,\r
725                         word sx, word sy,\r
726                         word dx, word dy,\r
727                         word width, word height)\r
728 {\r
729         word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);\r
730         word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);\r
731         word scans      = vga_state.vga_stride+8;                               //++++0000 the quick and dirty fix of the major issue with p16 video display wwww\r
732         word nextSrcRow = src->stridew - scans - 1;\r
733         word nextDestRow = dest->stridew - scans - 1;\r
734         LRCLIPDEF\r
735         byte left = lclip[sx&0x03];\r
736         byte right = rclip[(sx+width)&0x03];\r
737 \r
738         // handle the case which requires an extra group\r
739         if((sx & 0x03) && !((sx+width) & 0x03)) {\r
740                 right=0x0f;\r
741         }\r
742 \r
743 //      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
744 \r
745         __asm {\r
746                 PUSHF\r
747                 PUSH ES\r
748                 PUSH AX\r
749                 PUSH BX\r
750                 PUSH CX\r
751                 PUSH DX\r
752                 PUSH SI\r
753                 PUSH DI\r
754 \r
755                 MOV AX, SCREEN_SEG        ; work in the vga space\r
756                 MOV ES, AX                ;\r
757                 MOV DI, doffset  ;\r
758                 MOV SI, soffset  ;\r
759 \r
760                 MOV DX, GC_INDEX        ; turn off cpu bits\r
761                 MOV AX, 0008h      ;\r
762                 OUT DX, AX\r
763 \r
764                 MOV AX, SC_INDEX        ; point to the mask register\r
765                 MOV DX, AX                ;\r
766                 MOV AL, SC_MAPMASK      ;\r
767                 OUT DX, AL                ;\r
768                 INC DX            ;\r
769 \r
770         ROW_START:\r
771                 PUSH DS\r
772                 MOV AX, ES\r
773                 MOV DS, AX\r
774                 MOV CX, scans      ; the number of latches\r
775 \r
776                 MOV AL, left            ; do the left column\r
777                 OUT DX, AL                ;\r
778                 MOVSB              ;\r
779                 DEC CX            ;\r
780 \r
781                 MOV AL, 0fh              ; do the inner columns\r
782                 OUT DX, AL\r
783                 REP MOVSB                  ; copy the pixels\r
784 \r
785                 MOV AL, right      ; do the right column\r
786                 OUT DX, AL\r
787                 MOVSB\r
788                 POP DS\r
789 \r
790                 MOV AX, SI                ; go the start of the next row\r
791                 ADD AX, nextSrcRow        ;\r
792                 MOV SI, AX                ;\r
793                 MOV AX, DI                ;\r
794                 ADD AX, nextDestRow      ;\r
795                 MOV DI, AX                ;\r
796 \r
797                 DEC height                ; do the rest of the actions\r
798                 JNZ ROW_START      ;\r
799 \r
800                 MOV DX, GC_INDEX+1        ; go back to CPU data\r
801                 MOV AL, 0ffh            ; none from latches\r
802                 OUT DX, AL                ;\r
803 \r
804                 POP DI\r
805                 POP SI\r
806                 POP DX\r
807                 POP CX\r
808                 POP BX\r
809                 POP AX\r
810                 POP ES\r
811                 POPF\r
812         }\r
813 }\r
814 \r
815 //check 16_vl_1.c\r
816 \r
817 /* fade and flash */\r
818 void\r
819 modexFadeOn(word fade, byte *palette) {\r
820         fadePalette(-fade, 64, 64/fade+1, palette);\r
821 }\r
822 \r
823 \r
824 void\r
825 modexFadeOff(word fade, byte *palette) {\r
826         fadePalette(fade, 0, 64/fade+1, palette);\r
827 }\r
828 \r
829 \r
830 void\r
831 modexFlashOn(word fade, byte *palette) {\r
832         fadePalette(fade, -64, 64/fade+1, palette);\r
833 }\r
834 \r
835 \r
836 void\r
837 modexFlashOff(word fade, byte *palette) {\r
838         fadePalette(-fade, 0, 64/fade+1, palette);\r
839 }\r
840 \r
841 \r
842 static void\r
843 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {\r
844         word i;\r
845         byte dim = start;\r
846 \r
847         /* handle the case where we just update */\r
848         if(iter == 0) {\r
849         modexPalUpdate(palette);\r
850         return;\r
851         }\r
852 \r
853         while(iter > 0) {  /* FadeLoop */\r
854         for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */\r
855                 tmppal[i] = palette[i] - dim;\r
856                 if(tmppal[i] > 127) {\r
857                 tmppal[i] = 0;\r
858                 } else if(tmppal[i] > 63) {\r
859                 tmppal[i] = 63;\r
860                 }\r
861         }\r
862         modexPalUpdate(tmppal);\r
863         iter--;\r
864         dim += fade;\r
865         }\r
866 }\r
867 \r
868 \r
869 // save and load\r
870 void modexPalSave(byte *palette)\r
871 {\r
872         int  i;\r
873 \r
874         outp(PAL_READ_REG, 0);                  // start at palette entry 0\r
875         for(i=0; i<PAL_SIZE; i++)\r
876         {\r
877                 palette[i] = inp(PAL_DATA_REG); // read the palette data\r
878         }\r
879 }\r
880 \r
881 \r
882 /*byte *\r
883 modexNewPal() {\r
884         byte *ptr;\r
885         ptr = mAlloc(PAL_SIZE);\r
886 \r
887         // handle errors\r
888         if(!ptr) {\r
889                 printf("Could not Allocate palette.\n");\r
890         }\r
891 \r
892         return ptr;\r
893 }*/\r
894 \r
895 \r
896 void\r
897 modexLoadPalFile(byte *filename, byte *palette) {\r
898         FILE *file;\r
899         byte *ptr;\r
900 \r
901         // free the palette if it exists\r
902         //if(*palette) { free(*palette); }\r
903 \r
904         // allocate the new palette\r
905         //*palette = modexNewPal();\r
906 \r
907         // open the file\r
908         file = fopen(filename, "rb");\r
909         if(!file) {\r
910                 printf("Could not open palette file: %s\n", filename);\r
911         }\r
912 \r
913         /* read the file */\r
914         ptr = palette;\r
915         while(!feof(file)) {\r
916         *ptr++ = fgetc(file);\r
917         }\r
918 \r
919         fclose(file);\r
920 }\r
921 \r
922 #define COREPALSIZE 9//27       //3*9\r
923 \r
924 void VLL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, word palsize, global_game_variables_t *gvar)\r
925 {\r
926         int fd;\r
927         byte *newpalette;\r
928 \r
929         fd = open(filename,O_RDONLY|O_BINARY);\r
930         if (fd >= 0) {\r
931                 read(fd,palette,        palsize*3);\r
932                 close(fd);\r
933 \r
934                 if(palsize==COREPALSIZE) newpalette = palette; else{    //if core then load it\r
935                 newpalette = &palette[3];                       //skip overscan color\r
936                 if(!o) o++;\r
937                 }\r
938                 VL_UpdatePaletteWrite(newpalette, o, palsize, gvar);\r
939         }\r
940 }\r
941 \r
942 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)\r
943 {\r
944         VLL_LoadPalFilewithoffset(filename, palette,\r
945                 0,                      //overwrite core/system palette\r
946 //              COREPALSIZE,    //preserved core/system palette\r
947                 PAL_SIZE/3, gvar);\r
948 }\r
949 \r
950 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)\r
951 {\r
952         VLL_LoadPalFilewithoffset("data/16.pal", palette, 0, COREPALSIZE, gvar);\r
953 }\r
954 \r
955 void VL_UpdatePaletteWrite(byte *palette, word o, word p, global_game_variables_t *gvar)\r
956 {\r
957         word i;\r
958 \r
959         vga_palette_lseek(o);\r
960         for (i=0;i < p-o;i++)\r
961                 vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);\r
962 \r
963         VL_PaletteSync(gvar);\r
964 }\r
965 \r
966 void VL_PaletteSync(global_game_variables_t *gvar)\r
967 {\r
968         modexPalSave(&gvar->video.palette);\r
969 }\r
970 \r
971 void\r
972 modexSavePalFile(char *filename, byte *pal) {\r
973         //unsigned int i;\r
974         FILE *file;\r
975 \r
976         /* open the file for writing */\r
977         file = fopen(filename, "wb");\r
978         if(!file) {\r
979         printf("Could not open %s for writing\n", filename);\r
980         }\r
981 \r
982         /* write the data to the file */\r
983         fwrite(pal, 1, PAL_SIZE, file);\r
984         fclose(file);\r
985 }\r
986 \r
987 \r
988 /* blanking */\r
989 void\r
990 modexPalBlack() {\r
991         fadePalette(-1, 64, 1, tmppal);\r
992 }\r
993 \r
994 \r
995 void\r
996 modexPalWhite() {\r
997         fadePalette(-1, -64, 1, tmppal);\r
998 }\r
999 \r
1000 \r
1001 /* utility */\r
1002 //moved to 16_vlpal.c\r
1003 \r
1004 void\r
1005 modexPalUpdate(byte *p)\r
1006 {\r
1007         int i;\r
1008         //modexWaitBorder();\r
1009         vga_wait_for_vsync();\r
1010         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
1011         for(i=0; i<PAL_SIZE/2; i++)\r
1012         {\r
1013                 outp(PAL_DATA_REG, p[i]);\r
1014         }\r
1015         //modexWaitBorder();      /* waits one retrace -- less flicker */\r
1016         vga_wait_for_vsync();\r
1017         for(; i<PAL_SIZE; i++)\r
1018         {\r
1019                 outp(PAL_DATA_REG, p[(i)]);\r
1020         }\r
1021 }\r
1022 \r
1023 void\r
1024 //modexPalUpdate0(byte *p)\r
1025 VL_modexPalScramble(byte *p)\r
1026 {\r
1027         int i;\r
1028         //modexWaitBorder();\r
1029         vga_wait_for_vsync();\r
1030         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
1031         for(i=0; i<PAL_SIZE/2; i++)\r
1032         {\r
1033                 outp(PAL_DATA_REG, rand());\r
1034         }\r
1035         //modexWaitBorder();      /* waits one retrace -- less flicker */\r
1036         vga_wait_for_vsync();\r
1037         for(; i<PAL_SIZE; i++)\r
1038         {\r
1039                 outp(PAL_DATA_REG, rand());\r
1040         }\r
1041 }\r
1042 \r
1043 word\r
1044 VL_modexPalOverscan(byte *p, word col)\r
1045 {\r
1046         int i;\r
1047         //modexWaitBorder();\r
1048         vga_wait_for_vsync();\r
1049         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
1050         for(i=col; i<(3+col); i++)\r
1051         {\r
1052                 outp(PAL_DATA_REG, p[i]);\r
1053         }\r
1054 //      modexPalSave(p);\r
1055         return col;\r
1056 }\r
1057 \r
1058 //check 16_vl_1.c\r
1059 \r
1060 void modexputPixel(page_t *page, int x, int y, byte color)\r
1061 {\r
1062         word pageOff = (word) page->data;\r
1063         /* Each address accesses four neighboring pixels, so set\r
1064            Write Plane Enable according to which pixel we want\r
1065            to modify.  The plane is determined by the two least\r
1066            significant bits of the x-coordinate: */\r
1067         modexSelectPlane(PLANE(x));\r
1068         //outp(SC_INDEX, 0x02);\r
1069         //outp(SC_DATA, 0x01 << (x & 3));\r
1070 \r
1071         /* The offset of the pixel into the video segment is\r
1072            offset = (width * y + x) / 4, and write the given\r
1073            color to the plane we selected above.  Heed the active\r
1074            page start selection. */\r
1075         VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;\r
1076 \r
1077 }\r
1078 \r
1079 byte modexgetPixel(page_t *page, int x, int y)\r
1080 {\r
1081         word pageOff = (word) page->data;\r
1082         /* Select the plane from which we must read the pixel color: */\r
1083         outpw(GC_INDEX, 0x04);\r
1084         outpw(GC_INDEX+1, x & 3);\r
1085 \r
1086         return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];\r
1087 \r
1088 }\r
1089 \r
1090 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)\r
1091 {\r
1092         /* vertical drawing routine by joncampbell123.\r
1093          *\r
1094          * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.\r
1095          * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.\r
1096          *\r
1097          * 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
1098         word rows = romFonts[t].charSize;\r
1099         word drawaddr;\r
1100         word colm, row;\r
1101         byte fontbyte;\r
1102         byte plane;\r
1103         byte m1,m2;\r
1104 \r
1105         plane = x & 3;\r
1106         m1 = 0x80; // left half\r
1107         m2 = 0x08; // right half\r
1108         for (colm=0;colm < 4;colm++) {\r
1109                 drawaddr = addr;\r
1110                 modexSelectPlane(PLANE(plane));\r
1111                 for (row=0;row < rows;row++) {\r
1112                         fontbyte = romFontsData.l[row];\r
1113                         vga_state.vga_graphics_ram[drawaddr  ] = (fontbyte & m1) ? col : bgcol;\r
1114                         vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;\r
1115                         drawaddr += page->width >> 2;\r
1116                 }\r
1117 \r
1118                 m1 >>= 1;\r
1119                 m2 >>= 1;\r
1120                 if ((++plane) == 4) {\r
1121                         addr++;\r
1122                         plane = 0;\r
1123                 }\r
1124         }\r
1125 }\r
1126 \r
1127 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word color, word bgcolor, boolean vidsw, const byte *str)\r
1128 {\r
1129         word s, o, w;\r
1130         word x_draw;\r
1131         //word addr = (word) romFontsData.l;\r
1132         word addrq;\r
1133         word addrr;\r
1134         byte c;\r
1135 \r
1136         switch(vidsw)\r
1137         {\r
1138                 case 0:\r
1139                         printf("%s\n", str);\r
1140                 break;\r
1141                 case 1:\r
1142                         if(tlsw){ x-=page->tlx; y-=page->tly; }\r
1143                         x_draw = x>>2;\r
1144                         addrq = (page->stridew) * y + (word)(x_draw) +\r
1145                                 ((word)page->data);\r
1146                         addrr = addrq;\r
1147                         s=romFonts[t].seg;\r
1148                         o=romFonts[t].off;\r
1149                         w=romFonts[t].charSize;\r
1150                         romFontsData.chw=0;\r
1151 \r
1152                         for(; *str != '\0'; str++)\r
1153                         {\r
1154                                 c = (*str);\r
1155                                 if(c=='\n')\r
1156                                 {\r
1157                                         x = x_draw;\r
1158                                         romFontsData.chw = 0;\r
1159                                         addrq += (page->stridew) * 8;\r
1160                                         addrr = addrq;\r
1161                                         y += 8;\r
1162                                         continue;\r
1163                                 }\r
1164 \r
1165                         // load the character into romFontsData.l\r
1166                         // no need for inline assembly!\r
1167                         // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.\r
1168                                 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);\r
1169                                 modexDrawChar(page, x_draw/*for mode X planar use*/, t, color, bgcolor, addrr);\r
1170                                 x_draw += 8; /* track X for edge of screen */\r
1171                                 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */\r
1172                         }\r
1173                         //printf("print xy:%dx%d        tlxy:%dx%d\n", x, y, page->tlx, page->tly);\r
1174                 break;\r
1175         }\r
1176 }\r
1177 \r
1178 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)\r
1179 {\r
1180         word i, s, o, w, j, xp;\r
1181         byte l[1024];\r
1182         word addr = (word) l;\r
1183         word chw=0;\r
1184         byte c;\r
1185 \r
1186         switch(t)\r
1187         {\r
1188                 case 0:\r
1189                         w=14;\r
1190                 break;\r
1191                 case 1:\r
1192                         w=8;\r
1193                 break;\r
1194                 case 2:\r
1195                         w=8;\r
1196                 break;\r
1197                 case 3:\r
1198                         w=16;\r
1199                 break;\r
1200                 default:\r
1201                         t=3;\r
1202                         w=16;\r
1203                 break;\r
1204         }\r
1205 \r
1206         s=romFonts[t].seg;\r
1207         o=romFonts[t].off;\r
1208 \r
1209         for(; *str != '\0'; str++)\r
1210         {\r
1211         c = (*str);\r
1212         if((c=='\n'/* || c=="\\r
1213 "*/)/* || chw>=page->width*/)\r
1214         {\r
1215                 chw=0;\r
1216                 y+=w;\r
1217                 continue;\r
1218         }\r
1219         //load the letter 'A'\r
1220         __asm {\r
1221                 PUSHF\r
1222                 PUSH ES\r
1223                 PUSH AX\r
1224                 PUSH BX\r
1225                 PUSH CX\r
1226                 PUSH DX\r
1227                 PUSH SI\r
1228                 PUSH DI\r
1229 \r
1230                 MOV DI, addr\r
1231                 MOV SI, o\r
1232                 MOV ES, s\r
1233                 SUB AH, AH\r
1234                 MOV AL, c       ; the letter\r
1235                 MOV CX, w\r
1236                 MUL CX\r
1237                 ADD SI, AX      ;the address of charcter\r
1238         L1:     MOV AX, ES:SI\r
1239                 MOV DS:DI, AX\r
1240                 INC SI\r
1241                 INC DI\r
1242                 DEC CX\r
1243                 JNZ L1\r
1244 \r
1245                 POP DI\r
1246                 POP SI\r
1247                 POP DX\r
1248                 POP CX\r
1249                 POP BX\r
1250                 POP AX\r
1251                 POP ES\r
1252                 POPF\r
1253         }\r
1254 \r
1255                 for(i=0; i<w; i++)\r
1256                 {\r
1257                         j=1<<8;\r
1258                         xp=0;\r
1259                         while(j)\r
1260                         {\r
1261                                 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);\r
1262                                 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);\r
1263                                 xp++;\r
1264                                 j>>=1;\r
1265                         }\r
1266                 }\r
1267                 chw += xp;\r
1268         }\r
1269 }\r
1270 \r
1271 //      short hand of modexprint\r
1272 void VL_print(const byte *str, nibble pagenum, global_game_variables_t *gvar)\r
1273 {\r
1274         modexprint(&(gvar->video.page[pagenum]), gvar->video.print.x, gvar->video.print.y, gvar->video.print.t, gvar->video.print.tlsw, gvar->video.print.color, gvar->video.print.bgcolor, gvar->video.VL_Started, str);\r
1275 }\r
1276 \r
1277 /* palette dump on display! */\r
1278 void modexpdump(nibble pagenum, global_game_variables_t *gvar)\r
1279 {\r
1280         int mult=(QUADWH);\r
1281         int palq=(mult)*TILEWH;\r
1282         int palcol=0;\r
1283         int palx, paly;\r
1284         for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){\r
1285                 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){\r
1286                                 modexClearRegion(&gvar->video.page[pagenum], palx+TILEWH, paly+TILEWH, mult, mult, palcol);\r
1287                         palcol++;\r
1288                 }\r
1289         }\r
1290         modexPalSave(gvar->video.palette);\r
1291 }\r
1292 #if 0\r
1293 /////////////////////////////////////////////////////////////////////////////\r
1294 //                                                                                                                                               //\r
1295 // cls() - This clears the screen to the specified color, on the VGA or on //\r
1296 //               the Virtual screen.                                                                                     //\r
1297 //                                                                                                                                               //\r
1298 /////////////////////////////////////////////////////////////////////////////\r
1299 void modexcls(page_t *page, byte color, byte *Where)\r
1300 {\r
1301         //modexClearRegion(page, 0, 0, page->width, page->height, color);\r
1302         /* set map mask to all 4 planes */\r
1303         outpw(SC_INDEX, 0xff02);\r
1304         //_fmemset(VGA, color, 16000);\r
1305         _fmemset(Where, color, page->stridew*page->height);\r
1306 }\r
1307 #endif\r
1308 //\r
1309 // pattern filler from joncampbell123's code\r
1310 //\r
1311 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)\r
1312 {\r
1313         unsigned int i,j,o,     d,h,s;\r
1314         word w;\r
1315 \r
1316         switch(sw)\r
1317         {\r
1318                 case 0:\r
1319                         w=vga_state.vga_width;\r
1320                         d=0;\r
1321                         s=vga_state.vga_stride;\r
1322                         switch(allsw)\r
1323                         {\r
1324                                 case 0:\r
1325                                         h=vga_state.vga_height;\r
1326                                 break;\r
1327                                 case 1:\r
1328                                         h=video->vh;\r
1329                                 break;\r
1330                         }\r
1331                 break;\r
1332                 default:\r
1333                         w=video->page[pn].width;\r
1334                         d=(0x10000UL - (uint16_t)video->page[pn].data);\r
1335                         s=video->page[pn].stridew;\r
1336                         switch(allsw)\r
1337                         {\r
1338                                 case 0:\r
1339                                         h=video->page[pn].height;\r
1340                                 break;\r
1341                                 case 1:\r
1342                                         if(!pn) h=video->vh;\r
1343                                         else h=video->page[pn].height;\r
1344                                 break;\r
1345                         }\r
1346                 break;\r
1347         }\r
1348 \r
1349         /* fill screen/pattern with a distinctive pattern */\r
1350         for (i=0;i < w;i++) {\r
1351                 o = (i >> 2) + d;\r
1352                 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));\r
1353                 for (j=0;j < h;j++,o += s)\r
1354                         vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!\r
1355         }\r
1356 }\r
1357 \r
1358 void\r
1359 modexWaitBorder() {\r
1360         while(inp(STATUS_REGISTER_1)  & 8)  {\r
1361         // spin\r
1362         }\r
1363 \r
1364         while(!(inp(STATUS_REGISTER_1)  & 8))  {\r
1365         //spin\r
1366         }\r
1367 }\r
1368 \r
1369 void\r
1370 modexWaitBorder_start()\r
1371 {\r
1372         while(inp(STATUS_REGISTER_1)  & 8)  {\r
1373         // spin\r
1374         }\r
1375 \r
1376 }\r
1377 \r
1378 void\r
1379 modexWaitBorder_end()\r
1380 {\r
1381         while(!(inp(STATUS_REGISTER_1)  & 8))  {\r
1382         // spin\r
1383         }\r
1384 \r
1385 }\r
1386 \r
1387 //===========================================================================\r
1388 \r
1389 //\r
1390 // printings of video memory information\r
1391 //\r
1392 void VL_PrintmodexmemInfo(video_t *v)\r
1393 {\r
1394         byte i;\r
1395 \r
1396 //      printf("========================================\n");\r
1397         printf("VL_PrintmodexmemInfo:\n");\r
1398 //      printf("========================================\n");\r
1399         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
1400         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
1401         printf("  vga_stride: %u ", vga_state.vga_stride);\r
1402         printf("pagestride: %u ", v->page[0].stridew);\r
1403         printf("draw_stride: %u ", vga_state.vga_draw_stride);\r
1404         printf("draw_stride_limit: %u\n", vga_state.vga_draw_stride_limit);\r
1405 \r
1406         if(v->vmem_remain)\r
1407                 printf("  Free Video Memory: %u\n", v->vmem_remain);\r
1408         if(v->num_of_pages)\r
1409         {\r
1410         printf("  page");\r
1411                 for(i=0; i<v->num_of_pages;i++)\r
1412                 {\r
1413                         printf("        [%u]=", i);\r
1414                         printf("(%Fp)", (v->page[i].data));\r
1415                         printf(" size=%u        ", v->page[i].pagesize);\r
1416                         printf("w=%-3lu  h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);\r
1417                         printf("sw=%-3lu  sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);\r
1418                         printf("pi=%u", v->page[i].pi);\r
1419                         printf("\n");\r
1420                 }\r
1421         }\r
1422 }\r