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