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(INPUT_STATUS_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(INPUT_STATUS_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(INPUT_STATUS_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(INPUT_STATUS_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 void VLL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, word palsize, global_game_variables_t *gvar)
\r
924 fd = open(filename,O_RDONLY|O_BINARY);
\r
926 read(fd,palette, palsize);
\r
929 if(palsize==27) newpalette = palette; else{ //if core then load it
\r
930 newpalette = &palette[3]; //skip overscan color
\r
933 VL_UpdatePaletteWrite(newpalette, o, gvar);
\r
937 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)
\r
939 VLL_LoadPalFilewithoffset(filename, palette,
\r
940 0, //overwrite core/system palette
\r
941 // 9, //preserved core/system palette
\r
945 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)
\r
947 VLL_LoadPalFilewithoffset("data/16.pal", palette, 0, 27, gvar);
\r
950 void VL_UpdatePaletteWrite(byte *palette, word o, global_game_variables_t *gvar)
\r
954 vga_palette_lseek(o);
\r
955 for (i=0;i < 255-o;i++)
\r
956 vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);
\r
958 VL_PaletteSync(gvar);
\r
961 void VL_PaletteSync(global_game_variables_t *gvar)
\r
963 modexPalSave(&gvar->video.palette);
\r
967 modexSavePalFile(char *filename, byte *pal) {
\r
971 /* open the file for writing */
\r
972 file = fopen(filename, "wb");
\r
974 printf("Could not open %s for writing\n", filename);
\r
977 /* write the data to the file */
\r
978 fwrite(pal, 1, PAL_SIZE, file);
\r
986 fadePalette(-1, 64, 1, tmppal);
\r
992 fadePalette(-1, -64, 1, tmppal);
\r
997 //moved to 16_vlpal.c
\r
1000 modexPalUpdate(byte *p)
\r
1003 //modexWaitBorder();
\r
1004 vga_wait_for_vsync();
\r
1005 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1006 for(i=0; i<PAL_SIZE/2; i++)
\r
1008 outp(PAL_DATA_REG, p[i]);
\r
1010 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1011 vga_wait_for_vsync();
\r
1012 for(; i<PAL_SIZE; i++)
\r
1014 outp(PAL_DATA_REG, p[(i)]);
\r
1019 //modexPalUpdate0(byte *p)
\r
1020 VL_modexPalScramble(byte *p)
\r
1023 //modexWaitBorder();
\r
1024 vga_wait_for_vsync();
\r
1025 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1026 for(i=0; i<PAL_SIZE/2; i++)
\r
1028 outp(PAL_DATA_REG, rand());
\r
1030 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1031 vga_wait_for_vsync();
\r
1032 for(; i<PAL_SIZE; i++)
\r
1034 outp(PAL_DATA_REG, rand());
\r
1039 VL_modexPalOverscan(byte *p, word col)
\r
1042 //modexWaitBorder();
\r
1043 vga_wait_for_vsync();
\r
1044 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1045 for(i=col; i<(3+col); i++)
\r
1047 outp(PAL_DATA_REG, p[i]);
\r
1049 // modexPalSave(p);
\r
1055 void modexputPixel(page_t *page, int x, int y, byte color)
\r
1057 word pageOff = (word) page->data;
\r
1058 /* Each address accesses four neighboring pixels, so set
\r
1059 Write Plane Enable according to which pixel we want
\r
1060 to modify. The plane is determined by the two least
\r
1061 significant bits of the x-coordinate: */
\r
1062 modexSelectPlane(PLANE(x));
\r
1063 //outp(SC_INDEX, 0x02);
\r
1064 //outp(SC_DATA, 0x01 << (x & 3));
\r
1066 /* The offset of the pixel into the video segment is
\r
1067 offset = (width * y + x) / 4, and write the given
\r
1068 color to the plane we selected above. Heed the active
\r
1069 page start selection. */
\r
1070 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
1074 byte modexgetPixel(page_t *page, int x, int y)
\r
1076 word pageOff = (word) page->data;
\r
1077 /* Select the plane from which we must read the pixel color: */
\r
1078 outpw(GC_INDEX, 0x04);
\r
1079 outpw(GC_INDEX+1, x & 3);
\r
1081 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
1085 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
1087 /* vertical drawing routine by joncampbell123.
\r
1089 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
1090 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
1092 * 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
1093 word rows = romFonts[t].charSize;
\r
1101 m1 = 0x80; // left half
\r
1102 m2 = 0x08; // right half
\r
1103 for (colm=0;colm < 4;colm++) {
\r
1105 modexSelectPlane(PLANE(plane));
\r
1106 for (row=0;row < rows;row++) {
\r
1107 fontbyte = romFontsData.l[row];
\r
1108 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
1109 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
1110 drawaddr += page->width >> 2;
\r
1115 if ((++plane) == 4) {
\r
1122 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word color, word bgcolor, boolean vidsw, const byte *str)
\r
1126 //word addr = (word) romFontsData.l;
\r
1134 printf("%s\n", str);
\r
1137 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
1139 addrq = (page->stridew) * y + (word)(x_draw) +
\r
1140 ((word)page->data);
\r
1142 s=romFonts[t].seg;
\r
1143 o=romFonts[t].off;
\r
1144 w=romFonts[t].charSize;
\r
1145 romFontsData.chw=0;
\r
1147 for(; *str != '\0'; str++)
\r
1153 romFontsData.chw = 0;
\r
1154 addrq += (page->stridew) * 8;
\r
1160 // load the character into romFontsData.l
\r
1161 // no need for inline assembly!
\r
1162 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
1163 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
1164 modexDrawChar(page, x_draw/*for mode X planar use*/, t, color, bgcolor, addrr);
\r
1165 x_draw += 8; /* track X for edge of screen */
\r
1166 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
1168 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
1173 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
1175 word i, s, o, w, j, xp;
\r
1177 word addr = (word) l;
\r
1201 s=romFonts[t].seg;
\r
1202 o=romFonts[t].off;
\r
1204 for(; *str != '\0'; str++)
\r
1207 if((c=='\n'/* || c=="\
\r
1208 "*/)/* || chw>=page->width*/)
\r
1214 //load the letter 'A'
\r
1229 MOV AL, c ; the letter
\r
1232 ADD SI, AX ;the address of charcter
\r
1250 for(i=0; i<w; i++)
\r
1256 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1257 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1266 /* palette dump on display! */
\r
1267 void modexpdump(nibble pagenum, global_game_variables_t *gvar)
\r
1269 int mult=(QUADWH);
\r
1270 int palq=(mult)*TILEWH;
\r
1273 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1274 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1275 modexClearRegion(&gvar->video.page[pagenum], palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1279 modexPalSave(gvar->video.palette);
\r
1282 /////////////////////////////////////////////////////////////////////////////
\r
1284 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1285 // the Virtual screen. //
\r
1287 /////////////////////////////////////////////////////////////////////////////
\r
1288 void modexcls(page_t *page, byte color, byte *Where)
\r
1290 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1291 /* set map mask to all 4 planes */
\r
1292 outpw(SC_INDEX, 0xff02);
\r
1293 //_fmemset(VGA, color, 16000);
\r
1294 _fmemset(Where, color, page->stridew*page->height);
\r
1298 // pattern filler from joncampbell123's code
\r
1300 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1302 unsigned int i,j,o, d,h,s;
\r
1308 w=vga_state.vga_width;
\r
1310 s=vga_state.vga_stride;
\r
1314 h=vga_state.vga_height;
\r
1322 w=video->page[pn].width;
\r
1323 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1324 s=video->page[pn].stridew;
\r
1328 h=video->page[pn].height;
\r
1331 if(!pn) h=video->vh;
\r
1332 else h=video->page[pn].height;
\r
1338 /* fill screen/pattern with a distinctive pattern */
\r
1339 for (i=0;i < w;i++) {
\r
1341 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1342 for (j=0;j < h;j++,o += s)
\r
1343 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1348 modexWaitBorder() {
\r
1349 while(inp(INPUT_STATUS_1) & 8) {
\r
1353 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1359 modexWaitBorder_start()
\r
1361 while(inp(INPUT_STATUS_1) & 8) {
\r
1368 modexWaitBorder_end()
\r
1370 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1376 //===========================================================================
\r
1379 // printings of video memory information
\r
1381 void VL_PrintmodexmemInfo(video_t *v)
\r
1385 // printf("========================================\n");
\r
1386 printf("VL_PrintmodexmemInfo:\n");
\r
1387 // printf("========================================\n");
\r
1388 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
1389 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
1390 printf(" stride: %u ", vga_state.vga_stride);
\r
1391 printf("draw_stride: %u ", vga_state.vga_draw_stride);
\r
1392 printf("draw_stride_limit: %u\n", vga_state.vga_draw_stride_limit);
\r
1394 if(v->vmem_remain)
\r
1395 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1396 if(v->num_of_pages)
\r
1399 for(i=0; i<v->num_of_pages;i++)
\r
1401 printf(" [%u]=", i);
\r
1402 printf("(%Fp)", (v->page[i].data));
\r
1403 printf(" size=%u ", v->page[i].pagesize);
\r
1404 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1405 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1406 printf("pi=%u", v->page[i].pi);
\r