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.curr_mode=vq;
\r
364 gv->video.VL_Started=1;
\r
367 void modexLeave(void)
\r
369 // VGAmodeX restores original mode and palette
\r
370 VL_vgaSetMode(TEXT_MODE);
\r
375 modexDefaultPage(page_t *p)
\r
379 /* default page values */
\r
381 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
382 page.data = (vga_state.vga_graphics_ram);
\r
387 page.width = p->sw;
\r
388 page.height = p->sh;
\r
389 page.ti.tw = page.sw/TILEWH;
\r
390 page.ti.th = page.sh/TILEWH;
\r
391 page.ti.tilesw=page.width/TILEWH;
\r
392 page.ti.tilesh=page.height/TILEWH;
\r
393 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
394 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
395 page.stridew=page.width/4;
\r
396 page.pagesize = (word)(page.stridew)*page.height;
\r
397 page.pi=page.width*4;
\r
400 if(ggvv->video.curr_mode = 1)
\r
402 page.width += TILEWHD;
\r
403 page.height += TILEWHD;
\r
410 modexDefaultPage(page_t *p, video_t *v)
\r
414 /* default page values */
\r
416 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
417 page.data = (vga_state.vga_graphics_ram);
\r
422 page.width = p->sw;
\r
423 page.height = p->sh;
\r
424 if(v->curr_mode == 1)
\r
425 { page.width += TILEWHD;
\r
426 page.height += TILEWHD; }
\r
427 page.ti.tw = page.sw/TILEWH;
\r
428 page.ti.th = page.sh/TILEWH;
\r
429 page.ti.tilesw=page.width/TILEWH;
\r
430 page.ti.tilesh=page.height/TILEWH;
\r
431 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
432 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
433 page.stridew=page.width/4;
\r
434 page.pagesize = (word)(page.stridew)*page.height;
\r
435 page.pi=page.width*4;
\r
441 /* returns the next page in contiguous memory
\r
442 * the next page will be the same size as p, by default
\r
445 modexNextPage(page_t *p) {
\r
448 result.data = p->data + (p->pagesize);
\r
449 result.dx = p->dx; // not used anymore we use page[0].dx
\r
450 result.dy = p->dy; // not used anymore we use page[0].dy
\r
453 result.width = p->width;
\r
454 result.height = p->height;
\r
455 result.ti.tw = p->ti.tw;
\r
456 result.ti.th = p->ti.th;
\r
457 result.ti.tilesw = p->ti.tilesw;
\r
458 result.ti.tilesh = p->ti.tilesh;
\r
459 result.stridew=p->stridew;
\r
460 result.pagesize = p->pagesize;
\r
461 result.pi=result.width*4;
\r
462 result.id = p->id+1;
\r
467 //next page with defined dimentions~
\r
469 modexNextPageFlexibleSize(page_t *p, word x, word y)
\r
473 result.data = p->data + (p->pagesize); /* compute the offset */
\r
474 result.dx = 0; // not used anymore we use page[0].dx
\r
475 result.dy = 0; // not used anymore we use page[0].dy
\r
480 result.ti.tw = result.sw/TILEWH;
\r
481 result.ti.th = result.sh/TILEWH;
\r
482 result.ti.tilesw=result.width/TILEWH;
\r
483 result.ti.tilesh=result.height/TILEWH;
\r
484 result.id = p->id+1;
\r
485 result.stridew=result.width/4;//p->sw/4;
\r
486 result.pagesize = (word)(result.stridew)*result.height;
\r
487 /* switch(result.id)
\r
490 result.pi=p->width*4;
\r
496 result.pi=result.width*4;
\r
501 void modexCalcVmemRemain(video_t *video)
\r
504 //printf("\n\n 1st vmem_remain=%u\n", video->vmem_remain);
\r
505 for(i=0; i<video->num_of_pages; i++)
\r
507 video->vmem_remain-=video->page[i].pagesize;
\r
508 //printf(" [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);
\r
509 //printf(" [%u], vmem_remain=%u\n", i, video->vmem_remain);
\r
513 void VL_Initofs(video_t *video)
\r
515 if(!video->vga_state.bgps)
\r
517 video->ofs.offscreen_ofs = video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);
\r
518 video->ofs.pattern_ofs = (uint16_t)video->page[2].data;
\r
520 video->ofs.offscreen_ofs = 0;
\r
521 video->ofs.pattern_ofs = 0;//(uint16_t)video->page[0].data;
\r
525 void modexHiganbanaPageSetup(video_t *video)
\r
527 video->vmem_remain=65535U;
\r
528 video->num_of_pages=0;
\r
529 (video->page[0]) = modexDefaultPage(&(video->page[0]), video); video->num_of_pages++; //video->page[0].width += (TILEWHD); video->page[0].height += (TILEWHD);
\r
530 (video->page[1]) = modexNextPage(&(video->page[0])); video->num_of_pages++;
\r
531 //0000 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), (video->page[0]).width, TILEWH*4); video->num_of_pages++;
\r
532 //0000 (video->page[3]) = (video->page[2]); video->num_of_pages++;
\r
533 //// (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), TILEWH*4, TILEWH*4); video->num_of_pages++;
\r
534 //// (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].sw, 208); video->num_of_pages++;
\r
535 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), video->page[0].width, 96); video->num_of_pages++;
\r
536 (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].width, 96); video->num_of_pages++;
\r
537 modexCalcVmemRemain(video);
\r
539 video->sp=video->p = 0; //showpage
\r
540 video->dorender = 1; //render
\r
541 video->vh=video->page[0].height+video->page[1].height+video->page[2].height+video->page[3].height;
\r
545 video->vga_state.omemptr= vga_state.vga_graphics_ram;
\r
546 video->vga_state.vga_draw_stride= vga_state.vga_draw_stride;
\r
547 video->vga_state.vga_draw_stride_limit= vga_state.vga_draw_stride_limit;
\r
548 //sprite render switch and bgpreservation switch
\r
549 video->vga_state.rss= 1;
\r
550 video->vga_state.bgps= 1;
\r
552 //setup the buffersize
\r
553 video->page[0].dx=video->page[0].dy=
\r
554 video->page[1].dx=video->page[1].dy=TILEWH; // 1 tile size buffer
\r
555 video->page[2].dx=video->page[2].dy=
\r
556 video->page[3].dx=video->page[3].dy=0; // cache pages are buffer wwww
\r
560 // move page to appropriate part and show it
\r
563 modexShowPage(page_t *page) {
\r
564 word high_address, low_address, offset;
\r
567 /* calculate offset */
\r
568 offset = (word) page->data;
\r
569 offset += page[0].dy * (page->width >> 2 );
\r
570 offset += page[0].dx >> 2;
\r
572 /* calculate crtcOffset according to virtual width */
\r
573 crtcOffset = page->width >> 3;
\r
575 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
576 low_address = LOW_ADDRESS | (offset << 8);
\r
578 /* wait for appropriate timing and then program CRTC */
\r
579 //+=+= while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
580 outpw(CRTC_INDEX, high_address);
\r
581 outpw(CRTC_INDEX, low_address);
\r
582 outp(CRTC_INDEX, 0x13);
\r
583 outp(CRTC_DATA, crtcOffset);
\r
585 /* wait for one retrace */
\r
586 //+=+= while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
588 /* do PEL panning here */
\r
589 outp(AC_INDEX, 0x33);
\r
590 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
593 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
595 VL_ShowPage(page_t *page, boolean vsync, boolean sr)
\r
597 word high_address, low_address, offset;
\r
600 // calculate offset
\r
601 offset = (word) page->data;
\r
602 offset += page->dy * (page->width >> 2 );
\r
603 offset += page->dx >> 2;
\r
605 // calculate crtcOffset according to virtual width
\r
609 crtcOffset = page->sw >> 3;
\r
613 crtcOffset = page->width >> 3;
\r
617 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
618 low_address = LOW_ADDRESS | (offset << 8);
\r
620 // wait for appropriate timing and then program CRTC
\r
621 if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
622 outpw(CRTC_INDEX, high_address);
\r
623 outpw(CRTC_INDEX, low_address);
\r
624 outp(CRTC_INDEX, 0x13);
\r
625 outp(CRTC_DATA, crtcOffset);
\r
627 // wait for one retrace
\r
628 if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
630 // do PEL panning here
\r
631 outp(AC_INDEX, 0x33);
\r
632 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
633 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
634 vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;
\r
637 //=============================================================================
\r
640 modexPanPage(page_t *page, int dx, int dy) {
\r
646 modexSelectPlane(byte plane) {
\r
647 outp(SC_INDEX, SC_MAPMASK); /* select plane */
\r
648 outp(SC_DATA, plane);
\r
652 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
654 word pageOff = (word) page->data;
\r
655 word xoff=(x>>2); // xoffset that begins each row
\r
656 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
657 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
658 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
660 byte left = lclip[x&0x03];
\r
661 byte right = rclip[(x+w)&0x03];
\r
663 // handle the case which requires an extra group
\r
664 if((x & 0x03) && !((x+w) & 0x03)) {
\r
668 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
679 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
681 MOV DI, poffset ; go to the first pixel
\r
682 MOV DX, SC_INDEX ; point to the map mask
\r
686 MOV AL, color ; get ready to write colors
\r
688 MOV CX, scanCount ; count the line
\r
689 MOV BL, AL ; remember color
\r
690 MOV AL, left ; do the left clip
\r
691 OUT DX, AL ; set the left clip
\r
692 MOV AL, BL ; restore color
\r
693 STOSB ; write the color
\r
695 JZ SCAN_DONE ; handle 1 group stuff
\r
697 ;-- write the main body of the scanline
\r
698 MOV BL, AL ; remember color
\r
699 MOV AL, 0x0f ; write to all pixels
\r
701 MOV AL, BL ; restore color
\r
702 REP STOSB ; write the color
\r
704 MOV BL, AL ; remeber color
\r
706 OUT DX, AL ; do the right clip
\r
707 MOV AL, BL ; restore color
\r
708 STOSB ; write pixel
\r
709 ADD DI, nextRow ; go to the next row
\r
723 /* moved to src/lib/modex16/16render.c */
\r
725 /* copy a region of video memory from one page to another.
\r
726 * It assumes that the left edge of the tile is the same on both
\r
727 * regions and the memory areas do not overlap.
\r
730 modexCopyPageRegion(page_t *dest, page_t *src,
\r
733 word width, word height)
\r
735 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
736 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
737 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
738 word nextSrcRow = src->stridew - scans - 1;
\r
739 word nextDestRow = dest->stridew - scans - 1;
\r
741 byte left = lclip[sx&0x03];
\r
742 byte right = rclip[(sx+width)&0x03];
\r
744 // handle the case which requires an extra group
\r
745 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
749 // 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
761 MOV AX, SCREEN_SEG ; work in the vga space
\r
766 MOV DX, GC_INDEX ; turn off cpu bits
\r
770 MOV AX, SC_INDEX ; point to the mask register
\r
772 MOV AL, SC_MAPMASK ;
\r
780 MOV CX, scans ; the number of latches
\r
782 MOV AL, left ; do the left column
\r
787 MOV AL, 0fh ; do the inner columns
\r
789 REP MOVSB ; copy the pixels
\r
791 MOV AL, right ; do the right column
\r
796 MOV AX, SI ; go the start of the next row
\r
797 ADD AX, nextSrcRow ;
\r
800 ADD AX, nextDestRow ;
\r
803 DEC height ; do the rest of the actions
\r
806 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
807 MOV AL, 0ffh ; none from latches
\r
823 /* fade and flash */
\r
825 modexFadeOn(word fade, byte *palette) {
\r
826 fadePalette(-fade, 64, 64/fade+1, palette);
\r
831 modexFadeOff(word fade, byte *palette) {
\r
832 fadePalette(fade, 0, 64/fade+1, palette);
\r
837 modexFlashOn(word fade, byte *palette) {
\r
838 fadePalette(fade, -64, 64/fade+1, palette);
\r
843 modexFlashOff(word fade, byte *palette) {
\r
844 fadePalette(-fade, 0, 64/fade+1, palette);
\r
849 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
853 /* handle the case where we just update */
\r
855 modexPalUpdate(palette);
\r
859 while(iter > 0) { /* FadeLoop */
\r
860 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
861 tmppal[i] = palette[i] - dim;
\r
862 if(tmppal[i] > 127) {
\r
864 } else if(tmppal[i] > 63) {
\r
868 modexPalUpdate(tmppal);
\r
876 void modexPalSave(byte *palette)
\r
880 outp(PAL_READ_REG, 0); // start at palette entry 0
\r
881 for(i=0; i<PAL_SIZE; i++)
\r
883 palette[i] = inp(PAL_DATA_REG); // read the palette data
\r
891 ptr = m a l l o c(PAL_SIZE);
\r
895 printf("Could not allocate palette.\n");
\r
903 modexLoadPalFile(byte *filename, byte *palette) {
\r
907 // free the palette if it exists
\r
908 //if(*palette) { free(*palette); }
\r
910 // allocate the new palette
\r
911 //*palette = modexNewPal();
\r
914 file = fopen(filename, "rb");
\r
916 printf("Could not open palette file: %s\n", filename);
\r
919 /* read the file */
\r
921 while(!feof(file)) {
\r
922 *ptr++ = fgetc(file);
\r
928 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)
\r
930 VL_LoadPalFilewithoffset(filename, palette, 9, gvar);
\r
931 // VL_LoadPalFileCore(palette);
\r
934 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)
\r
936 VL_LoadPalFilewithoffset("data/16.pal", palette, 0, gvar);
\r
939 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, global_game_variables_t *gvar)
\r
943 fd = open(filename,O_RDONLY|O_BINARY);
\r
945 read(fd,palette, PAL_SIZE);
\r
948 VL_UpdatePaletteWrite(palette, o, gvar);
\r
952 void VL_UpdatePaletteWrite(byte *palette, word o, global_game_variables_t *gvar)
\r
955 vga_palette_lseek(/*1+*/o);
\r
956 //for (i=o;i < 256-o;i++)
\r
957 for (i=0;i < 256-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 modexPalOverscan(word col)
\r
1043 //modexWaitBorder();
\r
1044 vga_wait_for_vsync();
\r
1045 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1046 outp(PAL_DATA_REG, col);
\r
1051 void modexputPixel(page_t *page, int x, int y, byte color)
\r
1053 word pageOff = (word) page->data;
\r
1054 /* Each address accesses four neighboring pixels, so set
\r
1055 Write Plane Enable according to which pixel we want
\r
1056 to modify. The plane is determined by the two least
\r
1057 significant bits of the x-coordinate: */
\r
1058 modexSelectPlane(PLANE(x));
\r
1059 //outp(SC_INDEX, 0x02);
\r
1060 //outp(SC_DATA, 0x01 << (x & 3));
\r
1062 /* The offset of the pixel into the video segment is
\r
1063 offset = (width * y + x) / 4, and write the given
\r
1064 color to the plane we selected above. Heed the active
\r
1065 page start selection. */
\r
1066 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
1070 byte modexgetPixel(page_t *page, int x, int y)
\r
1072 word pageOff = (word) page->data;
\r
1073 /* Select the plane from which we must read the pixel color: */
\r
1074 outpw(GC_INDEX, 0x04);
\r
1075 outpw(GC_INDEX+1, x & 3);
\r
1077 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
1081 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
1083 /* vertical drawing routine by joncampbell123.
\r
1085 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
1086 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
1088 * 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
1089 word rows = romFonts[t].charSize;
\r
1097 m1 = 0x80; // left half
\r
1098 m2 = 0x08; // right half
\r
1099 for (colm=0;colm < 4;colm++) {
\r
1101 modexSelectPlane(PLANE(plane));
\r
1102 for (row=0;row < rows;row++) {
\r
1103 fontbyte = romFontsData.l[row];
\r
1104 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
1105 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
1106 drawaddr += page->width >> 2;
\r
1111 if ((++plane) == 4) {
\r
1118 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)
\r
1122 //word addr = (word) romFontsData.l;
\r
1130 printf("%s\n", str);
\r
1133 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
1135 addrq = (page->stridew) * y + (word)(x_draw) +
\r
1136 ((word)page->data);
\r
1138 s=romFonts[t].seg;
\r
1139 o=romFonts[t].off;
\r
1140 w=romFonts[t].charSize;
\r
1141 romFontsData.chw=0;
\r
1143 for(; *str != '\0'; str++)
\r
1149 romFontsData.chw = 0;
\r
1150 addrq += (page->stridew) * 8;
\r
1156 // load the character into romFontsData.l
\r
1157 // no need for inline assembly!
\r
1158 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
1159 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
1160 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
1161 x_draw += 8; /* track X for edge of screen */
\r
1162 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
1164 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
1169 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
1171 word i, s, o, w, j, xp;
\r
1173 word addr = (word) l;
\r
1197 s=romFonts[t].seg;
\r
1198 o=romFonts[t].off;
\r
1200 for(; *str != '\0'; str++)
\r
1203 if((c=='\n'/* || c=="\
\r
1204 "*/)/* || chw>=page->width*/)
\r
1210 //load the letter 'A'
\r
1225 MOV AL, c ; the letter
\r
1228 ADD SI, AX ;the address of charcter
\r
1246 for(i=0; i<w; i++)
\r
1252 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1253 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1262 /* palette dump on display! */
\r
1263 void modexpdump(page_t *pee)
\r
1265 int mult=(QUADWH);
\r
1266 int palq=(mult)*TILEWH;
\r
1269 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1270 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1271 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1277 /////////////////////////////////////////////////////////////////////////////
\r
1279 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1280 // the Virtual screen. //
\r
1282 /////////////////////////////////////////////////////////////////////////////
\r
1283 void modexcls(page_t *page, byte color, byte *Where)
\r
1285 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1286 /* set map mask to all 4 planes */
\r
1287 outpw(SC_INDEX, 0xff02);
\r
1288 //_fmemset(VGA, color, 16000);
\r
1289 _fmemset(Where, color, page->stridew*page->height);
\r
1293 // pattern filler from joncampbell123's code
\r
1295 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1297 unsigned int i,j,o, d,h,s;
\r
1303 w=vga_state.vga_width;
\r
1305 s=vga_state.vga_stride;
\r
1309 h=vga_state.vga_height;
\r
1317 w=video->page[pn].width;
\r
1318 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1319 s=video->page[pn].stridew;
\r
1323 h=video->page[pn].height;
\r
1326 if(!pn) h=video->vh;
\r
1327 else h=video->page[pn].height;
\r
1333 /* fill screen/pattern with a distinctive pattern */
\r
1334 for (i=0;i < w;i++) {
\r
1336 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1337 for (j=0;j < h;j++,o += s)
\r
1338 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1343 modexWaitBorder() {
\r
1344 while(inp(INPUT_STATUS_1) & 8) {
\r
1348 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1354 modexWaitBorder_start()
\r
1356 while(inp(INPUT_STATUS_1) & 8) {
\r
1363 modexWaitBorder_end()
\r
1365 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1371 //===========================================================================
\r
1374 // printings of video memory information
\r
1376 void VL_PrintmodexmemInfo(video_t *v)
\r
1380 // printf("========================================\n");
\r
1381 printf("VL_PrintmodexmemInfo:\n");
\r
1382 // printf("========================================\n");
\r
1383 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
1384 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
1386 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1388 for(i=0; i<v->num_of_pages;i++)
\r
1390 printf(" [%u]=", i);
\r
1391 printf("(%Fp)", (v->page[i].data));
\r
1392 printf(" size=%u ", v->page[i].pagesize);
\r
1393 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1394 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1395 printf("pi=%u", v->page[i].pi);
\r