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
35 // setvideo() - This function Manages the video modes //
\r
37 /////////////////////////////////////////////////////////////////////////////
\r
38 void VGAmodeX(sword vq, boolean cmem, global_game_variables_t *gv)
\r
44 case 0: // deinit the video
\r
45 // change to the video mode we were in before we switched to mode 13h
\r
46 if(gv->video.VL_Started)
\r
50 in.h.al = gv->video.old_mode;
\r
51 int86(0x10, &in, &out);
\r
53 gv->video.VL_Started=0;
\r
55 default: // init the video
\r
56 if(gv->video.VL_Started)
\r
59 modexEnter(vq, cmem, gv);
\r
65 vgaSetMode(byte mode)
\r
69 regs.h.ah = SET_MODE;
\r
71 int86(VIDEO_INT, ®s, ®s);
\r
72 //int10_setmode(mode);
\r
75 //---------------------------------------------------
\r
77 // Use the bios to get the current video mode
\r
80 byte/*FIXME: why long? "long" is 32-bit datatype, VGA modes are 8-bit numbers. */
\r
83 return int10_getmode();
\r
86 /* -========================= Entry Points ==========================- */
\r
87 void modexEnter(sword vq, boolean cmem, global_game_variables_t *gv)
\r
90 struct vga_mode_params cm;
\r
93 vgaSetMode(VGA_256_COLOR_MODE);
\r
94 vga_enable_256color_modex();
\r
96 update_state_from_vga();
\r
97 vga_read_crtc_mode(&cm);
\r
99 /* reprogram the CRT controller */
\r
100 //outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */
\r
101 //outp(CRTC_DATA, 0x7f); /* get current write protect on varios regs */
\r
106 //CRTParmCount = sizeof(ModeX_320x240regs) / sizeof(ModeX_320x240regs[0]);
\r
107 /*for(i=0; i<CRTParmCount; i++) {
\r
108 outpw(CRTC_INDEX, ModeX_320x240regs[i]);
\r
110 /* width and height */
\r
111 gv->video.page[0].sw = vga_state.vga_width = 320; // VGA lib currently does not update this
\r
112 gv->video.page[0].sh = vga_state.vga_height = 240; // VGA lib currently does not update this
\r
113 /* virtual width and height. match screen, at first */
\r
114 gv->video.page[0].height = gv->video.page[0].sh;
\r
115 gv->video.page[0].width = gv->video.page[0].sw;
\r
117 // mode X BYTE mode
\r
120 // 320x240 mode 60Hz
\r
121 cm.horizontal_total=0x5f + 5; /* CRTC[0] -5 */
\r
122 cm.horizontal_display_end=0x4f + 1; /* CRTC[1] -1 */
\r
123 cm.horizontal_blank_start=0x50 + 1; /* CRTC[2] */
\r
124 // cm.horizontal_blank_end=0x82 + 1; /* CRTC[3] bit 0-4 & CRTC[5] bit 7 *///skewing ^^;
\r
125 cm.horizontal_start_retrace=0x54;/* CRTC[4] */
\r
126 cm.horizontal_end_retrace=0x80; /* CRTC[5] bit 0-4 */
\r
127 //cm.horizontal_start_delay_after_total=0x3e; /* CRTC[3] bit 5-6 */
\r
128 //cm.horizontal_start_delay_after_retrace=0x41; /* CRTC[5] bit 5-6 */
\r
129 cm.vertical_total = 0x20D + 2;
\r
130 cm.vertical_start_retrace = 0x1EA;
\r
131 cm.vertical_end_retrace = 0x1EC;
\r
132 cm.vertical_display_end = 480;
\r
133 cm.vertical_blank_start = 0x1E7 + 1;
\r
134 cm.vertical_blank_end = 0x206 + 1;
\r
135 cm.clock_select = 0; /* misc register = 0xE3 25MHz */
\r
138 cm.offset = (vga_state.vga_width / (4 * 2)); // 320 wide (40 x 4 pixel groups x 2)
\r
140 case 2: // TODO: 160x120 according to ModeX_160x120regs
\r
142 case 3: // TODO: 160x120 according to ModeX_320x200regs
\r
144 case 4: // TODO: 160x120 according to ModeX_192x144regs
\r
146 case 5: // TODO: 160x120 according to ModeX_256x192regs
\r
152 vga_state.vga_stride = cm.offset * 2;
\r
153 vga_write_crtc_mode(&cm,0);
\r
155 /* clear video memory */
\r
159 /* clear video memory */
\r
160 dword far*ptr=(dword far*)vga_state.vga_graphics_ram;//VGA; /* used for faster screen clearing */
\r
161 vga_write_sequencer(2/*map mask register*/,0xf/*all 4 planes*/);
\r
162 for(i = 0;i < 0x4000; i++) ptr[i] = 0x0000; // 0x4000 x dword = 64KB
\r
163 /* fix up the palette and everything */
\r
164 modexPalBlack(); //reset the palette~
\r
168 VL_SetLineWidth (cm.offset, &gv->video.ofs);
\r
169 gv->video.VL_Started=1;
\r
174 /* VGAmodeX restores original mode and palette */
\r
175 vgaSetMode(TEXT_MODE);
\r
179 ====================
\r
183 = Line witdh is in WORDS, 40 words is normal width for vgaplanegr
\r
185 ====================
\r
188 void VL_SetLineWidth (unsigned width, ofs_t *ofs)
\r
193 // set wide virtual screen
\r
195 outport (CRTC_INDEX,CRTC_OFFSET+width*256);
\r
198 // set up lookup tables
\r
200 ofs->linewidth = width*2;
\r
204 for (i=0;i<MAXSCANLINES;i++)
\r
206 ofs->ylookup[i]=offset;
\r
207 offset += ofs->linewidth;
\r
212 modexDefaultPage(page_t *p)
\r
216 /* default page values */
\r
218 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
219 page.data = (vga_state.vga_graphics_ram);
\r
224 page.width = p->sw+TILEWHD;
\r
225 page.height = p->sh+TILEWHD;
\r
226 page.ti.tw = page.sw/TILEWH;
\r
227 page.ti.th = page.sh/TILEWH;
\r
228 page.ti.tilesw=page.width/TILEWH;
\r
229 page.ti.tilesh=page.height/TILEWH;
\r
230 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
231 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
232 page.stridew=page.width/4;
\r
233 page.pagesize = (word)(page.stridew)*page.height;
\r
234 page.pi=page.width*4;
\r
240 /* returns the next page in contiguous memory
\r
241 * the next page will be the same size as p, by default
\r
244 modexNextPage(page_t *p) {
\r
247 result.data = p->data + (p->pagesize);
\r
248 result.dx = p->dx; // not used anymore we use page[0].dx
\r
249 result.dy = p->dy; // not used anymore we use page[0].dy
\r
252 result.width = p->width;
\r
253 result.height = p->height;
\r
254 result.ti.tw = p->ti.tw;
\r
255 result.ti.th = p->ti.th;
\r
256 result.ti.tilesw = p->ti.tilesw;
\r
257 result.ti.tilesh = p->ti.tilesh;
\r
258 result.stridew=p->stridew;
\r
259 result.pagesize = p->pagesize;
\r
260 result.pi=result.width*4;
\r
261 result.id = p->id+1;
\r
266 //next page with defined dimentions~
\r
268 modexNextPageFlexibleSize(page_t *p, word x, word y)
\r
272 result.data = p->data + (p->pagesize); /* compute the offset */
\r
273 result.dx = 0; // not used anymore we use page[0].dx
\r
274 result.dy = 0; // not used anymore we use page[0].dy
\r
279 result.ti.tw = result.sw/TILEWH;
\r
280 result.ti.th = result.sh/TILEWH;
\r
281 result.ti.tilesw=result.width/TILEWH;
\r
282 result.ti.tilesh=result.height/TILEWH;
\r
283 result.id = p->id+1;
\r
284 result.stridew=result.width/4;//p->sw/4;
\r
285 result.pagesize = (word)(result.stridew)*result.height;
\r
286 /* switch(result.id)
\r
289 result.pi=p->width*4;
\r
295 result.pi=result.width*4;
\r
300 void modexCalcVmemRemain(video_t *video)
\r
303 //printf("\n\n 1st vmem_remain=%u\n", video->vmem_remain);
\r
304 for(i=0; i<video->num_of_pages; i++)
\r
306 video->vmem_remain-=video->page[i].pagesize;
\r
307 //printf(" [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);
\r
308 //printf(" [%u], vmem_remain=%u\n", i, video->vmem_remain);
\r
312 void VL_Initofs(video_t *video)
\r
314 if(!video->vga_state.bgps)
\r
316 video->ofs.offscreen_ofs = video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);
\r
317 video->ofs.pattern_ofs = (uint16_t)video->page[2].data;
\r
319 video->ofs.offscreen_ofs = 0;
\r
320 video->ofs.pattern_ofs = 0;//(uint16_t)video->page[0].data;
\r
324 void modexHiganbanaPageSetup(video_t *video)
\r
326 video->vmem_remain=65535U;
\r
327 video->num_of_pages=0;
\r
328 (video->page[0]) = modexDefaultPage(&(video->page[0])); video->num_of_pages++; //video->page[0].width += (TILEWHD); video->page[0].height += (TILEWHD);
\r
329 (video->page[1]) = modexNextPage(&(video->page[0])); video->num_of_pages++;
\r
330 //0000 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), (video->page[0]).width, TILEWH*4); video->num_of_pages++;
\r
331 //0000 (video->page[3]) = (video->page[2]); video->num_of_pages++;
\r
332 //// (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), TILEWH*4, TILEWH*4); video->num_of_pages++;
\r
333 //// (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].sw, 208); video->num_of_pages++;
\r
334 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), video->page[0].width, 96); video->num_of_pages++;
\r
335 (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].width, 96); video->num_of_pages++;
\r
336 modexCalcVmemRemain(video);
\r
338 video->sp=video->p = 0; //showpage
\r
339 video->dorender = 1; //render
\r
340 video->vh=video->page[0].height+video->page[1].height+video->page[2].height+video->page[3].height;
\r
344 video->vga_state.omemptr= vga_state.vga_graphics_ram;
\r
345 video->vga_state.vga_draw_stride= vga_state.vga_draw_stride;
\r
346 video->vga_state.vga_draw_stride_limit= vga_state.vga_draw_stride_limit;
\r
347 //sprite render switch and bgpreservation switch
\r
348 video->vga_state.rss= 1;
\r
349 video->vga_state.bgps= 1;
\r
351 //setup the buffersize
\r
352 video->page[0].dx=video->page[0].dy=
\r
353 video->page[1].dx=video->page[1].dy=TILEWH; // 1 tile size buffer
\r
354 video->page[2].dx=video->page[2].dy=
\r
355 video->page[3].dx=video->page[3].dy=0; // cache pages are buffer wwww
\r
359 // move page to appropriate part and show it
\r
362 modexShowPage(page_t *page) {
\r
363 word high_address, low_address, offset;
\r
366 /* calculate offset */
\r
367 offset = (word) page->data;
\r
368 offset += page[0].dy * (page->width >> 2 );
\r
369 offset += page[0].dx >> 2;
\r
371 /* calculate crtcOffset according to virtual width */
\r
372 crtcOffset = page->width >> 3;
\r
374 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
375 low_address = LOW_ADDRESS | (offset << 8);
\r
377 /* wait for appropriate timing and then program CRTC */
\r
378 //+=+= while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
379 outpw(CRTC_INDEX, high_address);
\r
380 outpw(CRTC_INDEX, low_address);
\r
381 outp(CRTC_INDEX, 0x13);
\r
382 outp(CRTC_DATA, crtcOffset);
\r
384 /* wait for one retrace */
\r
385 //+=+= while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
387 /* do PEL panning here */
\r
388 outp(AC_INDEX, 0x33);
\r
389 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
392 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
394 VL_ShowPage(page_t *page, boolean vsync, boolean sr) {
\r
395 word high_address, low_address, offset;
\r
398 // calculate offset
\r
399 offset = (word) page->data;
\r
400 offset += page->dy * (page->width >> 2 );
\r
401 offset += page->dx >> 2;
\r
403 // calculate crtcOffset according to virtual width
\r
407 crtcOffset = page->sw >> 3;
\r
411 crtcOffset = page->width >> 3;
\r
415 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
416 low_address = LOW_ADDRESS | (offset << 8);
\r
418 // wait for appropriate timing and then program CRTC
\r
419 if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
420 outpw(CRTC_INDEX, high_address);
\r
421 outpw(CRTC_INDEX, low_address);
\r
422 outp(CRTC_INDEX, 0x13);
\r
423 outp(CRTC_DATA, crtcOffset);
\r
425 // wait for one retrace
\r
426 if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
428 // do PEL panning here
\r
429 outp(AC_INDEX, 0x33);
\r
430 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
431 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
434 //=============================================================================
\r
437 modexPanPage(page_t *page, int dx, int dy) {
\r
443 modexSelectPlane(byte plane) {
\r
444 outp(SC_INDEX, MAP_MASK); /* select plane */
\r
445 outp(SC_DATA, plane);
\r
449 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
451 word pageOff = (word) page->data;
\r
452 word xoff=(x>>2); // xoffset that begins each row
\r
453 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
454 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
455 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
457 byte left = lclip[x&0x03];
\r
458 byte right = rclip[(x+w)&0x03];
\r
460 // handle the case which requires an extra group
\r
461 if((x & 0x03) && !((x+w) & 0x03)) {
\r
465 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
476 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
478 MOV DI, poffset ; go to the first pixel
\r
479 MOV DX, SC_INDEX ; point to the map mask
\r
483 MOV AL, color ; get ready to write colors
\r
485 MOV CX, scanCount ; count the line
\r
486 MOV BL, AL ; remember color
\r
487 MOV AL, left ; do the left clip
\r
488 OUT DX, AL ; set the left clip
\r
489 MOV AL, BL ; restore color
\r
490 STOSB ; write the color
\r
492 JZ SCAN_DONE ; handle 1 group stuff
\r
494 ;-- write the main body of the scanline
\r
495 MOV BL, AL ; remember color
\r
496 MOV AL, 0x0f ; write to all pixels
\r
498 MOV AL, BL ; restore color
\r
499 REP STOSB ; write the color
\r
501 MOV BL, AL ; remeber color
\r
503 OUT DX, AL ; do the right clip
\r
504 MOV AL, BL ; restore color
\r
505 STOSB ; write pixel
\r
506 ADD DI, nextRow ; go to the next row
\r
520 /* moved to src/lib/modex16/16render.c */
\r
522 /* copy a region of video memory from one page to another.
\r
523 * It assumes that the left edge of the tile is the same on both
\r
524 * regions and the memory areas do not overlap.
\r
527 modexCopyPageRegion(page_t *dest, page_t *src,
\r
530 word width, word height)
\r
532 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
533 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
534 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
535 word nextSrcRow = src->stridew - scans - 1;
\r
536 word nextDestRow = dest->stridew - scans - 1;
\r
538 byte left = lclip[sx&0x03];
\r
539 byte right = rclip[(sx+width)&0x03];
\r
541 // handle the case which requires an extra group
\r
542 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
546 // 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
558 MOV AX, SCREEN_SEG ; work in the vga space
\r
563 MOV DX, GC_INDEX ; turn off cpu bits
\r
567 MOV AX, SC_INDEX ; point to the mask register
\r
577 MOV CX, scans ; the number of latches
\r
579 MOV AL, left ; do the left column
\r
584 MOV AL, 0fh ; do the inner columns
\r
586 REP MOVSB ; copy the pixels
\r
588 MOV AL, right ; do the right column
\r
593 MOV AX, SI ; go the start of the next row
\r
594 ADD AX, nextSrcRow ;
\r
597 ADD AX, nextDestRow ;
\r
600 DEC height ; do the rest of the actions
\r
603 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
604 MOV AL, 0ffh ; none from latches
\r
620 /* fade and flash */
\r
622 modexFadeOn(word fade, byte *palette) {
\r
623 fadePalette(-fade, 64, 64/fade+1, palette);
\r
628 modexFadeOff(word fade, byte *palette) {
\r
629 fadePalette(fade, 0, 64/fade+1, palette);
\r
634 modexFlashOn(word fade, byte *palette) {
\r
635 fadePalette(fade, -64, 64/fade+1, palette);
\r
640 modexFlashOff(word fade, byte *palette) {
\r
641 fadePalette(-fade, 0, 64/fade+1, palette);
\r
646 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
650 /* handle the case where we just update */
\r
652 modexPalUpdate(palette);
\r
656 while(iter > 0) { /* FadeLoop */
\r
657 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
658 tmppal[i] = palette[i] - dim;
\r
659 if(tmppal[i] > 127) {
\r
661 } else if(tmppal[i] > 63) {
\r
665 modexPalUpdate(tmppal);
\r
672 /* save and load */
\r
674 modexPalSave(byte *palette) {
\r
677 outp(PAL_READ_REG, 0); /* start at palette entry 0 */
\r
678 for(i=0; i<PAL_SIZE; i++) {
\r
679 palette[i] = inp(PAL_DATA_REG); /* read the palette data */
\r
687 ptr = m a l l o c(PAL_SIZE);
\r
691 printf("Could not allocate palette.\n");
\r
699 modexLoadPalFile(byte *filename, byte *palette) {
\r
703 // free the palette if it exists
\r
704 //if(*palette) { free(*palette); }
\r
706 // allocate the new palette
\r
707 //*palette = modexNewPal();
\r
710 file = fopen(filename, "rb");
\r
712 printf("Could not open palette file: %s\n", filename);
\r
715 /* read the file */
\r
717 while(!feof(file)) {
\r
718 *ptr++ = fgetc(file);
\r
725 void VL_LoadPalFile(const char *filename, byte *palette)
\r
727 VL_LoadPalFilewithoffset(filename, palette, 0);
\r
730 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o)
\r
734 fd = open(filename,O_RDONLY|O_BINARY);
\r
736 read(fd,palette, PAL_SIZE);
\r
739 VL_UpdatePaletteWrite(palette, o);
\r
743 void VL_UpdatePaletteWrite(byte *palette, word o)
\r
746 vga_palette_lseek(/*1+*/o);
\r
747 for (i=o;i < 256-o;i++) vga_palette_write(palette[(i*3)+0]>>2,palette[(i*3)+1]>>2,palette[(i*3)+2]>>2);
\r
751 modexSavePalFile(char *filename, byte *pal) {
\r
755 /* open the file for writing */
\r
756 file = fopen(filename, "wb");
\r
758 printf("Could not open %s for writing\n", filename);
\r
761 /* write the data to the file */
\r
762 fwrite(pal, 1, PAL_SIZE, file);
\r
770 fadePalette(-1, 64, 1, tmppal);
\r
776 fadePalette(-1, -64, 1, tmppal);
\r
781 //moved to 16_vlpal.c
\r
784 modexPalUpdate(byte *p)
\r
787 //modexWaitBorder();
\r
788 vga_wait_for_vsync();
\r
789 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
790 for(i=0; i<PAL_SIZE/2; i++)
\r
792 outp(PAL_DATA_REG, p[i]);
\r
794 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
795 vga_wait_for_vsync();
\r
796 for(; i<PAL_SIZE; i++)
\r
798 outp(PAL_DATA_REG, p[(i)]);
\r
803 modexPalUpdate0(byte *p)
\r
806 //modexWaitBorder();
\r
807 vga_wait_for_vsync();
\r
808 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
809 for(i=0; i<PAL_SIZE/2; i++)
\r
811 outp(PAL_DATA_REG, rand());
\r
813 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
814 vga_wait_for_vsync();
\r
815 for(; i<PAL_SIZE; i++)
\r
817 outp(PAL_DATA_REG, rand());
\r
822 modexPalOverscan(word col)
\r
824 //modexWaitBorder();
\r
825 vga_wait_for_vsync();
\r
826 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
827 outp(PAL_DATA_REG, col);
\r
832 void modexputPixel(page_t *page, int x, int y, byte color)
\r
834 word pageOff = (word) page->data;
\r
835 /* Each address accesses four neighboring pixels, so set
\r
836 Write Plane Enable according to which pixel we want
\r
837 to modify. The plane is determined by the two least
\r
838 significant bits of the x-coordinate: */
\r
839 modexSelectPlane(PLANE(x));
\r
840 //outp(SC_INDEX, 0x02);
\r
841 //outp(SC_DATA, 0x01 << (x & 3));
\r
843 /* The offset of the pixel into the video segment is
\r
844 offset = (width * y + x) / 4, and write the given
\r
845 color to the plane we selected above. Heed the active
\r
846 page start selection. */
\r
847 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
851 byte modexgetPixel(page_t *page, int x, int y)
\r
853 word pageOff = (word) page->data;
\r
854 /* Select the plane from which we must read the pixel color: */
\r
855 outpw(GC_INDEX, 0x04);
\r
856 outpw(GC_INDEX+1, x & 3);
\r
858 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
862 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
864 /* vertical drawing routine by joncampbell123.
\r
866 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
867 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
869 * 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
870 word rows = romFonts[t].charSize;
\r
878 m1 = 0x80; // left half
\r
879 m2 = 0x08; // right half
\r
880 for (colm=0;colm < 4;colm++) {
\r
882 modexSelectPlane(PLANE(plane));
\r
883 for (row=0;row < rows;row++) {
\r
884 fontbyte = romFontsData.l[row];
\r
885 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
886 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
887 drawaddr += page->width >> 2;
\r
892 if ((++plane) == 4) {
\r
899 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)
\r
903 //word addr = (word) romFontsData.l;
\r
911 printf("%s\n", str);
\r
914 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
916 addrq = (page->stridew) * y + (word)(x_draw) +
\r
917 ((word)page->data);
\r
921 w=romFonts[t].charSize;
\r
922 romFontsData.chw=0;
\r
924 for(; *str != '\0'; str++)
\r
930 romFontsData.chw = 0;
\r
931 addrq += (page->stridew) * 8;
\r
937 // load the character into romFontsData.l
\r
938 // no need for inline assembly!
\r
939 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
940 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
941 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
942 x_draw += 8; /* track X for edge of screen */
\r
943 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
945 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
950 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
952 word i, s, o, w, j, xp;
\r
954 word addr = (word) l;
\r
981 for(; *str != '\0'; str++)
\r
984 if((c=='\n'/* || c=="\
\r
985 "*/)/* || chw>=page->width*/)
\r
991 //load the letter 'A'
\r
1006 MOV AL, c ; the letter
\r
1009 ADD SI, AX ;the address of charcter
\r
1027 for(i=0; i<w; i++)
\r
1033 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1034 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1043 /* palette dump on display! */
\r
1044 void modexpdump(page_t *pee)
\r
1046 int mult=(QUADWH);
\r
1047 int palq=(mult)*TILEWH;
\r
1050 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1051 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1052 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1058 /////////////////////////////////////////////////////////////////////////////
\r
1060 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1061 // the Virtual screen. //
\r
1063 /////////////////////////////////////////////////////////////////////////////
\r
1064 void modexcls(page_t *page, byte color, byte *Where)
\r
1066 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1067 /* set map mask to all 4 planes */
\r
1068 outpw(SC_INDEX, 0xff02);
\r
1069 //_fmemset(VGA, color, 16000);
\r
1070 _fmemset(Where, color, page->stridew*page->height);
\r
1074 // pattern filler from joncampbell123's code
\r
1076 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1078 unsigned int i,j,o, d,h,s;
\r
1084 w=vga_state.vga_width;
\r
1086 s=vga_state.vga_stride;
\r
1090 h=vga_state.vga_height;
\r
1098 w=video->page[pn].width;
\r
1099 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1100 s=video->page[pn].stridew;
\r
1104 h=video->page[pn].height;
\r
1107 if(!pn) h=video->vh;
\r
1108 else h=video->page[pn].height;
\r
1114 /* fill screen/pattern with a distinctive pattern */
\r
1115 for (i=0;i < w;i++) {
\r
1117 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1118 for (j=0;j < h;j++,o += s)
\r
1119 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1124 modexWaitBorder() {
\r
1125 while(inp(INPUT_STATUS_1) & 8) {
\r
1129 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1135 modexWaitBorder_start()
\r
1137 while(inp(INPUT_STATUS_1) & 8) {
\r
1144 modexWaitBorder_end()
\r
1146 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1152 //===========================================================================
\r
1155 // printings of video memory information
\r
1157 void VL_PrintmodexmemInfo(video_t *v)
\r
1161 // printf("========================================\n");
\r
1162 printf("VL_PrintmodexmemInfo:\n");
\r
1163 // printf("========================================\n");
\r
1164 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
1165 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
1167 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1169 for(i=0; i<v->num_of_pages;i++)
\r
1171 printf(" [%u]=", i);
\r
1172 printf("(%Fp)", (v->page[i].data));
\r
1173 printf(" size=%u ", v->page[i].pagesize);
\r
1174 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1175 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1176 printf("pi=%u", v->page[i].pi);
\r