]> 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 {\r
369         word high_address, low_address, offset;\r
370         byte crtcOffset;\r
371 \r
372         // calculate offset\r
373         offset = (word) page->data;\r
374         offset += page->dy * (page->width >> 2 );\r
375         offset += page->dx >> 2;\r
376 \r
377         // calculate crtcOffset according to virtual width\r
378         switch(sr)\r
379         {\r
380                 case 1:\r
381                         crtcOffset = page->sw >> 3;\r
382                 break;\r
383                 default:\r
384                 case 0:\r
385                         crtcOffset = page->width >> 3;\r
386                 break;\r
387         }\r
388 \r
389         high_address = HIGH_ADDRESS | (offset & 0xff00);\r
390         low_address  = LOW_ADDRESS  | (offset << 8);\r
391 \r
392         // wait for appropriate timing and then program CRTC\r
393         if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));\r
394         outpw(CRTC_INDEX, high_address);\r
395         outpw(CRTC_INDEX, low_address);\r
396         outp(CRTC_INDEX, 0x13);\r
397         outp(CRTC_DATA, crtcOffset);\r
398 \r
399         // wait for one retrace\r
400         if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));\r
401 \r
402         // do PEL panning here\r
403         outp(AC_INDEX, 0x33);\r
404         outp(AC_INDEX, (page->dx & 0x03) << 1);\r
405         vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;\r
406         vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;\r
407 }\r
408 \r
409 //=============================================================================\r
410 \r
411 void\r
412 modexPanPage(page_t *page, int dx, int dy) {\r
413         page[0].dx = dx;\r
414         page[0].dy = dy;\r
415 }\r
416 \r
417 void\r
418 modexSelectPlane(byte plane) {\r
419         outp(SC_INDEX, SC_MAPMASK);       /* select plane */\r
420         outp(SC_DATA,  plane);\r
421 }\r
422 \r
423 void\r
424 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)\r
425 {\r
426         word pageOff = (word) page->data;\r
427         word xoff=(x>>2);                                                       // xoffset that begins each row\r
428         word poffset = pageOff + y*(page->stridew) + xoff;      // starting offset\r
429         word scanCount=w>>2;                                            // number of iterations per row (excluding right clip)\r
430         word nextRow = page->stridew-scanCount-1;               // loc of next row\r
431         LRCLIPDEF\r
432         byte left = lclip[x&0x03];\r
433         byte right = rclip[(x+w)&0x03];\r
434 \r
435         // handle the case which requires an extra group\r
436         if((x & 0x03) && !((x+w) & 0x03)) {\r
437                 right=0x0f;\r
438         }\r
439 \r
440         //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);\r
441 \r
442         __asm {\r
443                 PUSHF\r
444                 PUSH ES\r
445                 PUSH AX\r
446                 PUSH BX\r
447                 PUSH CX\r
448                 PUSH DX\r
449                 PUSH SI\r
450                 PUSH DI\r
451                 MOV AX, SCREEN_SEG        ; go to the VGA memory\r
452                 MOV ES, AX\r
453                 MOV DI, poffset  ; go to the first pixel\r
454                 MOV DX, SC_INDEX        ; point to the map mask\r
455                 MOV AL, SC_MAPMASK\r
456                 OUT DX, AL\r
457                 INC DX\r
458                 MOV AL, color      ; get ready to write colors\r
459         SCAN_START:\r
460                 MOV CX, scanCount          ; count the line\r
461                 MOV BL, AL                ; remember color\r
462                 MOV AL, left            ; do the left clip\r
463                 OUT DX, AL                ; set the left clip\r
464                 MOV AL, BL                ; restore color\r
465                 STOSB              ; write the color\r
466                 DEC CX\r
467                 JZ SCAN_DONE            ; handle 1 group stuff\r
468 \r
469                 ;-- write the main body of the scanline\r
470                 MOV BL, AL                ; remember color\r
471                 MOV AL, 0x0f            ; write to all pixels\r
472                 OUT DX, AL\r
473                 MOV AL, BL                ; restore color\r
474                 REP STOSB                  ; write the color\r
475         SCAN_DONE:\r
476                 MOV BL, AL                ; remeber color\r
477                 MOV AL, right\r
478                 OUT DX, AL                ; do the right clip\r
479                 MOV AL, BL                ; restore color\r
480                 STOSB              ; write pixel\r
481                 ADD DI, nextRow  ; go to the next row\r
482                 DEC h\r
483                 JNZ SCAN_START\r
484                 POP DI\r
485                 POP SI\r
486                 POP DX\r
487                 POP CX\r
488                 POP BX\r
489                 POP AX\r
490                 POP ES\r
491                 POPF\r
492         }\r
493 }\r
494 \r
495 /* moved to src/lib/modex16/16render.c */\r
496 \r
497 /* copy a region of video memory from one page to another.\r
498  * It assumes that the left edge of the tile is the same on both\r
499  * regions and the memory areas do not overlap.\r
500  */\r
501 void\r
502 modexCopyPageRegion(page_t *dest, page_t *src,\r
503                         word sx, word sy,\r
504                         word dx, word dy,\r
505                         word width, word height)\r
506 {\r
507         word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);\r
508         word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);\r
509         word scans      = vga_state.vga_stride+8;                               //++++0000 the quick and dirty fix of the major issue with p16 video display wwww\r
510         word nextSrcRow = src->stridew - scans - 1;\r
511         word nextDestRow = dest->stridew - scans - 1;\r
512         LRCLIPDEF\r
513         byte left = lclip[sx&0x03];\r
514         byte right = rclip[(sx+width)&0x03];\r
515 \r
516         // handle the case which requires an extra group\r
517         if((sx & 0x03) && !((sx+width) & 0x03)) {\r
518                 right=0x0f;\r
519         }\r
520 \r
521 //      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
522 \r
523         __asm {\r
524                 PUSHF\r
525                 PUSH ES\r
526                 PUSH AX\r
527                 PUSH BX\r
528                 PUSH CX\r
529                 PUSH DX\r
530                 PUSH SI\r
531                 PUSH DI\r
532 \r
533                 MOV AX, SCREEN_SEG        ; work in the vga space\r
534                 MOV ES, AX                ;\r
535                 MOV DI, doffset  ;\r
536                 MOV SI, soffset  ;\r
537 \r
538                 MOV DX, GC_INDEX        ; turn off cpu bits\r
539                 MOV AX, 0008h      ;\r
540                 OUT DX, AX\r
541 \r
542                 MOV AX, SC_INDEX        ; point to the mask register\r
543                 MOV DX, AX                ;\r
544                 MOV AL, SC_MAPMASK      ;\r
545                 OUT DX, AL                ;\r
546                 INC DX            ;\r
547 \r
548         ROW_START:\r
549                 PUSH DS\r
550                 MOV AX, ES\r
551                 MOV DS, AX\r
552                 MOV CX, scans      ; the number of latches\r
553 \r
554                 MOV AL, left            ; do the left column\r
555                 OUT DX, AL                ;\r
556                 MOVSB              ;\r
557                 DEC CX            ;\r
558 \r
559                 MOV AL, 0fh              ; do the inner columns\r
560                 OUT DX, AL\r
561                 REP MOVSB                  ; copy the pixels\r
562 \r
563                 MOV AL, right      ; do the right column\r
564                 OUT DX, AL\r
565                 MOVSB\r
566                 POP DS\r
567 \r
568                 MOV AX, SI                ; go the start of the next row\r
569                 ADD AX, nextSrcRow        ;\r
570                 MOV SI, AX                ;\r
571                 MOV AX, DI                ;\r
572                 ADD AX, nextDestRow      ;\r
573                 MOV DI, AX                ;\r
574 \r
575                 DEC height                ; do the rest of the actions\r
576                 JNZ ROW_START      ;\r
577 \r
578                 MOV DX, GC_INDEX+1        ; go back to CPU data\r
579                 MOV AL, 0ffh            ; none from latches\r
580                 OUT DX, AL                ;\r
581 \r
582                 POP DI\r
583                 POP SI\r
584                 POP DX\r
585                 POP CX\r
586                 POP BX\r
587                 POP AX\r
588                 POP ES\r
589                 POPF\r
590         }\r
591 }\r
592 \r
593 //check 16_vl_1.c\r
594 \r
595 /* fade and flash */\r
596 void\r
597 modexFadeOn(word fade, byte *palette) {\r
598         fadePalette(-fade, 64, 64/fade+1, palette);\r
599 }\r
600 \r
601 \r
602 void\r
603 modexFadeOff(word fade, byte *palette) {\r
604         fadePalette(fade, 0, 64/fade+1, palette);\r
605 }\r
606 \r
607 \r
608 void\r
609 modexFlashOn(word fade, byte *palette) {\r
610         fadePalette(fade, -64, 64/fade+1, palette);\r
611 }\r
612 \r
613 \r
614 void\r
615 modexFlashOff(word fade, byte *palette) {\r
616         fadePalette(-fade, 0, 64/fade+1, palette);\r
617 }\r
618 \r
619 \r
620 static void\r
621 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {\r
622         word i;\r
623         byte dim = start;\r
624 \r
625         /* handle the case where we just update */\r
626         if(iter == 0) {\r
627         modexPalUpdate(palette);\r
628         return;\r
629         }\r
630 \r
631         while(iter > 0) {  /* FadeLoop */\r
632         for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */\r
633                 tmppal[i] = palette[i] - dim;\r
634                 if(tmppal[i] > 127) {\r
635                 tmppal[i] = 0;\r
636                 } else if(tmppal[i] > 63) {\r
637                 tmppal[i] = 63;\r
638                 }\r
639         }\r
640         modexPalUpdate(tmppal);\r
641         iter--;\r
642         dim += fade;\r
643         }\r
644 }\r
645 \r
646 \r
647 /* save and load */\r
648 void\r
649 modexPalSave(byte *palette) {\r
650         int  i;\r
651 \r
652         outp(PAL_READ_REG, 0);    /* start at palette entry 0 */\r
653         for(i=0; i<PAL_SIZE; i++) {\r
654         palette[i] = inp(PAL_DATA_REG); /* read the palette data */\r
655         }\r
656 }\r
657 \r
658 \r
659 /*byte *\r
660 modexNewPal() {\r
661         byte *ptr;\r
662         ptr = m a l l o c(PAL_SIZE);\r
663 \r
664         // handle errors\r
665         if(!ptr) {\r
666                 printf("Could not allocate palette.\n");\r
667         }\r
668 \r
669         return ptr;\r
670 }*/\r
671 \r
672 \r
673 void\r
674 modexLoadPalFile(byte *filename, byte *palette) {\r
675         FILE *file;\r
676         byte *ptr;\r
677 \r
678         // free the palette if it exists\r
679         //if(*palette) { free(*palette); }\r
680 \r
681         // allocate the new palette\r
682         //*palette = modexNewPal();\r
683 \r
684         // open the file\r
685         file = fopen(filename, "rb");\r
686         if(!file) {\r
687                 printf("Could not open palette file: %s\n", filename);\r
688         }\r
689 \r
690         /* read the file */\r
691         ptr = palette;\r
692         while(!feof(file)) {\r
693         *ptr++ = fgetc(file);\r
694         }\r
695 \r
696         fclose(file);\r
697 }\r
698 \r
699 void VL_LoadPalFile(const char *filename, byte *palette)\r
700 {\r
701         VL_LoadPalFilewithoffset(filename, palette, 8);\r
702         VL_LoadPalFileCore(palette);\r
703 }\r
704 \r
705 void VL_LoadPalFileCore(byte *palette)\r
706 {\r
707         VL_LoadPalFilewithoffset("data/16.pal", palette, 0);\r
708 }\r
709 \r
710 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o)\r
711 {\r
712         int fd;\r
713 \r
714         fd = open(filename,O_RDONLY|O_BINARY);\r
715         if (fd >= 0) {\r
716                 read(fd,palette,        PAL_SIZE);\r
717                 close(fd);\r
718 \r
719                 VL_UpdatePaletteWrite(palette, o);\r
720         }\r
721 }\r
722 \r
723 void VL_UpdatePaletteWrite(byte *palette, word o)\r
724 {\r
725         word i;\r
726         vga_palette_lseek(/*1+*/o);\r
727         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
728 }\r
729 \r
730 void\r
731 modexSavePalFile(char *filename, byte *pal) {\r
732         //unsigned int i;\r
733         FILE *file;\r
734 \r
735         /* open the file for writing */\r
736         file = fopen(filename, "wb");\r
737         if(!file) {\r
738         printf("Could not open %s for writing\n", filename);\r
739         }\r
740 \r
741         /* write the data to the file */\r
742         fwrite(pal, 1, PAL_SIZE, file);\r
743         fclose(file);\r
744 }\r
745 \r
746 \r
747 /* blanking */\r
748 void\r
749 modexPalBlack() {\r
750         fadePalette(-1, 64, 1, tmppal);\r
751 }\r
752 \r
753 \r
754 void\r
755 modexPalWhite() {\r
756         fadePalette(-1, -64, 1, tmppal);\r
757 }\r
758 \r
759 \r
760 /* utility */\r
761 //moved to 16_vlpal.c\r
762 \r
763 void\r
764 modexPalUpdate(byte *p)\r
765 {\r
766         int i;\r
767         //modexWaitBorder();\r
768         vga_wait_for_vsync();\r
769         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
770         for(i=0; i<PAL_SIZE/2; i++)\r
771         {\r
772                 outp(PAL_DATA_REG, p[i]);\r
773         }\r
774         //modexWaitBorder();      /* waits one retrace -- less flicker */\r
775         vga_wait_for_vsync();\r
776         for(; i<PAL_SIZE; i++)\r
777         {\r
778                 outp(PAL_DATA_REG, p[(i)]);\r
779         }\r
780 }\r
781 \r
782 void\r
783 //modexPalUpdate0(byte *p)\r
784 VL_modexPalScramble(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, rand());\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, rand());\r
799         }\r
800 }\r
801 \r
802 word\r
803 modexPalOverscan(word col)\r
804 {\r
805         //modexWaitBorder();\r
806         vga_wait_for_vsync();\r
807         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
808         outp(PAL_DATA_REG, col);\r
809         return col;\r
810 }\r
811 //check 16_vl_1.c\r
812 \r
813 void modexputPixel(page_t *page, int x, int y, byte color)\r
814 {\r
815         word pageOff = (word) page->data;\r
816         /* Each address accesses four neighboring pixels, so set\r
817            Write Plane Enable according to which pixel we want\r
818            to modify.  The plane is determined by the two least\r
819            significant bits of the x-coordinate: */\r
820         modexSelectPlane(PLANE(x));\r
821         //outp(SC_INDEX, 0x02);\r
822         //outp(SC_DATA, 0x01 << (x & 3));\r
823 \r
824         /* The offset of the pixel into the video segment is\r
825            offset = (width * y + x) / 4, and write the given\r
826            color to the plane we selected above.  Heed the active\r
827            page start selection. */\r
828         VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;\r
829 \r
830 }\r
831 \r
832 byte modexgetPixel(page_t *page, int x, int y)\r
833 {\r
834         word pageOff = (word) page->data;\r
835         /* Select the plane from which we must read the pixel color: */\r
836         outpw(GC_INDEX, 0x04);\r
837         outpw(GC_INDEX+1, x & 3);\r
838 \r
839         return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];\r
840 \r
841 }\r
842 \r
843 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)\r
844 {\r
845         /* vertical drawing routine by joncampbell123.\r
846          *\r
847          * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.\r
848          * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.\r
849          *\r
850          * 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
851         word rows = romFonts[t].charSize;\r
852         word drawaddr;\r
853         word colm, row;\r
854         byte fontbyte;\r
855         byte plane;\r
856         byte m1,m2;\r
857 \r
858         plane = x & 3;\r
859         m1 = 0x80; // left half\r
860         m2 = 0x08; // right half\r
861         for (colm=0;colm < 4;colm++) {\r
862                 drawaddr = addr;\r
863                 modexSelectPlane(PLANE(plane));\r
864                 for (row=0;row < rows;row++) {\r
865                         fontbyte = romFontsData.l[row];\r
866                         vga_state.vga_graphics_ram[drawaddr  ] = (fontbyte & m1) ? col : bgcol;\r
867                         vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;\r
868                         drawaddr += page->width >> 2;\r
869                 }\r
870 \r
871                 m1 >>= 1;\r
872                 m2 >>= 1;\r
873                 if ((++plane) == 4) {\r
874                         addr++;\r
875                         plane = 0;\r
876                 }\r
877         }\r
878 }\r
879 \r
880 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)\r
881 {\r
882         word s, o, w;\r
883         word x_draw;\r
884         //word addr = (word) romFontsData.l;\r
885         word addrq;\r
886         word addrr;\r
887         byte c;\r
888 \r
889         switch(sw)\r
890         {\r
891                 case 0:\r
892                         printf("%s\n", str);\r
893                 break;\r
894                 case 1:\r
895                         if(tlsw){ x-=page->tlx; y-=page->tly; }\r
896                         x_draw = x/4;\r
897                         addrq = (page->stridew) * y + (word)(x_draw) +\r
898                                 ((word)page->data);\r
899                         addrr = addrq;\r
900                         s=romFonts[t].seg;\r
901                         o=romFonts[t].off;\r
902                         w=romFonts[t].charSize;\r
903                         romFontsData.chw=0;\r
904 \r
905                         for(; *str != '\0'; str++)\r
906                         {\r
907                                 c = (*str);\r
908                                 if(c=='\n')\r
909                                 {\r
910                                         x = x_draw;\r
911                                         romFontsData.chw = 0;\r
912                                         addrq += (page->stridew) * 8;\r
913                                         addrr = addrq;\r
914                                         y += 8;\r
915                                         continue;\r
916                                 }\r
917 \r
918                         // load the character into romFontsData.l\r
919                         // no need for inline assembly!\r
920                         // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.\r
921                                 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);\r
922                                 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);\r
923                                 x_draw += 8; /* track X for edge of screen */\r
924                                 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */\r
925                         }\r
926                         //printf("print xy:%dx%d        tlxy:%dx%d\n", x, y, page->tlx, page->tly);\r
927                 break;\r
928         }\r
929 }\r
930 \r
931 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)\r
932 {\r
933         word i, s, o, w, j, xp;\r
934         byte l[1024];\r
935         word addr = (word) l;\r
936         word chw=0;\r
937         byte c;\r
938 \r
939         switch(t)\r
940         {\r
941                 case 0:\r
942                         w=14;\r
943                 break;\r
944                 case 1:\r
945                         w=8;\r
946                 break;\r
947                 case 2:\r
948                         w=8;\r
949                 break;\r
950                 case 3:\r
951                         w=16;\r
952                 break;\r
953                 default:\r
954                         t=3;\r
955                         w=16;\r
956                 break;\r
957         }\r
958 \r
959         s=romFonts[t].seg;\r
960         o=romFonts[t].off;\r
961 \r
962         for(; *str != '\0'; str++)\r
963         {\r
964         c = (*str);\r
965         if((c=='\n'/* || c=="\\r
966 "*/)/* || chw>=page->width*/)\r
967         {\r
968                 chw=0;\r
969                 y+=w;\r
970                 continue;\r
971         }\r
972         //load the letter 'A'\r
973         __asm {\r
974                 PUSHF\r
975                 PUSH ES\r
976                 PUSH AX\r
977                 PUSH BX\r
978                 PUSH CX\r
979                 PUSH DX\r
980                 PUSH SI\r
981                 PUSH DI\r
982 \r
983                 MOV DI, addr\r
984                 MOV SI, o\r
985                 MOV ES, s\r
986                 SUB AH, AH\r
987                 MOV AL, c       ; the letter\r
988                 MOV CX, w\r
989                 MUL CX\r
990                 ADD SI, AX      ;the address of charcter\r
991         L1:     MOV AX, ES:SI\r
992                 MOV DS:DI, AX\r
993                 INC SI\r
994                 INC DI\r
995                 DEC CX\r
996                 JNZ L1\r
997 \r
998                 POP DI\r
999                 POP SI\r
1000                 POP DX\r
1001                 POP CX\r
1002                 POP BX\r
1003                 POP AX\r
1004                 POP ES\r
1005                 POPF\r
1006         }\r
1007 \r
1008                 for(i=0; i<w; i++)\r
1009                 {\r
1010                         j=1<<8;\r
1011                         xp=0;\r
1012                         while(j)\r
1013                         {\r
1014                                 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);\r
1015                                 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);\r
1016                                 xp++;\r
1017                                 j>>=1;\r
1018                         }\r
1019                 }\r
1020                 chw += xp;\r
1021         }\r
1022 }\r
1023 \r
1024 /* palette dump on display! */\r
1025 void modexpdump(page_t *pee)\r
1026 {\r
1027         int mult=(QUADWH);\r
1028         int palq=(mult)*TILEWH;\r
1029         int palcol=0;\r
1030         int palx, paly;\r
1031         for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){\r
1032                 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){\r
1033                                 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);\r
1034                         palcol++;\r
1035                 }\r
1036         }\r
1037 }\r
1038 \r
1039 /////////////////////////////////////////////////////////////////////////////\r
1040 //                                                                                                                                               //\r
1041 // cls() - This clears the screen to the specified color, on the VGA or on //\r
1042 //               the Virtual screen.                                                                                     //\r
1043 //                                                                                                                                               //\r
1044 /////////////////////////////////////////////////////////////////////////////\r
1045 void modexcls(page_t *page, byte color, byte *Where)\r
1046 {\r
1047         //modexClearRegion(page, 0, 0, page->width, page->height, color);\r
1048         /* set map mask to all 4 planes */\r
1049         outpw(SC_INDEX, 0xff02);\r
1050         //_fmemset(VGA, color, 16000);\r
1051         _fmemset(Where, color, page->stridew*page->height);\r
1052 }\r
1053 \r
1054 //\r
1055 // pattern filler from joncampbell123's code\r
1056 //\r
1057 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)\r
1058 {\r
1059         unsigned int i,j,o,     d,h,s;\r
1060         word w;\r
1061 \r
1062         switch(sw)\r
1063         {\r
1064                 case 0:\r
1065                         w=vga_state.vga_width;\r
1066                         d=0;\r
1067                         s=vga_state.vga_stride;\r
1068                         switch(allsw)\r
1069                         {\r
1070                                 case 0:\r
1071                                         h=vga_state.vga_height;\r
1072                                 break;\r
1073                                 case 1:\r
1074                                         h=video->vh;\r
1075                                 break;\r
1076                         }\r
1077                 break;\r
1078                 default:\r
1079                         w=video->page[pn].width;\r
1080                         d=(0x10000UL - (uint16_t)video->page[pn].data);\r
1081                         s=video->page[pn].stridew;\r
1082                         switch(allsw)\r
1083                         {\r
1084                                 case 0:\r
1085                                         h=video->page[pn].height;\r
1086                                 break;\r
1087                                 case 1:\r
1088                                         if(!pn) h=video->vh;\r
1089                                         else h=video->page[pn].height;\r
1090                                 break;\r
1091                         }\r
1092                 break;\r
1093         }\r
1094 \r
1095         /* fill screen/pattern with a distinctive pattern */\r
1096         for (i=0;i < w;i++) {\r
1097                 o = (i >> 2) + d;\r
1098                 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));\r
1099                 for (j=0;j < h;j++,o += s)\r
1100                         vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!\r
1101         }\r
1102 }\r
1103 \r
1104 void\r
1105 modexWaitBorder() {\r
1106         while(inp(INPUT_STATUS_1)  & 8)  {\r
1107         // spin\r
1108         }\r
1109 \r
1110         while(!(inp(INPUT_STATUS_1)  & 8))  {\r
1111         //spin\r
1112         }\r
1113 }\r
1114 \r
1115 void\r
1116 modexWaitBorder_start()\r
1117 {\r
1118         while(inp(INPUT_STATUS_1)  & 8)  {\r
1119         // spin\r
1120         }\r
1121 \r
1122 }\r
1123 \r
1124 void\r
1125 modexWaitBorder_end()\r
1126 {\r
1127         while(!(inp(INPUT_STATUS_1)  & 8))  {\r
1128         // spin\r
1129         }\r
1130 \r
1131 }\r
1132 \r
1133 //===========================================================================\r
1134 \r
1135 //\r
1136 // printings of video memory information\r
1137 //\r
1138 void VL_PrintmodexmemInfo(video_t *v)\r
1139 {\r
1140         byte i;\r
1141 \r
1142 //      printf("========================================\n");\r
1143         printf("VL_PrintmodexmemInfo:\n");\r
1144 //      printf("========================================\n");\r
1145         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
1146         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
1147 \r
1148         printf("  Free Video Memory: %u\n", v->vmem_remain);\r
1149         printf("  page");\r
1150         for(i=0; i<v->num_of_pages;i++)\r
1151         {\r
1152                 printf("        [%u]=", i);\r
1153                 printf("(%Fp)", (v->page[i].data));\r
1154                 printf(" size=%u        ", v->page[i].pagesize);\r
1155                 printf("w=%-3lu  h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);\r
1156                 printf("sw=%-3lu  sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);\r
1157                 printf("pi=%u", v->page[i].pi);\r
1158                 printf("\n");\r
1159         }\r
1160 }\r