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