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
323 gv->video.page[0].sw = vga_state.vga_width = 300; // VGA lib currently does not update this
\r
324 gv->video.page[0].sh = vga_state.vga_height = 200; // VGA lib currently does not update this
\r
325 // virtual width and height. match screen, at first //
\r
326 gv->video.page[0].height = gv->video.page[0].sh;
\r
327 gv->video.page[0].width = gv->video.page[0].sw;
\r
329 cm.offset = (vga_state.vga_width / (4 * 2)); // 320 wide (40 x 4 pixel groups x 2)
\r
332 case 4: // TODO: 160x120 according to ModeX_192x144regs
\r
334 case 5: // TODO: 160x120 according to ModeX_256x192regs
\r
340 vga_state.vga_stride = cm.offset * 2;
\r
341 vga_write_crtc_mode(&cm,0);
\r
343 // clear video memory //
\r
349 dword far*ptr=(dword far*)vga_state.vga_graphics_ram;//VGA; // used for faster screen clearing //
\r
350 vga_write_sequencer(2/*map mask register*/,0xf/*all 4 planes*/);
\r
351 for(i = 0;i < 0x4000; i++) ptr[i] = 0x0000; // 0x4000 x dword = 64KB
\r
352 // fix up the palette and everything //
\r
353 modexPalBlack(); //reset the palette~//
\r
356 // clear the entire buffer space, because int 10h only did 16 k / plane
\r
362 // VL_SetLineWidth (cm.offset, gv);
\r
363 gv->video.ofs.displayofs = 0;
\r
364 gv->video.ofs.bufferofs = gv->video.page[0].width*gv->video.page[0].height;//gvar->video.page[0].pagesize;
\r
365 gv->video.curr_mode=vq;
\r
366 gv->video.VL_Started=1;
\r
369 void modexLeave(void)
\r
371 // VGAmodeX restores original mode and palette
\r
372 VL_vgaSetMode(TEXT_MODE);
\r
377 modexDefaultPage(page_t *p)
\r
381 /* default page values */
\r
383 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
384 page.data = (vga_state.vga_graphics_ram);
\r
389 page.width = p->sw;
\r
390 page.height = p->sh;
\r
391 page.ti.tw = page.sw/TILEWH;
\r
392 page.ti.th = page.sh/TILEWH;
\r
393 page.ti.tilesw=page.width/TILEWH;
\r
394 page.ti.tilesh=page.height/TILEWH;
\r
395 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
396 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
397 page.stridew=page.width/4;
\r
398 page.pagesize = (word)(page.stridew)*page.height;
\r
399 page.pi=page.width*4;
\r
402 if(ggvv->video.curr_mode = 1)
\r
404 page.width += TILEWHD;
\r
405 page.height += TILEWHD;
\r
412 modexDefaultPage(page_t *p, video_t *v)
\r
416 /* default page values */
\r
418 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
419 page.data = (vga_state.vga_graphics_ram);
\r
424 page.width = p->sw;
\r
425 page.height = p->sh;
\r
426 if(v->curr_mode == 1)
\r
427 { page.width += TILEWHD;
\r
428 page.height += TILEWHD; }
\r
429 page.ti.tw = page.sw/TILEWH;
\r
430 page.ti.th = page.sh/TILEWH;
\r
431 page.ti.tilesw=page.width/TILEWH;
\r
432 page.ti.tilesh=page.height/TILEWH;
\r
433 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
434 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
435 page.stridew=page.width/4;
\r
436 page.pagesize = (word)(page.stridew)*page.height;
\r
437 page.pi=page.width*4;
\r
443 /* returns the next page in contiguous memory
\r
444 * the next page will be the same size as p, by default
\r
447 modexNextPage(page_t *p) {
\r
450 result.data = p->data + (p->pagesize);
\r
451 result.dx = p->dx; // not used anymore we use page[0].dx
\r
452 result.dy = p->dy; // not used anymore we use page[0].dy
\r
455 result.width = p->width;
\r
456 result.height = p->height;
\r
457 result.ti.tw = p->ti.tw;
\r
458 result.ti.th = p->ti.th;
\r
459 result.ti.tilesw = p->ti.tilesw;
\r
460 result.ti.tilesh = p->ti.tilesh;
\r
461 result.stridew=p->stridew;
\r
462 result.pagesize = p->pagesize;
\r
463 result.pi=result.width*4;
\r
464 result.id = p->id+1;
\r
469 //next page with defined dimentions~
\r
471 modexNextPageFlexibleSize(page_t *p, word x, word y)
\r
475 result.data = p->data + (p->pagesize); /* compute the offset */
\r
476 result.dx = 0; // not used anymore we use page[0].dx
\r
477 result.dy = 0; // not used anymore we use page[0].dy
\r
482 result.ti.tw = result.sw/TILEWH;
\r
483 result.ti.th = result.sh/TILEWH;
\r
484 result.ti.tilesw=result.width/TILEWH;
\r
485 result.ti.tilesh=result.height/TILEWH;
\r
486 result.id = p->id+1;
\r
487 result.stridew=result.width/4;//p->sw/4;
\r
488 result.pagesize = (word)(result.stridew)*result.height;
\r
489 /* switch(result.id)
\r
492 result.pi=p->width*4;
\r
498 result.pi=result.width*4;
\r
503 void modexCalcVmemRemain(video_t *video)
\r
506 //printf("\n\n 1st vmem_remain=%u\n", video->vmem_remain);
\r
507 for(i=0; i<video->num_of_pages; i++)
\r
509 video->vmem_remain-=video->page[i].pagesize;
\r
510 //printf(" [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);
\r
511 //printf(" [%u], vmem_remain=%u\n", i, video->vmem_remain);
\r
515 void VL_Initofs(video_t *video)
\r
517 if(!video->vga_state.bgps)
\r
519 video->ofs.offscreen_ofs = video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);
\r
520 video->ofs.pattern_ofs = (uint16_t)video->page[2].data;
\r
522 video->ofs.offscreen_ofs = 0;
\r
523 video->ofs.pattern_ofs = 0;//(uint16_t)video->page[0].data;
\r
527 void modexHiganbanaPageSetup(video_t *video)
\r
529 video->vmem_remain=65535U;
\r
530 video->num_of_pages=0;
\r
531 (video->page[0]) = modexDefaultPage(&(video->page[0]), video); video->num_of_pages++; //video->page[0].width += (TILEWHD); video->page[0].height += (TILEWHD);
\r
532 (video->page[1]) = modexNextPage(&(video->page[0])); video->num_of_pages++;
\r
533 //0000 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), (video->page[0]).width, TILEWH*4); video->num_of_pages++;
\r
534 //0000 (video->page[3]) = (video->page[2]); video->num_of_pages++;
\r
535 //// (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), TILEWH*4, TILEWH*4); video->num_of_pages++;
\r
536 //// (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].sw, 208); video->num_of_pages++;
\r
537 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), video->page[0].width, 96); video->num_of_pages++;
\r
538 (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].width, 96); video->num_of_pages++;
\r
539 modexCalcVmemRemain(video);
\r
541 video->sp=video->p = 0; //showpage
\r
542 video->dorender = 1; //render
\r
543 video->vh=video->page[0].height+video->page[1].height+video->page[2].height+video->page[3].height;
\r
547 video->vga_state.omemptr= vga_state.vga_graphics_ram;
\r
548 video->vga_state.vga_draw_stride= vga_state.vga_draw_stride;
\r
549 video->vga_state.vga_draw_stride_limit= vga_state.vga_draw_stride_limit;
\r
550 //sprite render switch and bgpreservation switch
\r
551 video->vga_state.rss= 1;
\r
552 video->vga_state.bgps= 1;
\r
554 //setup the buffersize
\r
555 video->page[0].dx=video->page[0].dy=
\r
556 video->page[1].dx=video->page[1].dy=TILEWH; // 1 tile size buffer
\r
557 video->page[2].dx=video->page[2].dy=
\r
558 video->page[3].dx=video->page[3].dy=0; // cache pages are buffer wwww
\r
562 // move page to appropriate part and show it
\r
565 modexShowPage(page_t *page) {
\r
566 word high_address, low_address, offset;
\r
569 /* calculate offset */
\r
570 offset = (word) page->data;
\r
571 offset += page[0].dy * (page->width >> 2 );
\r
572 offset += page[0].dx >> 2;
\r
574 /* calculate crtcOffset according to virtual width */
\r
575 crtcOffset = page->width >> 3;
\r
577 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
578 low_address = LOW_ADDRESS | (offset << 8);
\r
580 /* wait for appropriate timing and then program CRTC */
\r
581 //+=+= while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
582 outpw(CRTC_INDEX, high_address);
\r
583 outpw(CRTC_INDEX, low_address);
\r
584 outp(CRTC_INDEX, 0x13);
\r
585 outp(CRTC_DATA, crtcOffset);
\r
587 /* wait for one retrace */
\r
588 //+=+= while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
590 /* do PEL panning here */
\r
591 outp(AC_INDEX, 0x33);
\r
592 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
595 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
597 VL_ShowPage(page_t *page, boolean vsync, boolean sr)
\r
599 word high_address, low_address, offset;
\r
602 // calculate offset
\r
603 offset = (word) page->data;
\r
604 offset += page->dy * (page->width >> 2 );
\r
605 offset += page->dx >> 2;
\r
607 // calculate crtcOffset according to virtual width
\r
611 crtcOffset = page->sw >> 3;
\r
615 crtcOffset = page->width >> 3;
\r
619 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
620 low_address = LOW_ADDRESS | (offset << 8);
\r
622 // wait for appropriate timing and then program CRTC
\r
623 if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
624 outpw(CRTC_INDEX, high_address);
\r
625 outpw(CRTC_INDEX, low_address);
\r
626 outp(CRTC_INDEX, 0x13);
\r
627 outp(CRTC_DATA, crtcOffset);
\r
629 // wait for one retrace
\r
630 if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
632 // do PEL panning here
\r
633 outp(AC_INDEX, 0x33);
\r
634 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
635 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
636 vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;
\r
639 //=============================================================================
\r
642 modexPanPage(page_t *page, int dx, int dy) {
\r
648 modexSelectPlane(byte plane) {
\r
649 outp(SC_INDEX, SC_MAPMASK); /* select plane */
\r
650 outp(SC_DATA, plane);
\r
654 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
656 word pageOff = (word) page->data;
\r
657 word xoff=(x>>2); // xoffset that begins each row
\r
658 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
659 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
660 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
662 byte left = lclip[x&0x03];
\r
663 byte right = rclip[(x+w)&0x03];
\r
665 // handle the case which requires an extra group
\r
666 if((x & 0x03) && !((x+w) & 0x03)) {
\r
670 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
681 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
683 MOV DI, poffset ; go to the first pixel
\r
684 MOV DX, SC_INDEX ; point to the map mask
\r
688 MOV AL, color ; get ready to write colors
\r
690 MOV CX, scanCount ; count the line
\r
691 MOV BL, AL ; remember color
\r
692 MOV AL, left ; do the left clip
\r
693 OUT DX, AL ; set the left clip
\r
694 MOV AL, BL ; restore color
\r
695 STOSB ; write the color
\r
697 JZ SCAN_DONE ; handle 1 group stuff
\r
699 ;-- write the main body of the scanline
\r
700 MOV BL, AL ; remember color
\r
701 MOV AL, 0x0f ; write to all pixels
\r
703 MOV AL, BL ; restore color
\r
704 REP STOSB ; write the color
\r
706 MOV BL, AL ; remeber color
\r
708 OUT DX, AL ; do the right clip
\r
709 MOV AL, BL ; restore color
\r
710 STOSB ; write pixel
\r
711 ADD DI, nextRow ; go to the next row
\r
725 /* moved to src/lib/modex16/16render.c */
\r
727 /* copy a region of video memory from one page to another.
\r
728 * It assumes that the left edge of the tile is the same on both
\r
729 * regions and the memory areas do not overlap.
\r
732 modexCopyPageRegion(page_t *dest, page_t *src,
\r
735 word width, word height)
\r
737 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
738 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
739 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
740 word nextSrcRow = src->stridew - scans - 1;
\r
741 word nextDestRow = dest->stridew - scans - 1;
\r
743 byte left = lclip[sx&0x03];
\r
744 byte right = rclip[(sx+width)&0x03];
\r
746 // handle the case which requires an extra group
\r
747 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
751 // 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
763 MOV AX, SCREEN_SEG ; work in the vga space
\r
768 MOV DX, GC_INDEX ; turn off cpu bits
\r
772 MOV AX, SC_INDEX ; point to the mask register
\r
774 MOV AL, SC_MAPMASK ;
\r
782 MOV CX, scans ; the number of latches
\r
784 MOV AL, left ; do the left column
\r
789 MOV AL, 0fh ; do the inner columns
\r
791 REP MOVSB ; copy the pixels
\r
793 MOV AL, right ; do the right column
\r
798 MOV AX, SI ; go the start of the next row
\r
799 ADD AX, nextSrcRow ;
\r
802 ADD AX, nextDestRow ;
\r
805 DEC height ; do the rest of the actions
\r
808 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
809 MOV AL, 0ffh ; none from latches
\r
825 /* fade and flash */
\r
827 modexFadeOn(word fade, byte *palette) {
\r
828 fadePalette(-fade, 64, 64/fade+1, palette);
\r
833 modexFadeOff(word fade, byte *palette) {
\r
834 fadePalette(fade, 0, 64/fade+1, palette);
\r
839 modexFlashOn(word fade, byte *palette) {
\r
840 fadePalette(fade, -64, 64/fade+1, palette);
\r
845 modexFlashOff(word fade, byte *palette) {
\r
846 fadePalette(-fade, 0, 64/fade+1, palette);
\r
851 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
855 /* handle the case where we just update */
\r
857 modexPalUpdate(palette);
\r
861 while(iter > 0) { /* FadeLoop */
\r
862 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
863 tmppal[i] = palette[i] - dim;
\r
864 if(tmppal[i] > 127) {
\r
866 } else if(tmppal[i] > 63) {
\r
870 modexPalUpdate(tmppal);
\r
878 void modexPalSave(byte *palette)
\r
882 outp(PAL_READ_REG, 0); // start at palette entry 0
\r
883 for(i=0; i<PAL_SIZE; i++)
\r
885 palette[i] = inp(PAL_DATA_REG); // read the palette data
\r
893 ptr = m a l l o c(PAL_SIZE);
\r
897 printf("Could not allocate palette.\n");
\r
905 modexLoadPalFile(byte *filename, byte *palette) {
\r
909 // free the palette if it exists
\r
910 //if(*palette) { free(*palette); }
\r
912 // allocate the new palette
\r
913 //*palette = modexNewPal();
\r
916 file = fopen(filename, "rb");
\r
918 printf("Could not open palette file: %s\n", filename);
\r
921 /* read the file */
\r
923 while(!feof(file)) {
\r
924 *ptr++ = fgetc(file);
\r
930 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)
\r
932 VL_LoadPalFilewithoffset(filename, palette, 9, gvar);
\r
933 // VL_LoadPalFileCore(palette);
\r
936 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)
\r
938 VL_LoadPalFilewithoffset("data/16.pal", palette, 0, gvar);
\r
941 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, global_game_variables_t *gvar)
\r
945 fd = open(filename,O_RDONLY|O_BINARY);
\r
947 read(fd,palette, PAL_SIZE);
\r
950 VL_UpdatePaletteWrite(palette, o, gvar);
\r
954 void VL_UpdatePaletteWrite(byte *palette, word o, global_game_variables_t *gvar)
\r
957 vga_palette_lseek(/*1+*/o);
\r
958 //for (i=o;i < 256-o;i++)
\r
959 for (i=0;i < 256-o;i++)
\r
960 vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);
\r
962 VL_PaletteSync(gvar);
\r
965 void VL_PaletteSync(global_game_variables_t *gvar)
\r
967 modexPalSave(&gvar->video.palette);
\r
971 modexSavePalFile(char *filename, byte *pal) {
\r
975 /* open the file for writing */
\r
976 file = fopen(filename, "wb");
\r
978 printf("Could not open %s for writing\n", filename);
\r
981 /* write the data to the file */
\r
982 fwrite(pal, 1, PAL_SIZE, file);
\r
990 fadePalette(-1, 64, 1, tmppal);
\r
996 fadePalette(-1, -64, 1, tmppal);
\r
1001 //moved to 16_vlpal.c
\r
1004 modexPalUpdate(byte *p)
\r
1007 //modexWaitBorder();
\r
1008 vga_wait_for_vsync();
\r
1009 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1010 for(i=0; i<PAL_SIZE/2; i++)
\r
1012 outp(PAL_DATA_REG, p[i]);
\r
1014 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1015 vga_wait_for_vsync();
\r
1016 for(; i<PAL_SIZE; i++)
\r
1018 outp(PAL_DATA_REG, p[(i)]);
\r
1023 //modexPalUpdate0(byte *p)
\r
1024 VL_modexPalScramble(byte *p)
\r
1027 //modexWaitBorder();
\r
1028 vga_wait_for_vsync();
\r
1029 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1030 for(i=0; i<PAL_SIZE/2; i++)
\r
1032 outp(PAL_DATA_REG, rand());
\r
1034 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1035 vga_wait_for_vsync();
\r
1036 for(; i<PAL_SIZE; i++)
\r
1038 outp(PAL_DATA_REG, rand());
\r
1043 modexPalOverscan(word col)
\r
1045 //modexWaitBorder();
\r
1046 vga_wait_for_vsync();
\r
1047 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1048 outp(PAL_DATA_REG, col);
\r
1053 void modexputPixel(page_t *page, int x, int y, byte color)
\r
1055 word pageOff = (word) page->data;
\r
1056 /* Each address accesses four neighboring pixels, so set
\r
1057 Write Plane Enable according to which pixel we want
\r
1058 to modify. The plane is determined by the two least
\r
1059 significant bits of the x-coordinate: */
\r
1060 modexSelectPlane(PLANE(x));
\r
1061 //outp(SC_INDEX, 0x02);
\r
1062 //outp(SC_DATA, 0x01 << (x & 3));
\r
1064 /* The offset of the pixel into the video segment is
\r
1065 offset = (width * y + x) / 4, and write the given
\r
1066 color to the plane we selected above. Heed the active
\r
1067 page start selection. */
\r
1068 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
1072 byte modexgetPixel(page_t *page, int x, int y)
\r
1074 word pageOff = (word) page->data;
\r
1075 /* Select the plane from which we must read the pixel color: */
\r
1076 outpw(GC_INDEX, 0x04);
\r
1077 outpw(GC_INDEX+1, x & 3);
\r
1079 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
1083 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
1085 /* vertical drawing routine by joncampbell123.
\r
1087 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
1088 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
1090 * 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
1091 word rows = romFonts[t].charSize;
\r
1099 m1 = 0x80; // left half
\r
1100 m2 = 0x08; // right half
\r
1101 for (colm=0;colm < 4;colm++) {
\r
1103 modexSelectPlane(PLANE(plane));
\r
1104 for (row=0;row < rows;row++) {
\r
1105 fontbyte = romFontsData.l[row];
\r
1106 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
1107 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
1108 drawaddr += page->width >> 2;
\r
1113 if ((++plane) == 4) {
\r
1120 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)
\r
1124 //word addr = (word) romFontsData.l;
\r
1132 printf("%s\n", str);
\r
1135 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
1137 addrq = (page->stridew) * y + (word)(x_draw) +
\r
1138 ((word)page->data);
\r
1140 s=romFonts[t].seg;
\r
1141 o=romFonts[t].off;
\r
1142 w=romFonts[t].charSize;
\r
1143 romFontsData.chw=0;
\r
1145 for(; *str != '\0'; str++)
\r
1151 romFontsData.chw = 0;
\r
1152 addrq += (page->stridew) * 8;
\r
1158 // load the character into romFontsData.l
\r
1159 // no need for inline assembly!
\r
1160 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
1161 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
1162 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
1163 x_draw += 8; /* track X for edge of screen */
\r
1164 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
1166 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
1171 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
1173 word i, s, o, w, j, xp;
\r
1175 word addr = (word) l;
\r
1199 s=romFonts[t].seg;
\r
1200 o=romFonts[t].off;
\r
1202 for(; *str != '\0'; str++)
\r
1205 if((c=='\n'/* || c=="\
\r
1206 "*/)/* || chw>=page->width*/)
\r
1212 //load the letter 'A'
\r
1227 MOV AL, c ; the letter
\r
1230 ADD SI, AX ;the address of charcter
\r
1248 for(i=0; i<w; i++)
\r
1254 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1255 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1264 /* palette dump on display! */
\r
1265 void modexpdump(page_t *pee)
\r
1267 int mult=(QUADWH);
\r
1268 int palq=(mult)*TILEWH;
\r
1271 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1272 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1273 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1279 /////////////////////////////////////////////////////////////////////////////
\r
1281 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1282 // the Virtual screen. //
\r
1284 /////////////////////////////////////////////////////////////////////////////
\r
1285 void modexcls(page_t *page, byte color, byte *Where)
\r
1287 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1288 /* set map mask to all 4 planes */
\r
1289 outpw(SC_INDEX, 0xff02);
\r
1290 //_fmemset(VGA, color, 16000);
\r
1291 _fmemset(Where, color, page->stridew*page->height);
\r
1295 // pattern filler from joncampbell123's code
\r
1297 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1299 unsigned int i,j,o, d,h,s;
\r
1305 w=vga_state.vga_width;
\r
1307 s=vga_state.vga_stride;
\r
1311 h=vga_state.vga_height;
\r
1319 w=video->page[pn].width;
\r
1320 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1321 s=video->page[pn].stridew;
\r
1325 h=video->page[pn].height;
\r
1328 if(!pn) h=video->vh;
\r
1329 else h=video->page[pn].height;
\r
1335 /* fill screen/pattern with a distinctive pattern */
\r
1336 for (i=0;i < w;i++) {
\r
1338 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1339 for (j=0;j < h;j++,o += s)
\r
1340 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1345 modexWaitBorder() {
\r
1346 while(inp(INPUT_STATUS_1) & 8) {
\r
1350 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1356 modexWaitBorder_start()
\r
1358 while(inp(INPUT_STATUS_1) & 8) {
\r
1365 modexWaitBorder_end()
\r
1367 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1373 //===========================================================================
\r
1376 // printings of video memory information
\r
1378 void VL_PrintmodexmemInfo(video_t *v)
\r
1382 // printf("========================================\n");
\r
1383 printf("VL_PrintmodexmemInfo:\n");
\r
1384 // printf("========================================\n");
\r
1385 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
1386 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
1388 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1390 for(i=0; i<v->num_of_pages;i++)
\r
1392 printf(" [%u]=", i);
\r
1393 printf("(%Fp)", (v->page[i].data));
\r
1394 printf(" size=%u ", v->page[i].pagesize);
\r
1395 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1396 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1397 printf("pi=%u", v->page[i].pi);
\r