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