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
368 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
397 modexDefaultPage(page_t *p, video_t *v)
\r
401 /* default page values */
\r
403 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
404 page.data = (vga_state.vga_graphics_ram);
\r
409 page.width = p->sw;
\r
410 page.height = p->sh;
\r
411 if(v->curr_mode == 1)
\r
412 { page.width += TILEWHD;
\r
413 page.height += TILEWHD; }
\r
414 page.ti.tw = page.sw/TILEWH;
\r
415 page.ti.th = page.sh/TILEWH;
\r
416 page.ti.tilesw=page.width/TILEWH;
\r
417 page.ti.tilesh=page.height/TILEWH;
\r
418 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
419 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
420 page.stridew=page.width/4;
\r
421 page.pagesize = (word)(page.stridew)*page.height;
\r
422 page.pi=page.width*4;
\r
428 /* returns the next page in contiguous memory
\r
429 * the next page will be the same size as p, by default
\r
432 modexNextPage(page_t *p) {
\r
435 result.data = p->data + (p->pagesize);
\r
436 result.dx = p->dx; // not used anymore we use page[0].dx
\r
437 result.dy = p->dy; // not used anymore we use page[0].dy
\r
440 result.width = p->width;
\r
441 result.height = p->height;
\r
442 result.ti.tw = p->ti.tw;
\r
443 result.ti.th = p->ti.th;
\r
444 result.ti.tilesw = p->ti.tilesw;
\r
445 result.ti.tilesh = p->ti.tilesh;
\r
446 result.stridew=p->stridew;
\r
447 result.pagesize = p->pagesize;
\r
448 result.pi=result.width*4;
\r
449 result.id = p->id+1;
\r
454 //next page with defined dimentions~
\r
456 modexNextPageFlexibleSize(page_t *p, word x, word y)
\r
460 result.data = p->data + (p->pagesize); /* compute the offset */
\r
461 result.dx = 0; // not used anymore we use page[0].dx
\r
462 result.dy = 0; // not used anymore we use page[0].dy
\r
467 result.ti.tw = result.sw/TILEWH;
\r
468 result.ti.th = result.sh/TILEWH;
\r
469 result.ti.tilesw=result.width/TILEWH;
\r
470 result.ti.tilesh=result.height/TILEWH;
\r
471 result.id = p->id+1;
\r
472 result.stridew=result.width/4;//p->sw/4;
\r
473 result.pagesize = (word)(result.stridew)*result.height;
\r
474 /* switch(result.id)
\r
477 result.pi=p->width*4;
\r
483 result.pi=result.width*4;
\r
488 void modexCalcVmemRemain(video_t *video)
\r
491 //printf("\n\n 1st vmem_remain=%u\n", video->vmem_remain);
\r
492 for(i=0; i<video->num_of_pages; i++)
\r
494 video->vmem_remain-=video->page[i].pagesize;
\r
495 //printf(" [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);
\r
496 //printf(" [%u], vmem_remain=%u\n", i, video->vmem_remain);
\r
500 void VL_Initofs(video_t *video)
\r
502 if(!video->vga_state.bgps)
\r
504 video->ofs.offscreen_ofs = video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);
\r
505 video->ofs.pattern_ofs = (uint16_t)video->page[2].data;
\r
507 video->ofs.offscreen_ofs = 0;
\r
508 video->ofs.pattern_ofs = 0;//(uint16_t)video->page[0].data;
\r
512 void modexHiganbanaPageSetup(video_t *video)
\r
514 video->vmem_remain=65535U;
\r
515 video->num_of_pages=0;
\r
516 (video->page[0]) = modexDefaultPage(&(video->page[0])/*, video*/); video->num_of_pages++; //video->page[0].width += (TILEWHD); video->page[0].height += (TILEWHD);
\r
517 (video->page[1]) = modexNextPage(&(video->page[0])); video->num_of_pages++;
\r
518 //0000 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), (video->page[0]).width, TILEWH*4); video->num_of_pages++;
\r
519 //0000 (video->page[3]) = (video->page[2]); video->num_of_pages++;
\r
520 //// (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), TILEWH*4, TILEWH*4); video->num_of_pages++;
\r
521 //// (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].sw, 208); video->num_of_pages++;
\r
522 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), video->page[0].width, 96); video->num_of_pages++;
\r
523 (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].width, 96); video->num_of_pages++;
\r
524 modexCalcVmemRemain(video);
\r
526 video->sp=video->p = 0; //showpage
\r
527 video->dorender = 1; //render
\r
528 video->vh=video->page[0].height+video->page[1].height+video->page[2].height+video->page[3].height;
\r
532 video->vga_state.omemptr= vga_state.vga_graphics_ram;
\r
533 video->vga_state.vga_draw_stride= vga_state.vga_draw_stride;
\r
534 video->vga_state.vga_draw_stride_limit= vga_state.vga_draw_stride_limit;
\r
535 //sprite render switch and bgpreservation switch
\r
536 video->vga_state.rss= 1;
\r
537 video->vga_state.bgps= 1;
\r
539 //setup the buffersize
\r
540 video->page[0].dx=video->page[0].dy=
\r
541 video->page[1].dx=video->page[1].dy=TILEWH; // 1 tile size buffer
\r
542 video->page[2].dx=video->page[2].dy=
\r
543 video->page[3].dx=video->page[3].dy=0; // cache pages are buffer wwww
\r
547 // move page to appropriate part and show it
\r
550 modexShowPage(page_t *page) {
\r
551 word high_address, low_address, offset;
\r
554 /* calculate offset */
\r
555 offset = (word) page->data;
\r
556 offset += page[0].dy * (page->width >> 2 );
\r
557 offset += page[0].dx >> 2;
\r
559 /* calculate crtcOffset according to virtual width */
\r
560 crtcOffset = page->width >> 3;
\r
562 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
563 low_address = LOW_ADDRESS | (offset << 8);
\r
565 /* wait for appropriate timing and then program CRTC */
\r
566 //+=+= while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
567 outpw(CRTC_INDEX, high_address);
\r
568 outpw(CRTC_INDEX, low_address);
\r
569 outp(CRTC_INDEX, 0x13);
\r
570 outp(CRTC_DATA, crtcOffset);
\r
572 /* wait for one retrace */
\r
573 //+=+= while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
575 /* do PEL panning here */
\r
576 outp(AC_INDEX, 0x33);
\r
577 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
580 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
582 VL_ShowPage(page_t *page, boolean vsync, boolean sr)
\r
584 word high_address, low_address, offset;
\r
587 // calculate offset
\r
588 offset = (word) page->data;
\r
589 offset += page->dy * (page->width >> 2 );
\r
590 offset += page->dx >> 2;
\r
592 // calculate crtcOffset according to virtual width
\r
596 crtcOffset = page->sw >> 3;
\r
600 crtcOffset = page->width >> 3;
\r
604 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
605 low_address = LOW_ADDRESS | (offset << 8);
\r
607 // wait for appropriate timing and then program CRTC
\r
608 if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
609 outpw(CRTC_INDEX, high_address);
\r
610 outpw(CRTC_INDEX, low_address);
\r
611 outp(CRTC_INDEX, 0x13);
\r
612 outp(CRTC_DATA, crtcOffset);
\r
614 // wait for one retrace
\r
615 if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
617 // do PEL panning here
\r
618 outp(AC_INDEX, 0x33);
\r
619 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
620 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
621 vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;
\r
624 //=============================================================================
\r
627 modexPanPage(page_t *page, int dx, int dy) {
\r
633 modexSelectPlane(byte plane) {
\r
634 outp(SC_INDEX, SC_MAPMASK); /* select plane */
\r
635 outp(SC_DATA, plane);
\r
639 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
641 word pageOff = (word) page->data;
\r
642 word xoff=(x>>2); // xoffset that begins each row
\r
643 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
644 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
645 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
647 byte left = lclip[x&0x03];
\r
648 byte right = rclip[(x+w)&0x03];
\r
650 // handle the case which requires an extra group
\r
651 if((x & 0x03) && !((x+w) & 0x03)) {
\r
655 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
666 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
668 MOV DI, poffset ; go to the first pixel
\r
669 MOV DX, SC_INDEX ; point to the map mask
\r
673 MOV AL, color ; get ready to write colors
\r
675 MOV CX, scanCount ; count the line
\r
676 MOV BL, AL ; remember color
\r
677 MOV AL, left ; do the left clip
\r
678 OUT DX, AL ; set the left clip
\r
679 MOV AL, BL ; restore color
\r
680 STOSB ; write the color
\r
682 JZ SCAN_DONE ; handle 1 group stuff
\r
684 ;-- write the main body of the scanline
\r
685 MOV BL, AL ; remember color
\r
686 MOV AL, 0x0f ; write to all pixels
\r
688 MOV AL, BL ; restore color
\r
689 REP STOSB ; write the color
\r
691 MOV BL, AL ; remeber color
\r
693 OUT DX, AL ; do the right clip
\r
694 MOV AL, BL ; restore color
\r
695 STOSB ; write pixel
\r
696 ADD DI, nextRow ; go to the next row
\r
710 /* moved to src/lib/modex16/16render.c */
\r
712 /* copy a region of video memory from one page to another.
\r
713 * It assumes that the left edge of the tile is the same on both
\r
714 * regions and the memory areas do not overlap.
\r
717 modexCopyPageRegion(page_t *dest, page_t *src,
\r
720 word width, word height)
\r
722 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
723 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
724 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
725 word nextSrcRow = src->stridew - scans - 1;
\r
726 word nextDestRow = dest->stridew - scans - 1;
\r
728 byte left = lclip[sx&0x03];
\r
729 byte right = rclip[(sx+width)&0x03];
\r
731 // handle the case which requires an extra group
\r
732 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
736 // 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
748 MOV AX, SCREEN_SEG ; work in the vga space
\r
753 MOV DX, GC_INDEX ; turn off cpu bits
\r
757 MOV AX, SC_INDEX ; point to the mask register
\r
759 MOV AL, SC_MAPMASK ;
\r
767 MOV CX, scans ; the number of latches
\r
769 MOV AL, left ; do the left column
\r
774 MOV AL, 0fh ; do the inner columns
\r
776 REP MOVSB ; copy the pixels
\r
778 MOV AL, right ; do the right column
\r
783 MOV AX, SI ; go the start of the next row
\r
784 ADD AX, nextSrcRow ;
\r
787 ADD AX, nextDestRow ;
\r
790 DEC height ; do the rest of the actions
\r
793 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
794 MOV AL, 0ffh ; none from latches
\r
810 /* fade and flash */
\r
812 modexFadeOn(word fade, byte *palette) {
\r
813 fadePalette(-fade, 64, 64/fade+1, palette);
\r
818 modexFadeOff(word fade, byte *palette) {
\r
819 fadePalette(fade, 0, 64/fade+1, palette);
\r
824 modexFlashOn(word fade, byte *palette) {
\r
825 fadePalette(fade, -64, 64/fade+1, palette);
\r
830 modexFlashOff(word fade, byte *palette) {
\r
831 fadePalette(-fade, 0, 64/fade+1, palette);
\r
836 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
840 /* handle the case where we just update */
\r
842 modexPalUpdate(palette);
\r
846 while(iter > 0) { /* FadeLoop */
\r
847 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
848 tmppal[i] = palette[i] - dim;
\r
849 if(tmppal[i] > 127) {
\r
851 } else if(tmppal[i] > 63) {
\r
855 modexPalUpdate(tmppal);
\r
863 void modexPalSave(byte *palette)
\r
867 outp(PAL_READ_REG, 0); // start at palette entry 0
\r
868 for(i=0; i<PAL_SIZE; i++)
\r
870 palette[i] = inp(PAL_DATA_REG); // read the palette data
\r
878 ptr = m a l l o c(PAL_SIZE);
\r
882 printf("Could not allocate palette.\n");
\r
890 modexLoadPalFile(byte *filename, byte *palette) {
\r
894 // free the palette if it exists
\r
895 //if(*palette) { free(*palette); }
\r
897 // allocate the new palette
\r
898 //*palette = modexNewPal();
\r
901 file = fopen(filename, "rb");
\r
903 printf("Could not open palette file: %s\n", filename);
\r
906 /* read the file */
\r
908 while(!feof(file)) {
\r
909 *ptr++ = fgetc(file);
\r
915 void VL_LoadPalFile(const char *filename, byte *palette, global_game_variables_t *gvar)
\r
917 VL_LoadPalFilewithoffset(filename, palette, 9, gvar);
\r
918 // VL_LoadPalFileCore(palette);
\r
921 void VL_LoadPalFileCore(byte *palette, global_game_variables_t *gvar)
\r
923 VL_LoadPalFilewithoffset("data/16.pal", palette, 0, gvar);
\r
926 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o, global_game_variables_t *gvar)
\r
930 fd = open(filename,O_RDONLY|O_BINARY);
\r
932 read(fd,palette, PAL_SIZE);
\r
935 VL_UpdatePaletteWrite(palette, o, gvar);
\r
939 void VL_UpdatePaletteWrite(byte *palette, word o, global_game_variables_t *gvar)
\r
942 vga_palette_lseek(/*1+*/o);
\r
943 //for (i=o;i < 256-o;i++)
\r
944 for (i=0;i < 256-o;i++)
\r
945 vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);
\r
947 VL_PaletteSync(gvar);
\r
950 void VL_PaletteSync(global_game_variables_t *gvar)
\r
952 modexPalSave(&gvar->video.palette);
\r
956 modexSavePalFile(char *filename, byte *pal) {
\r
960 /* open the file for writing */
\r
961 file = fopen(filename, "wb");
\r
963 printf("Could not open %s for writing\n", filename);
\r
966 /* write the data to the file */
\r
967 fwrite(pal, 1, PAL_SIZE, file);
\r
975 fadePalette(-1, 64, 1, tmppal);
\r
981 fadePalette(-1, -64, 1, tmppal);
\r
986 //moved to 16_vlpal.c
\r
989 modexPalUpdate(byte *p)
\r
992 //modexWaitBorder();
\r
993 vga_wait_for_vsync();
\r
994 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
995 for(i=0; i<PAL_SIZE/2; i++)
\r
997 outp(PAL_DATA_REG, p[i]);
\r
999 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1000 vga_wait_for_vsync();
\r
1001 for(; i<PAL_SIZE; i++)
\r
1003 outp(PAL_DATA_REG, p[(i)]);
\r
1008 //modexPalUpdate0(byte *p)
\r
1009 VL_modexPalScramble(byte *p)
\r
1012 //modexWaitBorder();
\r
1013 vga_wait_for_vsync();
\r
1014 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1015 for(i=0; i<PAL_SIZE/2; i++)
\r
1017 outp(PAL_DATA_REG, rand());
\r
1019 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
1020 vga_wait_for_vsync();
\r
1021 for(; i<PAL_SIZE; i++)
\r
1023 outp(PAL_DATA_REG, rand());
\r
1028 modexPalOverscan(word col)
\r
1030 //modexWaitBorder();
\r
1031 vga_wait_for_vsync();
\r
1032 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
1033 outp(PAL_DATA_REG, col);
\r
1039 void modexputPixel(page_t *page, int x, int y, byte color)
\r
1041 word pageOff = (word) page->data;
\r
1042 /* Each address accesses four neighboring pixels, so set
\r
1043 Write Plane Enable according to which pixel we want
\r
1044 to modify. The plane is determined by the two least
\r
1045 significant bits of the x-coordinate: */
\r
1046 modexSelectPlane(PLANE(x));
\r
1047 //outp(SC_INDEX, 0x02);
\r
1048 //outp(SC_DATA, 0x01 << (x & 3));
\r
1050 /* The offset of the pixel into the video segment is
\r
1051 offset = (width * y + x) / 4, and write the given
\r
1052 color to the plane we selected above. Heed the active
\r
1053 page start selection. */
\r
1054 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
1058 byte modexgetPixel(page_t *page, int x, int y)
\r
1060 word pageOff = (word) page->data;
\r
1061 /* Select the plane from which we must read the pixel color: */
\r
1062 outpw(GC_INDEX, 0x04);
\r
1063 outpw(GC_INDEX+1, x & 3);
\r
1065 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
1069 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
1071 /* vertical drawing routine by joncampbell123.
\r
1073 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
1074 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
1076 * 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
1077 word rows = romFonts[t].charSize;
\r
1085 m1 = 0x80; // left half
\r
1086 m2 = 0x08; // right half
\r
1087 for (colm=0;colm < 4;colm++) {
\r
1089 modexSelectPlane(PLANE(plane));
\r
1090 for (row=0;row < rows;row++) {
\r
1091 fontbyte = romFontsData.l[row];
\r
1092 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
1093 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
1094 drawaddr += page->width >> 2;
\r
1099 if ((++plane) == 4) {
\r
1106 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)
\r
1110 //word addr = (word) romFontsData.l;
\r
1118 printf("%s\n", str);
\r
1121 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
1123 addrq = (page->stridew) * y + (word)(x_draw) +
\r
1124 ((word)page->data);
\r
1126 s=romFonts[t].seg;
\r
1127 o=romFonts[t].off;
\r
1128 w=romFonts[t].charSize;
\r
1129 romFontsData.chw=0;
\r
1131 for(; *str != '\0'; str++)
\r
1137 romFontsData.chw = 0;
\r
1138 addrq += (page->stridew) * 8;
\r
1144 // load the character into romFontsData.l
\r
1145 // no need for inline assembly!
\r
1146 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
1147 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
1148 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
1149 x_draw += 8; /* track X for edge of screen */
\r
1150 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
1152 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
1157 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
1159 word i, s, o, w, j, xp;
\r
1161 word addr = (word) l;
\r
1185 s=romFonts[t].seg;
\r
1186 o=romFonts[t].off;
\r
1188 for(; *str != '\0'; str++)
\r
1191 if((c=='\n'/* || c=="\
\r
1192 "*/)/* || chw>=page->width*/)
\r
1198 //load the letter 'A'
\r
1213 MOV AL, c ; the letter
\r
1216 ADD SI, AX ;the address of charcter
\r
1234 for(i=0; i<w; i++)
\r
1240 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1241 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1250 /* palette dump on display! */
\r
1251 void modexpdump(page_t *pee)
\r
1253 int mult=(QUADWH);
\r
1254 int palq=(mult)*TILEWH;
\r
1257 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1258 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1259 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1265 /////////////////////////////////////////////////////////////////////////////
\r
1267 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1268 // the Virtual screen. //
\r
1270 /////////////////////////////////////////////////////////////////////////////
\r
1271 void modexcls(page_t *page, byte color, byte *Where)
\r
1273 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1274 /* set map mask to all 4 planes */
\r
1275 outpw(SC_INDEX, 0xff02);
\r
1276 //_fmemset(VGA, color, 16000);
\r
1277 _fmemset(Where, color, page->stridew*page->height);
\r
1281 // pattern filler from joncampbell123's code
\r
1283 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1285 unsigned int i,j,o, d,h,s;
\r
1291 w=vga_state.vga_width;
\r
1293 s=vga_state.vga_stride;
\r
1297 h=vga_state.vga_height;
\r
1305 w=video->page[pn].width;
\r
1306 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1307 s=video->page[pn].stridew;
\r
1311 h=video->page[pn].height;
\r
1314 if(!pn) h=video->vh;
\r
1315 else h=video->page[pn].height;
\r
1321 /* fill screen/pattern with a distinctive pattern */
\r
1322 for (i=0;i < w;i++) {
\r
1324 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1325 for (j=0;j < h;j++,o += s)
\r
1326 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1331 modexWaitBorder() {
\r
1332 while(inp(INPUT_STATUS_1) & 8) {
\r
1336 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1342 modexWaitBorder_start()
\r
1344 while(inp(INPUT_STATUS_1) & 8) {
\r
1351 modexWaitBorder_end()
\r
1353 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1359 //===========================================================================
\r
1362 // printings of video memory information
\r
1364 void VL_PrintmodexmemInfo(video_t *v)
\r
1368 // printf("========================================\n");
\r
1369 printf("VL_PrintmodexmemInfo:\n");
\r
1370 // printf("========================================\n");
\r
1371 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
1372 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
1374 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1376 for(i=0; i<v->num_of_pages;i++)
\r
1378 printf(" [%u]=", i);
\r
1379 printf("(%Fp)", (v->page[i].data));
\r
1380 printf(" size=%u ", v->page[i].pagesize);
\r
1381 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1382 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1383 printf("pi=%u", v->page[i].pi);
\r