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
551 // move page to appropriate part and show it
\r
554 modexShowPage(page_t *page) {
\r
555 word high_address, low_address, offset;
\r
558 /* calculate offset */
\r
559 offset = (word) page->data;
\r
560 offset += page[0].dy * (page->width >> 2 );
\r
561 offset += page[0].dx >> 2;
\r
563 /* calculate crtcOffset according to virtual width */
\r
564 crtcOffset = page->width >> 3;
\r
566 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
567 low_address = LOW_ADDRESS | (offset << 8);
\r
569 /* wait for appropriate timing and then program CRTC */
\r
570 //+=+= while ((inp(STATUS_REGISTER_1) & DISPLAY_ENABLE));
\r
571 outpw(CRTC_INDEX, high_address);
\r
572 outpw(CRTC_INDEX, low_address);
\r
573 outp(CRTC_INDEX, 0x13);
\r
574 outp(CRTC_DATA, crtcOffset);
\r
576 /* wait for one retrace */
\r
577 //+=+= while (!(inp(STATUS_REGISTER_1) & VRETRACE));
\r
579 /* do PEL panning here */
\r
580 outp(AC_INDEX, 0x33);
\r
581 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
584 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
586 VL_ShowPage(page_t *page, boolean vsync, boolean sr)
\r
588 word high_address, low_address, offset;
\r
591 // calculate offset
\r
592 offset = (word) page->data;
\r
593 offset += page->dy * (page->width >> 2 );
\r
594 offset += page->dx >> 2;
\r
596 // calculate crtcOffset according to virtual width
\r
600 crtcOffset = page->sw >> 3;
\r
604 crtcOffset = page->width >> 3;
\r
608 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
609 low_address = LOW_ADDRESS | (offset << 8);
\r
611 // wait for appropriate timing and then program CRTC
\r
612 if(vsync) while ((inp(STATUS_REGISTER_1) & DISPLAY_ENABLE));
\r
613 outpw(CRTC_INDEX, high_address);
\r
614 outpw(CRTC_INDEX, low_address);
\r
615 outp(CRTC_INDEX, 0x13);
\r
616 outp(CRTC_DATA, crtcOffset);
\r
618 // wait for one retrace
\r
619 if(vsync) while (!(inp(STATUS_REGISTER_1) & VRETRACE));
\r
621 // do PEL panning here
\r
622 outp(AC_INDEX, 0x33);
\r
623 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
624 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
625 vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;
\r
628 //=============================================================================
\r
631 modexPanPage(page_t *page, int dx, int dy) {
\r
637 modexSelectPlane(byte plane) {
\r
638 outp(SC_INDEX, SC_MAPMASK); /* select plane */
\r
639 outp(SC_DATA, plane);
\r
643 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
645 word pageOff = (word) page->data;
\r
646 word xoff=(x>>2); // xoffset that begins each row
\r
647 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
648 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
649 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
651 byte left = lclip[x&0x03];
\r
652 byte right = rclip[(x+w)&0x03];
\r
654 // handle the case which requires an extra group
\r
655 if((x & 0x03) && !((x+w) & 0x03)) {
\r
659 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
670 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
672 MOV DI, poffset ; go to the first pixel
\r
673 MOV DX, SC_INDEX ; point to the map mask
\r
677 MOV AL, color ; get ready to write colors
\r
679 MOV CX, scanCount ; count the line
\r
680 MOV BL, AL ; remember color
\r
681 MOV AL, left ; do the left clip
\r
682 OUT DX, AL ; set the left clip
\r
683 MOV AL, BL ; restore color
\r
684 STOSB ; write the color
\r
686 JZ SCAN_DONE ; handle 1 group stuff
\r
688 ;-- write the main body of the scanline
\r
689 MOV BL, AL ; remember color
\r
690 MOV AL, 0x0f ; write to all pixels
\r
692 MOV AL, BL ; restore color
\r
693 REP STOSB ; write the color
\r
695 MOV BL, AL ; remeber color
\r
697 OUT DX, AL ; do the right clip
\r
698 MOV AL, BL ; restore color
\r
699 STOSB ; write pixel
\r
700 ADD DI, nextRow ; go to the next row
\r
714 /* moved to src/lib/modex16/16render.c */
\r
716 /* copy a region of video memory from one page to another.
\r
717 * It assumes that the left edge of the tile is the same on both
\r
718 * regions and the memory areas do not overlap.
\r
721 modexCopyPageRegion(page_t *dest, page_t *src,
\r
724 word width, word height)
\r
726 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
727 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
728 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
729 word nextSrcRow = src->stridew - scans - 1;
\r
730 word nextDestRow = dest->stridew - scans - 1;
\r
732 byte left = lclip[sx&0x03];
\r
733 byte right = rclip[(sx+width)&0x03];
\r
735 // handle the case which requires an extra group
\r
736 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
740 // 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
752 MOV AX, SCREEN_SEG ; work in the vga space
\r
757 MOV DX, GC_INDEX ; turn off cpu bits
\r
761 MOV AX, SC_INDEX ; point to the mask register
\r
763 MOV AL, SC_MAPMASK ;
\r
771 MOV CX, scans ; the number of latches
\r
773 MOV AL, left ; do the left column
\r
778 MOV AL, 0fh ; do the inner columns
\r
780 REP MOVSB ; copy the pixels
\r
782 MOV AL, right ; do the right column
\r
787 MOV AX, SI ; go the start of the next row
\r
788 ADD AX, nextSrcRow ;
\r
791 ADD AX, nextDestRow ;
\r
794 DEC height ; do the rest of the actions
\r
797 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
798 MOV AL, 0ffh ; none from latches
\r
814 /* fade and flash */
\r
816 modexFadeOn(word fade, byte *palette) {
\r
817 fadePalette(-fade, 64, 64/fade+1, palette);
\r
822 modexFadeOff(word fade, byte *palette) {
\r
823 fadePalette(fade, 0, 64/fade+1, palette);
\r
828 modexFlashOn(word fade, byte *palette) {
\r
829 fadePalette(fade, -64, 64/fade+1, palette);
\r
834 modexFlashOff(word fade, byte *palette) {
\r
835 fadePalette(-fade, 0, 64/fade+1, palette);
\r
840 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
844 /* handle the case where we just update */
\r
846 modexPalUpdate(palette);
\r
850 while(iter > 0) { /* FadeLoop */
\r
851 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
852 tmppal[i] = palette[i] - dim;
\r
853 if(tmppal[i] > 127) {
\r
855 } else if(tmppal[i] > 63) {
\r
859 modexPalUpdate(tmppal);
\r
867 void modexPalSave(byte *palette)
\r
871 outp(PAL_READ_REG, 0); // start at palette entry 0
\r
872 for(i=0; i<PAL_SIZE; i++)
\r
874 palette[i] = inp(PAL_DATA_REG); // read the palette data
\r
882 ptr = mAlloc(PAL_SIZE);
\r
886 printf("Could not Allocate palette.\n");
\r
894 modexLoadPalFile(byte *filename, byte *palette) {
\r
898 // free the palette if it exists
\r
899 //if(*palette) { free(*palette); }
\r
901 // allocate the new palette
\r
902 //*palette = modexNewPal();
\r
905 file = fopen(filename, "rb");
\r
907 printf("Could not open palette file: %s\n", filename);
\r
910 /* read the file */
\r
912 while(!feof(file)) {
\r
913 *ptr++ = fgetc(file);
\r
919 #define COREPALSIZE 9//27 //3*9
\r
921 void VLL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, word palsize, global_game_variables_t *gvar)
\r
926 fd = open(filename,O_RDONLY|O_BINARY);
\r
928 read(fd,palette, palsize*3);
\r
931 if(palsize==COREPALSIZE) newpalette = palette; else{ //if core then load it
\r
932 newpalette = &palette[3]; //skip overscan color
\r
935 VL_UpdatePaletteWrite(newpalette, o, palsize, gvar);
\r
939 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)
\r
941 VLL_LoadPalFilewithoffset(filename, palette,
\r
942 0, //overwrite core/system palette
\r
943 // COREPALSIZE, //preserved core/system palette
\r
947 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)
\r
949 VLL_LoadPalFilewithoffset("data/16.pal", palette, 0, COREPALSIZE, gvar);
\r
952 void VL_UpdatePaletteWrite(byte *palette, word o, word p, global_game_variables_t *gvar)
\r
956 vga_palette_lseek(o);
\r
957 for (i=0;i < p-o;i++)
\r
958 vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);
\r
960 VL_PaletteSync(gvar);
\r
963 void VL_PaletteSync(global_game_variables_t *gvar)
\r
965 modexPalSave(&gvar->video.palette);
\r
969 modexSavePalFile(char *filename, byte *pal) {
\r
973 /* open the file for writing */
\r
974 file = fopen(filename, "wb");
\r
976 printf("Could not open %s for writing\n", filename);
\r
979 /* write the data to the file */
\r
980 fwrite(pal, 1, PAL_SIZE, file);
\r
988 fadePalette(-1, 64, 1, tmppal);
\r
994 fadePalette(-1, -64, 1, tmppal);
\r
999 //moved to 16_vlpal.c
\r
1002 modexPalUpdate(byte *p)
\r
1005 //modexWaitBorder();
\r
1006 vga_wait_for_vsync();
\r
1007 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1008 for(i=0; i<PAL_SIZE/2; i++)
\r
1010 outp(PAL_DATA_REG, p[i]);
\r
1012 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1013 vga_wait_for_vsync();
\r
1014 for(; i<PAL_SIZE; i++)
\r
1016 outp(PAL_DATA_REG, p[(i)]);
\r
1021 //modexPalUpdate0(byte *p)
\r
1022 VL_modexPalScramble(byte *p)
\r
1025 //modexWaitBorder();
\r
1026 vga_wait_for_vsync();
\r
1027 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1028 for(i=0; i<PAL_SIZE/2; i++)
\r
1030 outp(PAL_DATA_REG, rand());
\r
1032 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1033 vga_wait_for_vsync();
\r
1034 for(; i<PAL_SIZE; i++)
\r
1036 outp(PAL_DATA_REG, rand());
\r
1041 VL_modexPalOverscan(byte *p, word col)
\r
1044 //modexWaitBorder();
\r
1045 vga_wait_for_vsync();
\r
1046 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1047 for(i=col; i<(3+col); i++)
\r
1049 outp(PAL_DATA_REG, p[i]);
\r
1051 // modexPalSave(p);
\r
1057 void modexputPixel(page_t *page, int x, int y, byte color)
\r
1059 word pageOff = (word) page->data;
\r
1060 /* Each address accesses four neighboring pixels, so set
\r
1061 Write Plane Enable according to which pixel we want
\r
1062 to modify. The plane is determined by the two least
\r
1063 significant bits of the x-coordinate: */
\r
1064 modexSelectPlane(PLANE(x));
\r
1065 //outp(SC_INDEX, 0x02);
\r
1066 //outp(SC_DATA, 0x01 << (x & 3));
\r
1068 /* The offset of the pixel into the video segment is
\r
1069 offset = (width * y + x) / 4, and write the given
\r
1070 color to the plane we selected above. Heed the active
\r
1071 page start selection. */
\r
1072 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
1076 byte modexgetPixel(page_t *page, int x, int y)
\r
1078 word pageOff = (word) page->data;
\r
1079 /* Select the plane from which we must read the pixel color: */
\r
1080 outpw(GC_INDEX, 0x04);
\r
1081 outpw(GC_INDEX+1, x & 3);
\r
1083 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
1087 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
1089 /* vertical drawing routine by joncampbell123.
\r
1091 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
1092 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
1094 * 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
1095 word rows = romFonts[t].charSize;
\r
1103 m1 = 0x80; // left half
\r
1104 m2 = 0x08; // right half
\r
1105 for (colm=0;colm < 4;colm++) {
\r
1107 modexSelectPlane(PLANE(plane));
\r
1108 for (row=0;row < rows;row++) {
\r
1109 fontbyte = romFontsData.l[row];
\r
1110 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
1111 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
1112 drawaddr += page->width >> 2;
\r
1117 if ((++plane) == 4) {
\r
1124 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word color, word bgcolor, boolean vidsw, const byte *str)
\r
1128 //word addr = (word) romFontsData.l;
\r
1136 printf("%s\n", str);
\r
1139 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
1141 addrq = (page->stridew) * y + (word)(x_draw) +
\r
1142 ((word)page->data);
\r
1144 s=romFonts[t].seg;
\r
1145 o=romFonts[t].off;
\r
1146 w=romFonts[t].charSize;
\r
1147 romFontsData.chw=0;
\r
1149 for(; *str != '\0'; str++)
\r
1155 romFontsData.chw = 0;
\r
1156 addrq += (page->stridew) * 8;
\r
1162 // load the character into romFontsData.l
\r
1163 // no need for inline assembly!
\r
1164 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
1165 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
1166 modexDrawChar(page, x_draw/*for mode X planar use*/, t, color, bgcolor, addrr);
\r
1167 x_draw += 8; /* track X for edge of screen */
\r
1168 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
1170 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
1175 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
1177 word i, s, o, w, j, xp;
\r
1179 word addr = (word) l;
\r
1203 s=romFonts[t].seg;
\r
1204 o=romFonts[t].off;
\r
1206 for(; *str != '\0'; str++)
\r
1209 if((c=='\n'/* || c=="\
\r
1210 "*/)/* || chw>=page->width*/)
\r
1216 //load the letter 'A'
\r
1231 MOV AL, c ; the letter
\r
1234 ADD SI, AX ;the address of charcter
\r
1252 for(i=0; i<w; i++)
\r
1258 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1259 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1268 /* palette dump on display! */
\r
1269 void modexpdump(nibble pagenum, global_game_variables_t *gvar)
\r
1271 int mult=(QUADWH);
\r
1272 int palq=(mult)*TILEWH;
\r
1275 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1276 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1277 modexClearRegion(&gvar->video.page[pagenum], palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1281 modexPalSave(gvar->video.palette);
\r
1284 /////////////////////////////////////////////////////////////////////////////
\r
1286 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1287 // the Virtual screen. //
\r
1289 /////////////////////////////////////////////////////////////////////////////
\r
1290 void modexcls(page_t *page, byte color, byte *Where)
\r
1292 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1293 /* set map mask to all 4 planes */
\r
1294 outpw(SC_INDEX, 0xff02);
\r
1295 //_fmemset(VGA, color, 16000);
\r
1296 _fmemset(Where, color, page->stridew*page->height);
\r
1300 // pattern filler from joncampbell123's code
\r
1302 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1304 unsigned int i,j,o, d,h,s;
\r
1310 w=vga_state.vga_width;
\r
1312 s=vga_state.vga_stride;
\r
1316 h=vga_state.vga_height;
\r
1324 w=video->page[pn].width;
\r
1325 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1326 s=video->page[pn].stridew;
\r
1330 h=video->page[pn].height;
\r
1333 if(!pn) h=video->vh;
\r
1334 else h=video->page[pn].height;
\r
1340 /* fill screen/pattern with a distinctive pattern */
\r
1341 for (i=0;i < w;i++) {
\r
1343 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1344 for (j=0;j < h;j++,o += s)
\r
1345 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1350 modexWaitBorder() {
\r
1351 while(inp(STATUS_REGISTER_1) & 8) {
\r
1355 while(!(inp(STATUS_REGISTER_1) & 8)) {
\r
1361 modexWaitBorder_start()
\r
1363 while(inp(STATUS_REGISTER_1) & 8) {
\r
1370 modexWaitBorder_end()
\r
1372 while(!(inp(STATUS_REGISTER_1) & 8)) {
\r
1378 //===========================================================================
\r
1381 // printings of video memory information
\r
1383 void VL_PrintmodexmemInfo(video_t *v)
\r
1387 // printf("========================================\n");
\r
1388 printf("VL_PrintmodexmemInfo:\n");
\r
1389 // printf("========================================\n");
\r
1390 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
1391 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
1392 printf(" stride: %u ", vga_state.vga_stride);
\r
1393 printf("draw_stride: %u ", vga_state.vga_draw_stride);
\r
1394 printf("draw_stride_limit: %u\n", vga_state.vga_draw_stride_limit);
\r
1396 if(v->vmem_remain)
\r
1397 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1398 if(v->num_of_pages)
\r
1401 for(i=0; i<v->num_of_pages;i++)
\r
1403 printf(" [%u]=", i);
\r
1404 printf("(%Fp)", (v->page[i].data));
\r
1405 printf(" size=%u ", v->page[i].pagesize);
\r
1406 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1407 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1408 printf("pi=%u", v->page[i].pi);
\r