]> 4ch.mooo.com Git - 16.git/blob - src/lib/16_vl.c
XCROLL broken
[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 {\r
776         int i;\r
777         //modexWaitBorder();\r
778         vga_wait_for_vsync();\r
779         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
780         for(i=0; i<PAL_SIZE/2; i++)\r
781         {\r
782                 outp(PAL_DATA_REG, rand());\r
783         }\r
784         //modexWaitBorder();      /* waits one retrace -- less flicker */\r
785         vga_wait_for_vsync();\r
786         for(; i<PAL_SIZE; i++)\r
787         {\r
788                 outp(PAL_DATA_REG, rand());\r
789         }\r
790 }\r
791 \r
792 word\r
793 modexPalOverscan(word col)\r
794 {\r
795         //modexWaitBorder();\r
796         vga_wait_for_vsync();\r
797         outp(PAL_WRITE_REG, 0);  /* start at the beginning of palette */\r
798         outp(PAL_DATA_REG, col);\r
799         return col;\r
800 }\r
801 //check 16_vl_1.c\r
802 \r
803 void modexputPixel(page_t *page, int x, int y, byte color)\r
804 {\r
805         word pageOff = (word) page->data;\r
806         /* Each address accesses four neighboring pixels, so set\r
807            Write Plane Enable according to which pixel we want\r
808            to modify.  The plane is determined by the two least\r
809            significant bits of the x-coordinate: */\r
810         modexSelectPlane(PLANE(x));\r
811         //outp(SC_INDEX, 0x02);\r
812         //outp(SC_DATA, 0x01 << (x & 3));\r
813 \r
814         /* The offset of the pixel into the video segment is\r
815            offset = (width * y + x) / 4, and write the given\r
816            color to the plane we selected above.  Heed the active\r
817            page start selection. */\r
818         VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;\r
819 \r
820 }\r
821 \r
822 byte modexgetPixel(page_t *page, int x, int y)\r
823 {\r
824         word pageOff = (word) page->data;\r
825         /* Select the plane from which we must read the pixel color: */\r
826         outpw(GC_INDEX, 0x04);\r
827         outpw(GC_INDEX+1, x & 3);\r
828 \r
829         return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];\r
830 \r
831 }\r
832 \r
833 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)\r
834 {\r
835         /* vertical drawing routine by joncampbell123.\r
836          *\r
837          * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.\r
838          * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.\r
839          *\r
840          * 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
841         word rows = romFonts[t].charSize;\r
842         word drawaddr;\r
843         word colm, row;\r
844         byte fontbyte;\r
845         byte plane;\r
846         byte m1,m2;\r
847 \r
848         plane = x & 3;\r
849         m1 = 0x80; // left half\r
850         m2 = 0x08; // right half\r
851         for (colm=0;colm < 4;colm++) {\r
852                 drawaddr = addr;\r
853                 modexSelectPlane(PLANE(plane));\r
854                 for (row=0;row < rows;row++) {\r
855                         fontbyte = romFontsData.l[row];\r
856                         vga_state.vga_graphics_ram[drawaddr  ] = (fontbyte & m1) ? col : bgcol;\r
857                         vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;\r
858                         drawaddr += page->width >> 2;\r
859                 }\r
860 \r
861                 m1 >>= 1;\r
862                 m2 >>= 1;\r
863                 if ((++plane) == 4) {\r
864                         addr++;\r
865                         plane = 0;\r
866                 }\r
867         }\r
868 }\r
869 \r
870 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)\r
871 {\r
872         word s, o, w;\r
873         word x_draw;\r
874         //word addr = (word) romFontsData.l;\r
875         word addrq;\r
876         word addrr;\r
877         byte c;\r
878 \r
879         switch(sw)\r
880         {\r
881                 case 0:\r
882                         printf("%s\n", str);\r
883                 break;\r
884                 case 1:\r
885                         if(tlsw){ x-=page->tlx; y-=page->tly; }\r
886                         x_draw = x/4;\r
887                         addrq = (page->stridew) * y + (word)(x_draw) +\r
888                                 ((word)page->data);\r
889                         addrr = addrq;\r
890                         s=romFonts[t].seg;\r
891                         o=romFonts[t].off;\r
892                         w=romFonts[t].charSize;\r
893                         romFontsData.chw=0;\r
894 \r
895                         for(; *str != '\0'; str++)\r
896                         {\r
897                                 c = (*str);\r
898                                 if(c=='\n')\r
899                                 {\r
900                                         x = x_draw;\r
901                                         romFontsData.chw = 0;\r
902                                         addrq += (page->stridew) * 8;\r
903                                         addrr = addrq;\r
904                                         y += 8;\r
905                                         continue;\r
906                                 }\r
907 \r
908                         // load the character into romFontsData.l\r
909                         // no need for inline assembly!\r
910                         // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.\r
911                                 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);\r
912                                 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);\r
913                                 x_draw += 8; /* track X for edge of screen */\r
914                                 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */\r
915                         }\r
916                         //printf("print xy:%dx%d        tlxy:%dx%d\n", x, y, page->tlx, page->tly);\r
917                 break;\r
918         }\r
919 }\r
920 \r
921 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)\r
922 {\r
923         word i, s, o, w, j, xp;\r
924         byte l[1024];\r
925         word addr = (word) l;\r
926         word chw=0;\r
927         byte c;\r
928 \r
929         switch(t)\r
930         {\r
931                 case 0:\r
932                         w=14;\r
933                 break;\r
934                 case 1:\r
935                         w=8;\r
936                 break;\r
937                 case 2:\r
938                         w=8;\r
939                 break;\r
940                 case 3:\r
941                         w=16;\r
942                 break;\r
943                 default:\r
944                         t=3;\r
945                         w=16;\r
946                 break;\r
947         }\r
948 \r
949         s=romFonts[t].seg;\r
950         o=romFonts[t].off;\r
951 \r
952         for(; *str != '\0'; str++)\r
953         {\r
954         c = (*str);\r
955         if((c=='\n'/* || c=="\\r
956 "*/)/* || chw>=page->width*/)\r
957         {\r
958                 chw=0;\r
959                 y+=w;\r
960                 continue;\r
961         }\r
962         //load the letter 'A'\r
963         __asm {\r
964                 PUSHF\r
965                 PUSH ES\r
966                 PUSH AX\r
967                 PUSH BX\r
968                 PUSH CX\r
969                 PUSH DX\r
970                 PUSH SI\r
971                 PUSH DI\r
972 \r
973                 MOV DI, addr\r
974                 MOV SI, o\r
975                 MOV ES, s\r
976                 SUB AH, AH\r
977                 MOV AL, c       ; the letter\r
978                 MOV CX, w\r
979                 MUL CX\r
980                 ADD SI, AX      ;the address of charcter\r
981         L1:     MOV AX, ES:SI\r
982                 MOV DS:DI, AX\r
983                 INC SI\r
984                 INC DI\r
985                 DEC CX\r
986                 JNZ L1\r
987 \r
988                 POP DI\r
989                 POP SI\r
990                 POP DX\r
991                 POP CX\r
992                 POP BX\r
993                 POP AX\r
994                 POP ES\r
995                 POPF\r
996         }\r
997 \r
998                 for(i=0; i<w; i++)\r
999                 {\r
1000                         j=1<<8;\r
1001                         xp=0;\r
1002                         while(j)\r
1003                         {\r
1004                                 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);\r
1005                                 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);\r
1006                                 xp++;\r
1007                                 j>>=1;\r
1008                         }\r
1009                 }\r
1010                 chw += xp;\r
1011         }\r
1012 }\r
1013 \r
1014 /* palette dump on display! */\r
1015 void modexpdump(page_t *pee)\r
1016 {\r
1017         int mult=(QUADWH);\r
1018         int palq=(mult)*TILEWH;\r
1019         int palcol=0;\r
1020         int palx, paly;\r
1021         for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){\r
1022                 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){\r
1023                                 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);\r
1024                         palcol++;\r
1025                 }\r
1026         }\r
1027 }\r
1028 \r
1029 /////////////////////////////////////////////////////////////////////////////\r
1030 //                                                                                                                                               //\r
1031 // cls() - This clears the screen to the specified color, on the VGA or on //\r
1032 //               the Virtual screen.                                                                                     //\r
1033 //                                                                                                                                               //\r
1034 /////////////////////////////////////////////////////////////////////////////\r
1035 void modexcls(page_t *page, byte color, byte *Where)\r
1036 {\r
1037         //modexClearRegion(page, 0, 0, page->width, page->height, color);\r
1038         /* set map mask to all 4 planes */\r
1039         outpw(SC_INDEX, 0xff02);\r
1040         //_fmemset(VGA, color, 16000);\r
1041         _fmemset(Where, color, page->stridew*page->height);\r
1042 }\r
1043 \r
1044 //\r
1045 // pattern filler from joncampbell123's code\r
1046 //\r
1047 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)\r
1048 {\r
1049         unsigned int i,j,o,     d,h,s;\r
1050         word w;\r
1051 \r
1052         switch(sw)\r
1053         {\r
1054                 case 0:\r
1055                         w=vga_state.vga_width;\r
1056                         d=0;\r
1057                         s=vga_state.vga_stride;\r
1058                         switch(allsw)\r
1059                         {\r
1060                                 case 0:\r
1061                                         h=vga_state.vga_height;\r
1062                                 break;\r
1063                                 case 1:\r
1064                                         h=video->vh;\r
1065                                 break;\r
1066                         }\r
1067                 break;\r
1068                 default:\r
1069                         w=video->page[pn].width;\r
1070                         d=(0x10000UL - (uint16_t)video->page[pn].data);\r
1071                         s=video->page[pn].stridew;\r
1072                         switch(allsw)\r
1073                         {\r
1074                                 case 0:\r
1075                                         h=video->page[pn].height;\r
1076                                 break;\r
1077                                 case 1:\r
1078                                         if(!pn) h=video->vh;\r
1079                                         else h=video->page[pn].height;\r
1080                                 break;\r
1081                         }\r
1082                 break;\r
1083         }\r
1084 \r
1085         /* fill screen/pattern with a distinctive pattern */\r
1086         for (i=0;i < w;i++) {\r
1087                 o = (i >> 2) + d;\r
1088                 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));\r
1089                 for (j=0;j < h;j++,o += s)\r
1090                         vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!\r
1091         }\r
1092 }\r
1093 \r
1094 void\r
1095 modexWaitBorder() {\r
1096         while(inp(INPUT_STATUS_1)  & 8)  {\r
1097         // spin\r
1098         }\r
1099 \r
1100         while(!(inp(INPUT_STATUS_1)  & 8))  {\r
1101         //spin\r
1102         }\r
1103 }\r
1104 \r
1105 void\r
1106 modexWaitBorder_start()\r
1107 {\r
1108         while(inp(INPUT_STATUS_1)  & 8)  {\r
1109         // spin\r
1110         }\r
1111 \r
1112 }\r
1113 \r
1114 void\r
1115 modexWaitBorder_end()\r
1116 {\r
1117         while(!(inp(INPUT_STATUS_1)  & 8))  {\r
1118         // spin\r
1119         }\r
1120 \r
1121 }\r
1122 \r
1123 //===========================================================================\r
1124 \r
1125 //\r
1126 // printings of video memory information\r
1127 //\r
1128 void VL_PrintmodexmemInfo(video_t *v)\r
1129 {\r
1130         byte i;\r
1131 \r
1132 //      printf("========================================\n");\r
1133         printf("VL_PrintmodexmemInfo:\n");\r
1134 //      printf("========================================\n");\r
1135         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
1136         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
1137 \r
1138         printf("  Free Video Memory: %u\n", v->vmem_remain);\r
1139         printf("  page");\r
1140         for(i=0; i<v->num_of_pages;i++)\r
1141         {\r
1142                 printf("        [%u]=", i);\r
1143                 printf("(%Fp)", (v->page[i].data));\r
1144                 printf(" size=%u        ", v->page[i].pagesize);\r
1145                 printf("w=%-3lu  h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);\r
1146                 printf("sw=%-3lu  sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);\r
1147                 printf("pi=%u", v->page[i].pi);\r
1148                 printf("\n");\r
1149         }\r
1150 }\r