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
1038 void modexputPixel(page_t *page, int x, int y, byte color)
\r
1040 word pageOff = (word) page->data;
\r
1041 /* Each address accesses four neighboring pixels, so set
\r
1042 Write Plane Enable according to which pixel we want
\r
1043 to modify. The plane is determined by the two least
\r
1044 significant bits of the x-coordinate: */
\r
1045 modexSelectPlane(PLANE(x));
\r
1046 //outp(SC_INDEX, 0x02);
\r
1047 //outp(SC_DATA, 0x01 << (x & 3));
\r
1049 /* The offset of the pixel into the video segment is
\r
1050 offset = (width * y + x) / 4, and write the given
\r
1051 color to the plane we selected above. Heed the active
\r
1052 page start selection. */
\r
1053 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
1057 byte modexgetPixel(page_t *page, int x, int y)
\r
1059 word pageOff = (word) page->data;
\r
1060 /* Select the plane from which we must read the pixel color: */
\r
1061 outpw(GC_INDEX, 0x04);
\r
1062 outpw(GC_INDEX+1, x & 3);
\r
1064 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
1068 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
1070 /* vertical drawing routine by joncampbell123.
\r
1072 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
1073 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
1075 * 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
1076 word rows = romFonts[t].charSize;
\r
1084 m1 = 0x80; // left half
\r
1085 m2 = 0x08; // right half
\r
1086 for (colm=0;colm < 4;colm++) {
\r
1088 modexSelectPlane(PLANE(plane));
\r
1089 for (row=0;row < rows;row++) {
\r
1090 fontbyte = romFontsData.l[row];
\r
1091 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
1092 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
1093 drawaddr += page->width >> 2;
\r
1098 if ((++plane) == 4) {
\r
1105 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)
\r
1109 //word addr = (word) romFontsData.l;
\r
1117 printf("%s\n", str);
\r
1120 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
1122 addrq = (page->stridew) * y + (word)(x_draw) +
\r
1123 ((word)page->data);
\r
1125 s=romFonts[t].seg;
\r
1126 o=romFonts[t].off;
\r
1127 w=romFonts[t].charSize;
\r
1128 romFontsData.chw=0;
\r
1130 for(; *str != '\0'; str++)
\r
1136 romFontsData.chw = 0;
\r
1137 addrq += (page->stridew) * 8;
\r
1143 // load the character into romFontsData.l
\r
1144 // no need for inline assembly!
\r
1145 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
1146 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
1147 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
1148 x_draw += 8; /* track X for edge of screen */
\r
1149 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
1151 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
1156 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
1158 word i, s, o, w, j, xp;
\r
1160 word addr = (word) l;
\r
1184 s=romFonts[t].seg;
\r
1185 o=romFonts[t].off;
\r
1187 for(; *str != '\0'; str++)
\r
1190 if((c=='\n'/* || c=="\
\r
1191 "*/)/* || chw>=page->width*/)
\r
1197 //load the letter 'A'
\r
1212 MOV AL, c ; the letter
\r
1215 ADD SI, AX ;the address of charcter
\r
1233 for(i=0; i<w; i++)
\r
1239 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1240 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1249 /* palette dump on display! */
\r
1250 void modexpdump(page_t *pee)
\r
1252 int mult=(QUADWH);
\r
1253 int palq=(mult)*TILEWH;
\r
1256 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1257 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1258 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1264 /////////////////////////////////////////////////////////////////////////////
\r
1266 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1267 // the Virtual screen. //
\r
1269 /////////////////////////////////////////////////////////////////////////////
\r
1270 void modexcls(page_t *page, byte color, byte *Where)
\r
1272 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1273 /* set map mask to all 4 planes */
\r
1274 outpw(SC_INDEX, 0xff02);
\r
1275 //_fmemset(VGA, color, 16000);
\r
1276 _fmemset(Where, color, page->stridew*page->height);
\r
1280 // pattern filler from joncampbell123's code
\r
1282 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1284 unsigned int i,j,o, d,h,s;
\r
1290 w=vga_state.vga_width;
\r
1292 s=vga_state.vga_stride;
\r
1296 h=vga_state.vga_height;
\r
1304 w=video->page[pn].width;
\r
1305 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1306 s=video->page[pn].stridew;
\r
1310 h=video->page[pn].height;
\r
1313 if(!pn) h=video->vh;
\r
1314 else h=video->page[pn].height;
\r
1320 /* fill screen/pattern with a distinctive pattern */
\r
1321 for (i=0;i < w;i++) {
\r
1323 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1324 for (j=0;j < h;j++,o += s)
\r
1325 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1330 modexWaitBorder() {
\r
1331 while(inp(INPUT_STATUS_1) & 8) {
\r
1335 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1341 modexWaitBorder_start()
\r
1343 while(inp(INPUT_STATUS_1) & 8) {
\r
1350 modexWaitBorder_end()
\r
1352 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1358 //===========================================================================
\r
1361 // printings of video memory information
\r
1363 void VL_PrintmodexmemInfo(video_t *v)
\r
1367 // printf("========================================\n");
\r
1368 printf("VL_PrintmodexmemInfo:\n");
\r
1369 // printf("========================================\n");
\r
1370 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
1371 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
1373 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1375 for(i=0; i<v->num_of_pages;i++)
\r
1377 printf(" [%u]=", i);
\r
1378 printf("(%Fp)", (v->page[i].data));
\r
1379 printf(" size=%u ", v->page[i].pagesize);
\r
1380 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1381 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1382 printf("pi=%u", v->page[i].pi);
\r