1 /* Project 16 Source Code~
\r
2 * Copyright (C) 2012-2017 sparky4 & pngwen & andrius4669 & joncampbell123 & yakui-lover
\r
4 * This file is part of Project 16.
\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
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
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
26 #include "src/lib/16_vl.h"
\r
28 byte far* VGA=(byte far*) 0xA0000000; /* this points to video memory. */
\r
30 static void fadePalette(sbyte fade, sbyte start, word iter, byte *palette);
\r
31 static byte tmppal[PAL_SIZE];
\r
33 //===========================================================================
\r
36 =======================
\r
40 =======================
\r
43 void VL_Startup (global_game_variables_t *gvar)
\r
47 VGAmodeX(1/*TODO other modes*/, 1, gvar);
\r
48 VL_LoadPalFileCore(gvar->video.palette, gvar);
\r
49 //Quit ("Improper video card! If you really have a VGA card that I am not\ndetecting it!", gvar);
\r
55 =======================
\r
59 =======================
\r
62 void VL_Shutdown (global_game_variables_t *gvar)
\r
64 VGAmodeX(0, 1, gvar);
\r
68 =======================
\r
70 = VL_SetVGAPlaneMode
\r
72 =======================
\r
75 void VL_SetVGAPlaneMode (global_game_variables_t *gvar)
\r
77 VL_vgaSetMode(VGA_256_COLOR_MODE);
\r
80 VL_SetLineWidth (40, &gvar->video.ofs);
\r
84 //===========================================================================
\r
91 = Fill the entire video buffer with a given color
\r
96 void VL_ClearVideo (byte color)
\r
104 and al,0xfc // write mode 0 to store directly to video
\r
108 mov ax,SC_MAPMASK+15*256
\r
109 out dx,ax // write through all four planes
\r
115 mov cx,0x8000 // 0x8000 words, clearing 8 video bytes/word
\r
122 =============================================================================
\r
124 VGA REGISTER MANAGEMENT ROUTINES
\r
126 =============================================================================
\r
138 void VL_DePlaneVGA (void)
\r
142 // change CPU addressing to non linear mode
\r
146 // turn off chain 4 and odd/even
\r
148 outportb (SC_INDEX,SC_MEMMODE);
\r
149 outportb (SC_INDEX+1,(inportb(SC_INDEX+1)&~8)|4);
\r
151 outportb (SC_INDEX,SC_MAPMASK); // leave this set throughought
\r
154 // turn off odd/even and set write mode 0
\r
156 outportb (GC_INDEX,GC_MODE);
\r
157 outportb (GC_INDEX+1,inportb(GC_INDEX+1)&~0x13);
\r
162 outportb (GC_INDEX,GC_MISCELLANEOUS);
\r
163 outportb (GC_INDEX+1,inportb(GC_INDEX+1)&~2);
\r
166 // clear the entire buffer space, because int 10h only did 16 k / plane
\r
171 // change CRTC scanning from doubleword to byte mode, allowing >64k scans
\r
173 outportb (CRTC_INDEX,CRTC_UNDERLINE);
\r
174 outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1)&~0x40);
\r
176 outportb (CRTC_INDEX,CRTC_MODE);
\r
177 outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1)|0x40);
\r
180 //===========================================================================
\r
183 ====================
\r
185 = VL_SetSplitScreen
\r
187 ====================
\r
190 void VL_SetSplitScreen (int linenum)
\r
193 linenum=linenum*2-1;
\r
194 outportb (CRTC_INDEX,CRTC_LINECOMPARE);
\r
195 outportb (CRTC_INDEX+1,linenum % 256);
\r
196 outportb (CRTC_INDEX,CRTC_OVERFLOW);
\r
197 outportb (CRTC_INDEX+1, 1+16*(linenum/256));
\r
198 outportb (CRTC_INDEX,CRTC_MAXSCANLINE);
\r
199 outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1) & (255-64));
\r
202 /////////////////////////////////////////////////////////////////////////////
\r
204 // setvideo() - This function Manages the video modes //
\r
206 /////////////////////////////////////////////////////////////////////////////
\r
207 void VGAmodeX(sword vq, boolean cmem, global_game_variables_t *gv)
\r
209 union REGS in, out;
\r
213 case 0: // deinit the video
\r
214 // change to the video mode we were in before we switched to mode 13h
\r
215 if(gv->video.VL_Started)
\r
219 in.h.al = gv->video.old_mode;
\r
220 int86(0x10, &in, &out);
\r
222 gv->video.VL_Started=0;
\r
224 default: // init the video
\r
225 if(gv->video.VL_Started)
\r
227 if(!gv->video.VL_Initiated)
\r
229 // get old video mode
\r
231 //int86(0x10, &in, &out);
\r
232 gv->video.old_mode = VL_vgaGetMode();//out.h.al;
\r
234 modexEnter(vq, cmem, gv);
\r
239 //---------------------------------------------------
\r
241 // Use the bios to set the current video mode
\r
245 VL_vgaSetMode(byte mode)
\r
249 regs.h.ah = SET_MODE;
\r
251 int86(VIDEO_INT, ®s, ®s);
\r
254 //---------------------------------------------------
\r
256 // Use the bios to get the current video mode
\r
260 VL_vgaGetMode(void)
\r
262 return int10_getmode();
\r
265 /* -========================= Entry Points ==========================- */
\r
266 void modexEnter(sword vq, boolean cmem, global_game_variables_t *gv)
\r
269 struct vga_mode_params cm;
\r
270 //int CRTParmCount;
\r
272 VL_vgaSetMode(VGA_256_COLOR_MODE);
\r
273 vga_enable_256color_modex();
\r
275 update_state_from_vga();
\r
276 vga_read_crtc_mode(&cm);
\r
278 /* reprogram the CRT controller */
\r
279 //outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */
\r
280 //outp(CRTC_DATA, 0x7f); /* get current write protect on varios regs */
\r
285 case 8: //320x240 no buffer
\r
286 //CRTParmCount = sizeof(ModeX_320x240regs) / sizeof(ModeX_320x240regs[0]);
\r
287 /*for(i=0; i<CRTParmCount; i++) {
\r
288 outpw(CRTC_INDEX, ModeX_320x240regs[i]);
\r
290 // width and height //
\r
291 gv->video.page[0].sw = vga_state.vga_width = 320; // VGA lib currently does not update this
\r
292 gv->video.page[0].sh = vga_state.vga_height = 240; // VGA lib currently does not update this
\r
293 // virtual width and height. match screen, at first //
\r
294 gv->video.page[0].height = gv->video.page[0].sh;
\r
295 gv->video.page[0].width = gv->video.page[0].sw;
\r
297 // mode X BYTE mode
\r
300 // 320x240 mode 60Hz
\r
301 cm.horizontal_total=0x5f + 5; /* CRTC[0] -5 */
\r
302 cm.horizontal_display_end=0x4f + 1; /* CRTC[1] -1 */
\r
303 cm.horizontal_blank_start=0x50 + 1; /* CRTC[2] */
\r
304 // cm.horizontal_blank_end=0x82 + 1; /* CRTC[3] bit 0-4 & CRTC[5] bit 7 *///skewing ^^;
\r
305 cm.horizontal_start_retrace=0x54;/* CRTC[4] */
\r
306 cm.horizontal_end_retrace=0x80; /* CRTC[5] bit 0-4 */
\r
307 //cm.horizontal_start_delay_after_total=0x3e; /* CRTC[3] bit 5-6 */
\r
308 //cm.horizontal_start_delay_after_retrace=0x41; /* CRTC[5] bit 5-6 */
\r
309 cm.vertical_total = 0x20D + 2;
\r
310 cm.vertical_start_retrace = 0x1EA;
\r
311 cm.vertical_end_retrace = 0x1EC;
\r
312 cm.vertical_display_end = 480;
\r
313 cm.vertical_blank_start = 0x1E7 + 1;
\r
314 cm.vertical_blank_end = 0x206 + 1;
\r
315 cm.clock_select = 0; /* misc register = 0xE3 25MHz */
\r
318 cm.offset = (vga_state.vga_width / (4 * 2)); // 320 wide (40 x 4 pixel groups x 2)
\r
320 case 2: // TODO: 160x120 according to ModeX_160x120regs
\r
322 case 3: // TODO: 160x120 according to ModeX_320x200regs
\r
324 case 4: // TODO: 160x120 according to ModeX_192x144regs
\r
326 case 5: // TODO: 160x120 according to ModeX_256x192regs
\r
332 vga_state.vga_stride = cm.offset * 2;
\r
333 vga_write_crtc_mode(&cm,0);
\r
335 // clear video memory //
\r
341 dword far*ptr=(dword far*)vga_state.vga_graphics_ram;//VGA; // used for faster screen clearing //
\r
342 vga_write_sequencer(2/*map mask register*/,0xf/*all 4 planes*/);
\r
343 for(i = 0;i < 0x4000; i++) ptr[i] = 0x0000; // 0x4000 x dword = 64KB
\r
344 // fix up the palette and everything //
\r
345 modexPalBlack(); //reset the palette~//
\r
348 // clear the entire buffer space, because int 10h only did 16 k / plane
\r
354 //-- VL_SetLineWidth (cm.offset, gv);
\r
355 //gv->video.ofs.displayofs = 0;
\r
356 //gv->video.ofs.bufferofs = gv->video.page[0].width*gv->video.page[0].height;//gvar->video.page[0].pagesize;
\r
357 gv->video.curr_mode=vq;
\r
358 gv->video.VL_Started=1;
\r
361 void modexLeave(void)
\r
363 // VGAmodeX restores original mode and palette
\r
364 VL_vgaSetMode(TEXT_MODE);
\r
369 modexDefaultPage(page_t *p)
\r
372 /* default page values */
\r
374 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
375 page.data = (vga_state.vga_graphics_ram);
\r
380 page.width = p->sw;
\r
381 page.height = p->sh;
\r
382 page.ti.tw = page.sw/TILEWH;
\r
383 page.ti.th = page.sh/TILEWH;
\r
384 page.ti.tilesw=page.width/TILEWH;
\r
385 page.ti.tilesh=page.height/TILEWH;
\r
386 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
387 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
388 page.stridew=page.width/4;
\r
389 page.pagesize = (word)(page.stridew)*page.height;
\r
390 page.pi=page.width*4;
\r
392 if(ggvv->video.curr_mode = 1)
\r
394 page.width += TILEWHD;
\r
395 page.height += TILEWHD;
\r
401 modexDefaultPage(page_t *p, global_game_variables_t *gvar)
\r
405 /* default page values */
\r
407 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
408 page.data = (vga_state.vga_graphics_ram);
\r
413 page.width = p->sw;
\r
414 page.height = p->sh;
\r
415 if(gvar->video.curr_mode == 1)
\r
416 { page.width += TILEWHD;
\r
417 page.height += TILEWHD; }
\r
418 page.ti.tw = page.sw/TILEWH;
\r
419 page.ti.th = page.sh/TILEWH;
\r
420 page.ti.tilesw=page.width/TILEWH;
\r
421 page.ti.tilesh=page.height/TILEWH;
\r
422 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
423 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
424 page.stridew=page.width/4;
\r
425 page.pagesize = (word)(page.stridew)*page.height;
\r
426 page.pi=page.width*4;
\r
432 /* returns the next page in contiguous memory
\r
433 * the next page will be the same size as p, by default
\r
436 modexNextPage(page_t *p) {
\r
439 result.data = p->data + (p->pagesize);
\r
440 result.dx = p->dx; // not used anymore we use page[0].dx
\r
441 result.dy = p->dy; // not used anymore we use page[0].dy
\r
444 result.width = p->width;
\r
445 result.height = p->height;
\r
446 result.ti.tw = p->ti.tw;
\r
447 result.ti.th = p->ti.th;
\r
448 result.ti.tilesw = p->ti.tilesw;
\r
449 result.ti.tilesh = p->ti.tilesh;
\r
450 result.stridew=p->stridew;
\r
451 result.pagesize = p->pagesize;
\r
452 result.pi=result.width*4;
\r
453 result.id = p->id+1;
\r
458 //next page with defined dimentions~
\r
460 modexNextPageFlexibleSize(page_t *p, word x, word y)
\r
464 result.data = p->data + (p->pagesize); /* compute the offset */
\r
465 result.dx = 0; // not used anymore we use page[0].dx
\r
466 result.dy = 0; // not used anymore we use page[0].dy
\r
471 result.ti.tw = result.sw/TILEWH;
\r
472 result.ti.th = result.sh/TILEWH;
\r
473 result.ti.tilesw=result.width/TILEWH;
\r
474 result.ti.tilesh=result.height/TILEWH;
\r
475 result.id = p->id+1;
\r
476 result.stridew=result.width/4;//p->sw/4;
\r
477 result.pagesize = (word)(result.stridew)*result.height;
\r
478 /* switch(result.id)
\r
481 result.pi=p->width*4;
\r
487 result.pi=result.width*4;
\r
492 void modexCalcVmemRemain(video_t *video)
\r
495 //printf("\n\n 1st vmem_remain=%u\n", video->vmem_remain);
\r
496 for(i=0; i<video->num_of_pages; i++)
\r
498 video->vmem_remain-=video->page[i].pagesize;
\r
499 //printf(" [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);
\r
500 //printf(" [%u], vmem_remain=%u\n", i, video->vmem_remain);
\r
504 void VL_Initofs(video_t *video)
\r
506 if(!video->vga_state.bgps)
\r
508 video->ofs.offscreen_ofs = video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);
\r
509 video->ofs.pattern_ofs = (uint16_t)video->page[2].data;
\r
511 video->ofs.offscreen_ofs = 0;
\r
512 video->ofs.pattern_ofs = 0;//(uint16_t)video->page[0].data;
\r
516 void modexHiganbanaPageSetup(global_game_variables_t *gvar)
\r
518 gvar->video.vmem_remain=65535U;
\r
519 gvar->video.num_of_pages=0;
\r
520 (gvar->video.page[0]) = modexDefaultPage(&(gvar->video.page[0]), gvar); gvar->video.num_of_pages++; //gvar->video.page[0].width += (TILEWHD); gvar->video.page[0].height += (TILEWHD);
\r
521 (gvar->video.page[1]) = modexNextPage(&(gvar->video.page[0])); gvar->video.num_of_pages++;
\r
522 //0000 (gvar->video.page[2]) = modexNextPageFlexibleSize(&(gvar->video.page[1]), (gvar->video.page[0]).width, TILEWH*4); gvar->video.num_of_pages++;
\r
523 //0000 (gvar->video.page[3]) = (gvar->video.page[2]); gvar->video.num_of_pages++;
\r
524 //// (gvar->video.page[2]) = modexNextPageFlexibleSize(&(gvar->video.page[1]), TILEWH*4, TILEWH*4); gvar->video.num_of_pages++;
\r
525 //// (gvar->video.page[3]) = modexNextPageFlexibleSize(&(gvar->video.page[2]), gvar->video.page[0].sw, 208); gvar->video.num_of_pages++;
\r
526 (gvar->video.page[2]) = modexNextPageFlexibleSize(&(gvar->video.page[1]), gvar->video.page[0].width, 96); gvar->video.num_of_pages++;
\r
527 (gvar->video.page[3]) = modexNextPageFlexibleSize(&(gvar->video.page[2]), gvar->video.page[0].width, 96); gvar->video.num_of_pages++;
\r
528 modexCalcVmemRemain(&gvar->video);
\r
530 gvar->video.sp=gvar->video.p = 0; //showpage
\r
531 gvar->video.dorender = 1; //render
\r
532 gvar->video.vh=gvar->video.page[0].height+gvar->video.page[1].height+gvar->video.page[2].height+gvar->video.page[3].height;
\r
534 VL_Initofs(&gvar->video);
\r
536 gvar->video.vga_state.omemptr= vga_state.vga_graphics_ram;
\r
537 gvar->video.vga_state.vga_draw_stride= vga_state.vga_draw_stride;
\r
538 gvar->video.vga_state.vga_draw_stride_limit= vga_state.vga_draw_stride_limit;
\r
539 //sprite render switch and bgpreservation switch
\r
540 gvar->video.vga_state.rss= 1;
\r
541 gvar->video.vga_state.bgps= 1;
\r
543 //setup the buffersize
\r
544 gvar->video.page[0].dx=gvar->video.page[0].dy=
\r
545 gvar->video.page[1].dx=gvar->video.page[1].dy=TILEWH; // 1 tile size buffer
\r
546 gvar->video.page[2].dx=gvar->video.page[2].dy=
\r
547 gvar->video.page[3].dx=gvar->video.page[3].dy=0; // cache pages are buffer wwww
\r
549 gvar->video.page[0].tlx=gvar->mv[0].tx*TILEWH;
\r
550 gvar->video.page[0].tly=gvar->mv[0].ty*TILEWH;
\r
554 // move page to appropriate part and show it
\r
557 modexShowPage(page_t *page) {
\r
558 word high_address, low_address, offset;
\r
561 /* calculate offset */
\r
562 offset = (word) page->data;
\r
563 offset += page[0].dy * (page->width >> 2 );
\r
564 offset += page[0].dx >> 2;
\r
566 /* calculate crtcOffset according to virtual width */
\r
567 crtcOffset = page->width >> 3;
\r
569 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
570 low_address = LOW_ADDRESS | (offset << 8);
\r
572 /* wait for appropriate timing and then program CRTC */
\r
573 //+=+= while ((inp(STATUS_REGISTER_1) & DISPLAY_ENABLE));
\r
574 outpw(CRTC_INDEX, high_address);
\r
575 outpw(CRTC_INDEX, low_address);
\r
576 outp(CRTC_INDEX, 0x13);
\r
577 outp(CRTC_DATA, crtcOffset);
\r
579 /* wait for one retrace */
\r
580 //+=+= while (!(inp(STATUS_REGISTER_1) & VRETRACE));
\r
582 /* do PEL panning here */
\r
583 outp(AC_INDEX, 0x33);
\r
584 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
587 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
589 VL_ShowPage(page_t *page, boolean vsync, boolean sr)
\r
591 word high_address, low_address, offset;
\r
594 // calculate offset
\r
595 offset = (word) page->data;
\r
596 offset += page->dy * (page->width >> 2 );
\r
597 offset += page->dx >> 2;
\r
599 // calculate crtcOffset according to virtual width
\r
603 crtcOffset = page->sw >> 3;
\r
607 crtcOffset = page->width >> 3;
\r
611 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
612 low_address = LOW_ADDRESS | (offset << 8);
\r
614 // wait for appropriate timing and then program CRTC
\r
615 if(vsync) while ((inp(STATUS_REGISTER_1) & DISPLAY_ENABLE));
\r
616 outpw(CRTC_INDEX, high_address);
\r
617 outpw(CRTC_INDEX, low_address);
\r
618 outp(CRTC_INDEX, 0x13);
\r
619 outp(CRTC_DATA, crtcOffset);
\r
621 // wait for one retrace
\r
622 if(vsync) while (!(inp(STATUS_REGISTER_1) & VRETRACE));
\r
624 // do PEL panning here
\r
625 outp(AC_INDEX, 0x33);
\r
626 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
627 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
628 vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;
\r
631 //=============================================================================
\r
634 modexPanPage(page_t *page, int dx, int dy) {
\r
640 modexSelectPlane(byte plane) {
\r
641 outp(SC_INDEX, SC_MAPMASK); /* select plane */
\r
642 outp(SC_DATA, plane);
\r
646 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
648 word pageOff = (word) page->data;
\r
649 word xoff=(x>>2); // xoffset that begins each row
\r
650 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
651 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
652 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
654 byte left = lclip[x&0x03];
\r
655 byte right = rclip[(x+w)&0x03];
\r
657 // handle the case which requires an extra group
\r
658 if((x & 0x03) && !((x+w) & 0x03)) {
\r
662 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
673 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
675 MOV DI, poffset ; go to the first pixel
\r
676 MOV DX, SC_INDEX ; point to the map mask
\r
680 MOV AL, color ; get ready to write colors
\r
682 MOV CX, scanCount ; count the line
\r
683 MOV BL, AL ; remember color
\r
684 MOV AL, left ; do the left clip
\r
685 OUT DX, AL ; set the left clip
\r
686 MOV AL, BL ; restore color
\r
687 STOSB ; write the color
\r
689 JZ SCAN_DONE ; handle 1 group stuff
\r
691 ;-- write the main body of the scanline
\r
692 MOV BL, AL ; remember color
\r
693 MOV AL, 0x0f ; write to all pixels
\r
695 MOV AL, BL ; restore color
\r
696 REP STOSB ; write the color
\r
698 MOV BL, AL ; remeber color
\r
700 OUT DX, AL ; do the right clip
\r
701 MOV AL, BL ; restore color
\r
702 STOSB ; write pixel
\r
703 ADD DI, nextRow ; go to the next row
\r
717 /* moved to src/lib/modex16/16render.c */
\r
719 /* copy a region of video memory from one page to another.
\r
720 * It assumes that the left edge of the tile is the same on both
\r
721 * regions and the memory areas do not overlap.
\r
724 modexCopyPageRegion(page_t *dest, page_t *src,
\r
727 word width, word height)
\r
729 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
730 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
731 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
732 word nextSrcRow = src->stridew - scans - 1;
\r
733 word nextDestRow = dest->stridew - scans - 1;
\r
735 byte left = lclip[sx&0x03];
\r
736 byte right = rclip[(sx+width)&0x03];
\r
738 // handle the case which requires an extra group
\r
739 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
743 // 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
755 MOV AX, SCREEN_SEG ; work in the vga space
\r
760 MOV DX, GC_INDEX ; turn off cpu bits
\r
764 MOV AX, SC_INDEX ; point to the mask register
\r
766 MOV AL, SC_MAPMASK ;
\r
774 MOV CX, scans ; the number of latches
\r
776 MOV AL, left ; do the left column
\r
781 MOV AL, 0fh ; do the inner columns
\r
783 REP MOVSB ; copy the pixels
\r
785 MOV AL, right ; do the right column
\r
790 MOV AX, SI ; go the start of the next row
\r
791 ADD AX, nextSrcRow ;
\r
794 ADD AX, nextDestRow ;
\r
797 DEC height ; do the rest of the actions
\r
800 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
801 MOV AL, 0ffh ; none from latches
\r
817 /* fade and flash */
\r
819 modexFadeOn(word fade, byte *palette) {
\r
820 fadePalette(-fade, 64, 64/fade+1, palette);
\r
825 modexFadeOff(word fade, byte *palette) {
\r
826 fadePalette(fade, 0, 64/fade+1, palette);
\r
831 modexFlashOn(word fade, byte *palette) {
\r
832 fadePalette(fade, -64, 64/fade+1, palette);
\r
837 modexFlashOff(word fade, byte *palette) {
\r
838 fadePalette(-fade, 0, 64/fade+1, palette);
\r
843 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
847 /* handle the case where we just update */
\r
849 modexPalUpdate(palette);
\r
853 while(iter > 0) { /* FadeLoop */
\r
854 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
855 tmppal[i] = palette[i] - dim;
\r
856 if(tmppal[i] > 127) {
\r
858 } else if(tmppal[i] > 63) {
\r
862 modexPalUpdate(tmppal);
\r
870 void modexPalSave(byte *palette)
\r
874 outp(PAL_READ_REG, 0); // start at palette entry 0
\r
875 for(i=0; i<PAL_SIZE; i++)
\r
877 palette[i] = inp(PAL_DATA_REG); // read the palette data
\r
885 ptr = mAlloc(PAL_SIZE);
\r
889 printf("Could not Allocate palette.\n");
\r
897 modexLoadPalFile(byte *filename, byte *palette) {
\r
901 // free the palette if it exists
\r
902 //if(*palette) { free(*palette); }
\r
904 // allocate the new palette
\r
905 //*palette = modexNewPal();
\r
908 file = fopen(filename, "rb");
\r
910 printf("Could not open palette file: %s\n", filename);
\r
913 /* read the file */
\r
915 while(!feof(file)) {
\r
916 *ptr++ = fgetc(file);
\r
922 #define COREPALSIZE 9//27 //3*9
\r
924 void VLL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, word palsize, global_game_variables_t *gvar)
\r
929 fd = open(filename,O_RDONLY|O_BINARY);
\r
931 read(fd,palette, palsize*3);
\r
934 if(palsize==COREPALSIZE) newpalette = palette; else{ //if core then load it
\r
935 newpalette = &palette[3]; //skip overscan color
\r
938 VL_UpdatePaletteWrite(newpalette, o, palsize, gvar);
\r
942 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)
\r
944 VLL_LoadPalFilewithoffset(filename, palette,
\r
945 0, //overwrite core/system palette
\r
946 // COREPALSIZE, //preserved core/system palette
\r
950 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)
\r
952 VLL_LoadPalFilewithoffset("data/16.pal", palette, 0, COREPALSIZE, gvar);
\r
955 void VL_UpdatePaletteWrite(byte *palette, word o, word p, global_game_variables_t *gvar)
\r
959 vga_palette_lseek(o);
\r
960 for (i=0;i < p-o;i++)
\r
961 vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);
\r
963 VL_PaletteSync(gvar);
\r
966 void VL_PaletteSync(global_game_variables_t *gvar)
\r
968 modexPalSave(&gvar->video.palette);
\r
972 modexSavePalFile(char *filename, byte *pal) {
\r
976 /* open the file for writing */
\r
977 file = fopen(filename, "wb");
\r
979 printf("Could not open %s for writing\n", filename);
\r
982 /* write the data to the file */
\r
983 fwrite(pal, 1, PAL_SIZE, file);
\r
991 fadePalette(-1, 64, 1, tmppal);
\r
997 fadePalette(-1, -64, 1, tmppal);
\r
1002 //moved to 16_vlpal.c
\r
1005 modexPalUpdate(byte *p)
\r
1008 //modexWaitBorder();
\r
1009 vga_wait_for_vsync();
\r
1010 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1011 for(i=0; i<PAL_SIZE/2; i++)
\r
1013 outp(PAL_DATA_REG, p[i]);
\r
1015 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1016 vga_wait_for_vsync();
\r
1017 for(; i<PAL_SIZE; i++)
\r
1019 outp(PAL_DATA_REG, p[(i)]);
\r
1024 //modexPalUpdate0(byte *p)
\r
1025 VL_modexPalScramble(byte *p)
\r
1028 //modexWaitBorder();
\r
1029 vga_wait_for_vsync();
\r
1030 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1031 for(i=0; i<PAL_SIZE/2; i++)
\r
1033 outp(PAL_DATA_REG, rand());
\r
1035 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1036 vga_wait_for_vsync();
\r
1037 for(; i<PAL_SIZE; i++)
\r
1039 outp(PAL_DATA_REG, rand());
\r
1044 VL_modexPalOverscan(byte *p, word col)
\r
1047 //modexWaitBorder();
\r
1048 vga_wait_for_vsync();
\r
1049 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1050 for(i=col; i<(3+col); i++)
\r
1052 outp(PAL_DATA_REG, p[i]);
\r
1054 // modexPalSave(p);
\r
1060 void modexputPixel(page_t *page, int x, int y, byte color)
\r
1062 word pageOff = (word) page->data;
\r
1063 /* Each address accesses four neighboring pixels, so set
\r
1064 Write Plane Enable according to which pixel we want
\r
1065 to modify. The plane is determined by the two least
\r
1066 significant bits of the x-coordinate: */
\r
1067 modexSelectPlane(PLANE(x));
\r
1068 //outp(SC_INDEX, 0x02);
\r
1069 //outp(SC_DATA, 0x01 << (x & 3));
\r
1071 /* The offset of the pixel into the video segment is
\r
1072 offset = (width * y + x) / 4, and write the given
\r
1073 color to the plane we selected above. Heed the active
\r
1074 page start selection. */
\r
1075 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
1079 byte modexgetPixel(page_t *page, int x, int y)
\r
1081 word pageOff = (word) page->data;
\r
1082 /* Select the plane from which we must read the pixel color: */
\r
1083 outpw(GC_INDEX, 0x04);
\r
1084 outpw(GC_INDEX+1, x & 3);
\r
1086 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
1090 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
1092 /* vertical drawing routine by joncampbell123.
\r
1094 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
1095 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
1097 * 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
1098 word rows = romFonts[t].charSize;
\r
1106 m1 = 0x80; // left half
\r
1107 m2 = 0x08; // right half
\r
1108 for (colm=0;colm < 4;colm++) {
\r
1110 modexSelectPlane(PLANE(plane));
\r
1111 for (row=0;row < rows;row++) {
\r
1112 fontbyte = romFontsData.l[row];
\r
1113 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
1114 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
1115 drawaddr += page->width >> 2;
\r
1120 if ((++plane) == 4) {
\r
1127 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word color, word bgcolor, boolean vidsw, const byte *str)
\r
1131 //word addr = (word) romFontsData.l;
\r
1139 printf("%s\n", str);
\r
1142 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
1144 addrq = (page->stridew) * y + (word)(x_draw) +
\r
1145 ((word)page->data);
\r
1147 s=romFonts[t].seg;
\r
1148 o=romFonts[t].off;
\r
1149 w=romFonts[t].charSize;
\r
1150 romFontsData.chw=0;
\r
1152 for(; *str != '\0'; str++)
\r
1158 romFontsData.chw = 0;
\r
1159 addrq += (page->stridew) * 8;
\r
1165 // load the character into romFontsData.l
\r
1166 // no need for inline assembly!
\r
1167 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
1168 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
1169 modexDrawChar(page, x_draw/*for mode X planar use*/, t, color, bgcolor, addrr);
\r
1170 x_draw += 8; /* track X for edge of screen */
\r
1171 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
1173 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
1178 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
1180 word i, s, o, w, j, xp;
\r
1182 word addr = (word) l;
\r
1206 s=romFonts[t].seg;
\r
1207 o=romFonts[t].off;
\r
1209 for(; *str != '\0'; str++)
\r
1212 if((c=='\n'/* || c=="\
\r
1213 "*/)/* || chw>=page->width*/)
\r
1219 //load the letter 'A'
\r
1234 MOV AL, c ; the letter
\r
1237 ADD SI, AX ;the address of charcter
\r
1255 for(i=0; i<w; i++)
\r
1261 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1262 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1271 // short hand of modexprint
\r
1272 void VL_print(const byte *str, nibble pagenum, global_game_variables_t *gvar)
\r
1274 modexprint(&(gvar->video.page[pagenum]), gvar->video.print.x, gvar->video.print.y, gvar->video.print.t, gvar->video.print.tlsw, gvar->video.print.color, gvar->video.print.bgcolor, gvar->video.VL_Started, str);
\r
1277 /* palette dump on display! */
\r
1278 void modexpdump(nibble pagenum, global_game_variables_t *gvar)
\r
1280 int mult=(QUADWH);
\r
1281 int palq=(mult)*TILEWH;
\r
1284 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1285 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1286 modexClearRegion(&gvar->video.page[pagenum], palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1290 modexPalSave(gvar->video.palette);
\r
1293 /////////////////////////////////////////////////////////////////////////////
\r
1295 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1296 // the Virtual screen. //
\r
1298 /////////////////////////////////////////////////////////////////////////////
\r
1299 void modexcls(page_t *page, byte color, byte *Where)
\r
1301 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1302 /* set map mask to all 4 planes */
\r
1303 outpw(SC_INDEX, 0xff02);
\r
1304 //_fmemset(VGA, color, 16000);
\r
1305 _fmemset(Where, color, page->stridew*page->height);
\r
1309 // pattern filler from joncampbell123's code
\r
1311 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1313 unsigned int i,j,o, d,h,s;
\r
1319 w=vga_state.vga_width;
\r
1321 s=vga_state.vga_stride;
\r
1325 h=vga_state.vga_height;
\r
1333 w=video->page[pn].width;
\r
1334 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1335 s=video->page[pn].stridew;
\r
1339 h=video->page[pn].height;
\r
1342 if(!pn) h=video->vh;
\r
1343 else h=video->page[pn].height;
\r
1349 /* fill screen/pattern with a distinctive pattern */
\r
1350 for (i=0;i < w;i++) {
\r
1352 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1353 for (j=0;j < h;j++,o += s)
\r
1354 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1359 modexWaitBorder() {
\r
1360 while(inp(STATUS_REGISTER_1) & 8) {
\r
1364 while(!(inp(STATUS_REGISTER_1) & 8)) {
\r
1370 modexWaitBorder_start()
\r
1372 while(inp(STATUS_REGISTER_1) & 8) {
\r
1379 modexWaitBorder_end()
\r
1381 while(!(inp(STATUS_REGISTER_1) & 8)) {
\r
1387 //===========================================================================
\r
1390 // printings of video memory information
\r
1392 void VL_PrintmodexmemInfo(video_t *v)
\r
1396 // printf("========================================\n");
\r
1397 printf("VL_PrintmodexmemInfo:\n");
\r
1398 // printf("========================================\n");
\r
1399 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
1400 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
1401 printf(" vga_stride: %u ", vga_state.vga_stride);
\r
1402 printf("pagestride: %u ", v->page[0].stridew);
\r
1403 printf("draw_stride: %u ", vga_state.vga_draw_stride);
\r
1404 printf("draw_stride_limit: %u\n", vga_state.vga_draw_stride_limit);
\r
1406 if(v->vmem_remain)
\r
1407 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1408 if(v->num_of_pages)
\r
1411 for(i=0; i<v->num_of_pages;i++)
\r
1413 printf(" [%u]=", i);
\r
1414 printf("(%Fp)", (v->page[i].data));
\r
1415 printf(" size=%u ", v->page[i].pagesize);
\r
1416 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1417 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1418 printf("pi=%u", v->page[i].pi);
\r