]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_vl.c
p16 is being worked on a bunch by me wwww [16_ca needs huge amounts of work and I...
[16.git] / src / lib / 16_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(INPUT_STATUS_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(INPUT_STATUS_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(INPUT_STATUS_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(INPUT_STATUS_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 = m a l l o c(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 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)\r
920 {\r
921         VL_LoadPalFilewithoffset(filename, palette, 9, gvar);\r
922 //      VL_LoadPalFileCore(palette);\r
923 }\r
924 \r
925 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)\r
926 {\r
927         VL_LoadPalFilewithoffset("data/16.pal", palette, 0, gvar);\r
928 }\r
929 \r
930 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, global_game_variables_t *gvar)\r
931 {\r
932         int fd;\r
933 \r
934         fd = open(filename,O_RDONLY|O_BINARY);\r
935         if (fd >= 0) {\r
936                 read(fd,palette,        PAL_SIZE);\r
937                 close(fd);\r
938 \r
939                 VL_UpdatePaletteWrite(palette, o, gvar);\r
940         }\r
941 }\r
942 \r
943 void VL_UpdatePaletteWrite(byte *palette, word o, global_game_variables_t *gvar)\r
944 {\r
945         word i;\r
946         vga_palette_lseek(/*1+*/o);\r
947         //for (i=o;i < 256-o;i++)\r
948         for (i=0;i < 256-o;i++)\r
949                 vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);\r
950 \r
951         VL_PaletteSync(gvar);\r
952 }\r
953 \r
954 void VL_PaletteSync(global_game_variables_t *gvar)\r
955 {\r
956         modexPalSave(&gvar->video.palette);\r
957 }\r
958 \r
959 void\r
960 modexSavePalFile(char *filename, byte *pal) {\r
961         //unsigned int i;\r
962         FILE *file;\r
963 \r
964         /* open the file for writing */\r
965         file = fopen(filename, "wb");\r
966         if(!file) {\r
967         printf("Could not open %s for writing\n", filename);\r
968         }\r
969 \r
970         /* write the data to the file */\r
971         fwrite(pal, 1, PAL_SIZE, file);\r
972         fclose(file);\r
973 }\r
974 \r
975 \r
976 /* blanking */\r
977 void\r
978 modexPalBlack() {\r
979         fadePalette(-1, 64, 1, tmppal);\r
980 }\r
981 \r
982 \r
983 void\r
984 modexPalWhite() {\r
985         fadePalette(-1, -64, 1, tmppal);\r
986 }\r
987 \r
988 \r
989 /* utility */\r
990 //moved to 16_vlpal.c\r
991 \r
992 void\r
993 modexPalUpdate(byte *p)\r
994 {\r
995         int i;\r
996         //modexWaitBorder();\r
997         vga_wait_for_vsync();\r
998         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
999         for(i=0; i<PAL_SIZE/2; i++)\r
1000         {\r
1001                 outp(PAL_DATA_REG, p[i]);\r
1002         }\r
1003         //modexWaitBorder();      /* waits one retrace -- less flicker */\r
1004         vga_wait_for_vsync();\r
1005         for(; i<PAL_SIZE; i++)\r
1006         {\r
1007                 outp(PAL_DATA_REG, p[(i)]);\r
1008         }\r
1009 }\r
1010 \r
1011 void\r
1012 //modexPalUpdate0(byte *p)\r
1013 VL_modexPalScramble(byte *p)\r
1014 {\r
1015         int i;\r
1016         //modexWaitBorder();\r
1017         vga_wait_for_vsync();\r
1018         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
1019         for(i=0; i<PAL_SIZE/2; i++)\r
1020         {\r
1021                 outp(PAL_DATA_REG, rand());\r
1022         }\r
1023         //modexWaitBorder();      /* waits one retrace -- less flicker */\r
1024         vga_wait_for_vsync();\r
1025         for(; i<PAL_SIZE; i++)\r
1026         {\r
1027                 outp(PAL_DATA_REG, rand());\r
1028         }\r
1029 }\r
1030 \r
1031 word\r
1032 modexPalOverscan(word col)\r
1033 {\r
1034         //modexWaitBorder();\r
1035         vga_wait_for_vsync();\r
1036         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
1037         outp(PAL_DATA_REG, col);\r
1038         return col;\r
1039 }\r
1040 \r
1041 //check 16_vl_1.c\r
1042 \r
1043 void modexputPixel(page_t *page, int x, int y, byte color)\r
1044 {\r
1045         word pageOff = (word) page->data;\r
1046         /* Each address accesses four neighboring pixels, so set\r
1047            Write Plane Enable according to which pixel we want\r
1048            to modify.  The plane is determined by the two least\r
1049            significant bits of the x-coordinate: */\r
1050         modexSelectPlane(PLANE(x));\r
1051         //outp(SC_INDEX, 0x02);\r
1052         //outp(SC_DATA, 0x01 << (x & 3));\r
1053 \r
1054         /* The offset of the pixel into the video segment is\r
1055            offset = (width * y + x) / 4, and write the given\r
1056            color to the plane we selected above.  Heed the active\r
1057            page start selection. */\r
1058         VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;\r
1059 \r
1060 }\r
1061 \r
1062 byte modexgetPixel(page_t *page, int x, int y)\r
1063 {\r
1064         word pageOff = (word) page->data;\r
1065         /* Select the plane from which we must read the pixel color: */\r
1066         outpw(GC_INDEX, 0x04);\r
1067         outpw(GC_INDEX+1, x & 3);\r
1068 \r
1069         return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];\r
1070 \r
1071 }\r
1072 \r
1073 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)\r
1074 {\r
1075         /* vertical drawing routine by joncampbell123.\r
1076          *\r
1077          * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.\r
1078          * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.\r
1079          *\r
1080          * 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
1081         word rows = romFonts[t].charSize;\r
1082         word drawaddr;\r
1083         word colm, row;\r
1084         byte fontbyte;\r
1085         byte plane;\r
1086         byte m1,m2;\r
1087 \r
1088         plane = x & 3;\r
1089         m1 = 0x80; // left half\r
1090         m2 = 0x08; // right half\r
1091         for (colm=0;colm < 4;colm++) {\r
1092                 drawaddr = addr;\r
1093                 modexSelectPlane(PLANE(plane));\r
1094                 for (row=0;row < rows;row++) {\r
1095                         fontbyte = romFontsData.l[row];\r
1096                         vga_state.vga_graphics_ram[drawaddr  ] = (fontbyte & m1) ? col : bgcol;\r
1097                         vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;\r
1098                         drawaddr += page->width >> 2;\r
1099                 }\r
1100 \r
1101                 m1 >>= 1;\r
1102                 m2 >>= 1;\r
1103                 if ((++plane) == 4) {\r
1104                         addr++;\r
1105                         plane = 0;\r
1106                 }\r
1107         }\r
1108 }\r
1109 \r
1110 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)\r
1111 {\r
1112         word s, o, w;\r
1113         word x_draw;\r
1114         //word addr = (word) romFontsData.l;\r
1115         word addrq;\r
1116         word addrr;\r
1117         byte c;\r
1118 \r
1119         switch(sw)\r
1120         {\r
1121                 case 0:\r
1122                         printf("%s\n", str);\r
1123                 break;\r
1124                 case 1:\r
1125                         if(tlsw){ x-=page->tlx; y-=page->tly; }\r
1126                         x_draw = x/4;\r
1127                         addrq = (page->stridew) * y + (word)(x_draw) +\r
1128                                 ((word)page->data);\r
1129                         addrr = addrq;\r
1130                         s=romFonts[t].seg;\r
1131                         o=romFonts[t].off;\r
1132                         w=romFonts[t].charSize;\r
1133                         romFontsData.chw=0;\r
1134 \r
1135                         for(; *str != '\0'; str++)\r
1136                         {\r
1137                                 c = (*str);\r
1138                                 if(c=='\n')\r
1139                                 {\r
1140                                         x = x_draw;\r
1141                                         romFontsData.chw = 0;\r
1142                                         addrq += (page->stridew) * 8;\r
1143                                         addrr = addrq;\r
1144                                         y += 8;\r
1145                                         continue;\r
1146                                 }\r
1147 \r
1148                         // load the character into romFontsData.l\r
1149                         // no need for inline assembly!\r
1150                         // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.\r
1151                                 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);\r
1152                                 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);\r
1153                                 x_draw += 8; /* track X for edge of screen */\r
1154                                 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */\r
1155                         }\r
1156                         //printf("print xy:%dx%d        tlxy:%dx%d\n", x, y, page->tlx, page->tly);\r
1157                 break;\r
1158         }\r
1159 }\r
1160 \r
1161 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)\r
1162 {\r
1163         word i, s, o, w, j, xp;\r
1164         byte l[1024];\r
1165         word addr = (word) l;\r
1166         word chw=0;\r
1167         byte c;\r
1168 \r
1169         switch(t)\r
1170         {\r
1171                 case 0:\r
1172                         w=14;\r
1173                 break;\r
1174                 case 1:\r
1175                         w=8;\r
1176                 break;\r
1177                 case 2:\r
1178                         w=8;\r
1179                 break;\r
1180                 case 3:\r
1181                         w=16;\r
1182                 break;\r
1183                 default:\r
1184                         t=3;\r
1185                         w=16;\r
1186                 break;\r
1187         }\r
1188 \r
1189         s=romFonts[t].seg;\r
1190         o=romFonts[t].off;\r
1191 \r
1192         for(; *str != '\0'; str++)\r
1193         {\r
1194         c = (*str);\r
1195         if((c=='\n'/* || c=="\\r
1196 "*/)/* || chw>=page->width*/)\r
1197         {\r
1198                 chw=0;\r
1199                 y+=w;\r
1200                 continue;\r
1201         }\r
1202         //load the letter 'A'\r
1203         __asm {\r
1204                 PUSHF\r
1205                 PUSH ES\r
1206                 PUSH AX\r
1207                 PUSH BX\r
1208                 PUSH CX\r
1209                 PUSH DX\r
1210                 PUSH SI\r
1211                 PUSH DI\r
1212 \r
1213                 MOV DI, addr\r
1214                 MOV SI, o\r
1215                 MOV ES, s\r
1216                 SUB AH, AH\r
1217                 MOV AL, c       ; the letter\r
1218                 MOV CX, w\r
1219                 MUL CX\r
1220                 ADD SI, AX      ;the address of charcter\r
1221         L1:     MOV AX, ES:SI\r
1222                 MOV DS:DI, AX\r
1223                 INC SI\r
1224                 INC DI\r
1225                 DEC CX\r
1226                 JNZ L1\r
1227 \r
1228                 POP DI\r
1229                 POP SI\r
1230                 POP DX\r
1231                 POP CX\r
1232                 POP BX\r
1233                 POP AX\r
1234                 POP ES\r
1235                 POPF\r
1236         }\r
1237 \r
1238                 for(i=0; i<w; i++)\r
1239                 {\r
1240                         j=1<<8;\r
1241                         xp=0;\r
1242                         while(j)\r
1243                         {\r
1244                                 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);\r
1245                                 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);\r
1246                                 xp++;\r
1247                                 j>>=1;\r
1248                         }\r
1249                 }\r
1250                 chw += xp;\r
1251         }\r
1252 }\r
1253 \r
1254 /* palette dump on display! */\r
1255 void modexpdump(page_t *pee)\r
1256 {\r
1257         int mult=(QUADWH);\r
1258         int palq=(mult)*TILEWH;\r
1259         int palcol=0;\r
1260         int palx, paly;\r
1261         for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){\r
1262                 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){\r
1263                                 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);\r
1264                         palcol++;\r
1265                 }\r
1266         }\r
1267 }\r
1268 #if 0\r
1269 /////////////////////////////////////////////////////////////////////////////\r
1270 //                                                                                                                                               //\r
1271 // cls() - This clears the screen to the specified color, on the VGA or on //\r
1272 //               the Virtual screen.                                                                                     //\r
1273 //                                                                                                                                               //\r
1274 /////////////////////////////////////////////////////////////////////////////\r
1275 void modexcls(page_t *page, byte color, byte *Where)\r
1276 {\r
1277         //modexClearRegion(page, 0, 0, page->width, page->height, color);\r
1278         /* set map mask to all 4 planes */\r
1279         outpw(SC_INDEX, 0xff02);\r
1280         //_fmemset(VGA, color, 16000);\r
1281         _fmemset(Where, color, page->stridew*page->height);\r
1282 }\r
1283 #endif\r
1284 //\r
1285 // pattern filler from joncampbell123's code\r
1286 //\r
1287 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)\r
1288 {\r
1289         unsigned int i,j,o,     d,h,s;\r
1290         word w;\r
1291 \r
1292         switch(sw)\r
1293         {\r
1294                 case 0:\r
1295                         w=vga_state.vga_width;\r
1296                         d=0;\r
1297                         s=vga_state.vga_stride;\r
1298                         switch(allsw)\r
1299                         {\r
1300                                 case 0:\r
1301                                         h=vga_state.vga_height;\r
1302                                 break;\r
1303                                 case 1:\r
1304                                         h=video->vh;\r
1305                                 break;\r
1306                         }\r
1307                 break;\r
1308                 default:\r
1309                         w=video->page[pn].width;\r
1310                         d=(0x10000UL - (uint16_t)video->page[pn].data);\r
1311                         s=video->page[pn].stridew;\r
1312                         switch(allsw)\r
1313                         {\r
1314                                 case 0:\r
1315                                         h=video->page[pn].height;\r
1316                                 break;\r
1317                                 case 1:\r
1318                                         if(!pn) h=video->vh;\r
1319                                         else h=video->page[pn].height;\r
1320                                 break;\r
1321                         }\r
1322                 break;\r
1323         }\r
1324 \r
1325         /* fill screen/pattern with a distinctive pattern */\r
1326         for (i=0;i < w;i++) {\r
1327                 o = (i >> 2) + d;\r
1328                 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));\r
1329                 for (j=0;j < h;j++,o += s)\r
1330                         vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!\r
1331         }\r
1332 }\r
1333 \r
1334 void\r
1335 modexWaitBorder() {\r
1336         while(inp(INPUT_STATUS_1)  & 8)  {\r
1337         // spin\r
1338         }\r
1339 \r
1340         while(!(inp(INPUT_STATUS_1)  & 8))  {\r
1341         //spin\r
1342         }\r
1343 }\r
1344 \r
1345 void\r
1346 modexWaitBorder_start()\r
1347 {\r
1348         while(inp(INPUT_STATUS_1)  & 8)  {\r
1349         // spin\r
1350         }\r
1351 \r
1352 }\r
1353 \r
1354 void\r
1355 modexWaitBorder_end()\r
1356 {\r
1357         while(!(inp(INPUT_STATUS_1)  & 8))  {\r
1358         // spin\r
1359         }\r
1360 \r
1361 }\r
1362 \r
1363 //===========================================================================\r
1364 \r
1365 //\r
1366 // printings of video memory information\r
1367 //\r
1368 void VL_PrintmodexmemInfo(video_t *v)\r
1369 {\r
1370         byte i;\r
1371 \r
1372 //      printf("========================================\n");\r
1373         printf("VL_PrintmodexmemInfo:\n");\r
1374 //      printf("========================================\n");\r
1375         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
1376         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
1377         printf("  stride: %u ", vga_state.vga_stride);\r
1378         printf("draw_stride: %u ", vga_state.vga_draw_stride);\r
1379         printf("draw_stride_limit: %u\n", vga_state.vga_draw_stride_limit);\r
1380 \r
1381         if(v->vmem_remain)\r
1382                 printf("  Free Video Memory: %u\n", v->vmem_remain);\r
1383         if(v->num_of_pages)\r
1384         {\r
1385         printf("  page");\r
1386                 for(i=0; i<v->num_of_pages;i++)\r
1387                 {\r
1388                         printf("        [%u]=", i);\r
1389                         printf("(%Fp)", (v->page[i].data));\r
1390                         printf(" size=%u        ", v->page[i].pagesize);\r
1391                         printf("w=%-3lu  h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);\r
1392                         printf("sw=%-3lu  sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);\r
1393                         printf("pi=%u", v->page[i].pi);\r
1394                         printf("\n");\r
1395                 }\r
1396         }\r
1397 }\r