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