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
58 // get old video mode
\r
60 //int86(0x10, &in, &out);
\r
61 gv->video.old_mode = vgaGetMode();//out.h.al;
\r
63 modexEnter(vq, cmem, gv);
\r
69 vgaSetMode(byte mode)
\r
73 regs.h.ah = SET_MODE;
\r
75 int86(VIDEO_INT, ®s, ®s);
\r
76 //int10_setmode(mode);
\r
79 //---------------------------------------------------
\r
81 // Use the bios to get the current video mode
\r
84 byte/*FIXME: why long? "long" is 32-bit datatype, VGA modes are 8-bit numbers. */
\r
87 return int10_getmode();
\r
90 /* -========================= Entry Points ==========================- */
\r
91 void modexEnter(sword vq, boolean cmem, global_game_variables_t *gv)
\r
94 struct vga_mode_params cm;
\r
97 vgaSetMode(VGA_256_COLOR_MODE);
\r
98 vga_enable_256color_modex();
\r
100 update_state_from_vga();
\r
101 vga_read_crtc_mode(&cm);
\r
103 /* reprogram the CRT controller */
\r
104 //outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */
\r
105 //outp(CRTC_DATA, 0x7f); /* get current write protect on varios regs */
\r
110 //CRTParmCount = sizeof(ModeX_320x240regs) / sizeof(ModeX_320x240regs[0]);
\r
111 /*for(i=0; i<CRTParmCount; i++) {
\r
112 outpw(CRTC_INDEX, ModeX_320x240regs[i]);
\r
114 /* width and height */
\r
115 gv->video.page[0].sw = vga_state.vga_width = 320; // VGA lib currently does not update this
\r
116 gv->video.page[0].sh = vga_state.vga_height = 240; // VGA lib currently does not update this
\r
117 /* virtual width and height. match screen, at first */
\r
118 gv->video.page[0].height = gv->video.page[0].sh;
\r
119 gv->video.page[0].width = gv->video.page[0].sw;
\r
121 // mode X BYTE mode
\r
124 // 320x240 mode 60Hz
\r
125 cm.horizontal_total=0x5f + 5; /* CRTC[0] -5 */
\r
126 cm.horizontal_display_end=0x4f + 1; /* CRTC[1] -1 */
\r
127 cm.horizontal_blank_start=0x50 + 1; /* CRTC[2] */
\r
128 // cm.horizontal_blank_end=0x82 + 1; /* CRTC[3] bit 0-4 & CRTC[5] bit 7 *///skewing ^^;
\r
129 cm.horizontal_start_retrace=0x54;/* CRTC[4] */
\r
130 cm.horizontal_end_retrace=0x80; /* CRTC[5] bit 0-4 */
\r
131 //cm.horizontal_start_delay_after_total=0x3e; /* CRTC[3] bit 5-6 */
\r
132 //cm.horizontal_start_delay_after_retrace=0x41; /* CRTC[5] bit 5-6 */
\r
133 cm.vertical_total = 0x20D + 2;
\r
134 cm.vertical_start_retrace = 0x1EA;
\r
135 cm.vertical_end_retrace = 0x1EC;
\r
136 cm.vertical_display_end = 480;
\r
137 cm.vertical_blank_start = 0x1E7 + 1;
\r
138 cm.vertical_blank_end = 0x206 + 1;
\r
139 cm.clock_select = 0; /* misc register = 0xE3 25MHz */
\r
142 cm.offset = (vga_state.vga_width / (4 * 2)); // 320 wide (40 x 4 pixel groups x 2)
\r
144 case 2: // TODO: 160x120 according to ModeX_160x120regs
\r
146 case 3: // TODO: 160x120 according to ModeX_320x200regs
\r
148 case 4: // TODO: 160x120 according to ModeX_192x144regs
\r
150 case 5: // TODO: 160x120 according to ModeX_256x192regs
\r
156 vga_state.vga_stride = cm.offset * 2;
\r
157 vga_write_crtc_mode(&cm,0);
\r
159 /* clear video memory */
\r
163 /* clear video memory */
\r
164 dword far*ptr=(dword far*)vga_state.vga_graphics_ram;//VGA; /* used for faster screen clearing */
\r
165 vga_write_sequencer(2/*map mask register*/,0xf/*all 4 planes*/);
\r
166 for(i = 0;i < 0x4000; i++) ptr[i] = 0x0000; // 0x4000 x dword = 64KB
\r
167 /* fix up the palette and everything */
\r
168 modexPalBlack(); //reset the palette~
\r
172 // VL_SetLineWidth (cm.offset, &gv->video.ofs);
\r
173 gv->video.VL_Started=1;
\r
178 /* VGAmodeX restores original mode and palette */
\r
179 vgaSetMode(TEXT_MODE);
\r
183 modexDefaultPage(page_t *p)
\r
187 /* default page values */
\r
189 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
190 page.data = (vga_state.vga_graphics_ram);
\r
195 page.width = p->sw+TILEWHD;
\r
196 page.height = p->sh+TILEWHD;
\r
197 page.ti.tw = page.sw/TILEWH;
\r
198 page.ti.th = page.sh/TILEWH;
\r
199 page.ti.tilesw=page.width/TILEWH;
\r
200 page.ti.tilesh=page.height/TILEWH;
\r
201 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
202 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
203 page.stridew=page.width/4;
\r
204 page.pagesize = (word)(page.stridew)*page.height;
\r
205 page.pi=page.width*4;
\r
211 /* returns the next page in contiguous memory
\r
212 * the next page will be the same size as p, by default
\r
215 modexNextPage(page_t *p) {
\r
218 result.data = p->data + (p->pagesize);
\r
219 result.dx = p->dx; // not used anymore we use page[0].dx
\r
220 result.dy = p->dy; // not used anymore we use page[0].dy
\r
223 result.width = p->width;
\r
224 result.height = p->height;
\r
225 result.ti.tw = p->ti.tw;
\r
226 result.ti.th = p->ti.th;
\r
227 result.ti.tilesw = p->ti.tilesw;
\r
228 result.ti.tilesh = p->ti.tilesh;
\r
229 result.stridew=p->stridew;
\r
230 result.pagesize = p->pagesize;
\r
231 result.pi=result.width*4;
\r
232 result.id = p->id+1;
\r
237 //next page with defined dimentions~
\r
239 modexNextPageFlexibleSize(page_t *p, word x, word y)
\r
243 result.data = p->data + (p->pagesize); /* compute the offset */
\r
244 result.dx = 0; // not used anymore we use page[0].dx
\r
245 result.dy = 0; // not used anymore we use page[0].dy
\r
250 result.ti.tw = result.sw/TILEWH;
\r
251 result.ti.th = result.sh/TILEWH;
\r
252 result.ti.tilesw=result.width/TILEWH;
\r
253 result.ti.tilesh=result.height/TILEWH;
\r
254 result.id = p->id+1;
\r
255 result.stridew=result.width/4;//p->sw/4;
\r
256 result.pagesize = (word)(result.stridew)*result.height;
\r
257 /* switch(result.id)
\r
260 result.pi=p->width*4;
\r
266 result.pi=result.width*4;
\r
271 void modexCalcVmemRemain(video_t *video)
\r
274 //printf("\n\n 1st vmem_remain=%u\n", video->vmem_remain);
\r
275 for(i=0; i<video->num_of_pages; i++)
\r
277 video->vmem_remain-=video->page[i].pagesize;
\r
278 //printf(" [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);
\r
279 //printf(" [%u], vmem_remain=%u\n", i, video->vmem_remain);
\r
283 void VL_Initofs(video_t *video)
\r
285 if(!video->vga_state.bgps)
\r
287 video->ofs.offscreen_ofs = video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);
\r
288 video->ofs.pattern_ofs = (uint16_t)video->page[2].data;
\r
290 video->ofs.offscreen_ofs = 0;
\r
291 video->ofs.pattern_ofs = 0;//(uint16_t)video->page[0].data;
\r
295 void modexHiganbanaPageSetup(video_t *video)
\r
297 video->vmem_remain=65535U;
\r
298 video->num_of_pages=0;
\r
299 (video->page[0]) = modexDefaultPage(&(video->page[0])); video->num_of_pages++; //video->page[0].width += (TILEWHD); video->page[0].height += (TILEWHD);
\r
300 (video->page[1]) = modexNextPage(&(video->page[0])); video->num_of_pages++;
\r
301 //0000 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), (video->page[0]).width, TILEWH*4); video->num_of_pages++;
\r
302 //0000 (video->page[3]) = (video->page[2]); video->num_of_pages++;
\r
303 //// (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), TILEWH*4, TILEWH*4); video->num_of_pages++;
\r
304 //// (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].sw, 208); video->num_of_pages++;
\r
305 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), video->page[0].width, 96); video->num_of_pages++;
\r
306 (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].width, 96); video->num_of_pages++;
\r
307 modexCalcVmemRemain(video);
\r
309 video->sp=video->p = 0; //showpage
\r
310 video->dorender = 1; //render
\r
311 video->vh=video->page[0].height+video->page[1].height+video->page[2].height+video->page[3].height;
\r
315 video->vga_state.omemptr= vga_state.vga_graphics_ram;
\r
316 video->vga_state.vga_draw_stride= vga_state.vga_draw_stride;
\r
317 video->vga_state.vga_draw_stride_limit= vga_state.vga_draw_stride_limit;
\r
318 //sprite render switch and bgpreservation switch
\r
319 video->vga_state.rss= 1;
\r
320 video->vga_state.bgps= 1;
\r
322 //setup the buffersize
\r
323 video->page[0].dx=video->page[0].dy=
\r
324 video->page[1].dx=video->page[1].dy=TILEWH; // 1 tile size buffer
\r
325 video->page[2].dx=video->page[2].dy=
\r
326 video->page[3].dx=video->page[3].dy=0; // cache pages are buffer wwww
\r
330 // move page to appropriate part and show it
\r
333 modexShowPage(page_t *page) {
\r
334 word high_address, low_address, offset;
\r
337 /* calculate offset */
\r
338 offset = (word) page->data;
\r
339 offset += page[0].dy * (page->width >> 2 );
\r
340 offset += page[0].dx >> 2;
\r
342 /* calculate crtcOffset according to virtual width */
\r
343 crtcOffset = page->width >> 3;
\r
345 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
346 low_address = LOW_ADDRESS | (offset << 8);
\r
348 /* wait for appropriate timing and then program CRTC */
\r
349 //+=+= while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
350 outpw(CRTC_INDEX, high_address);
\r
351 outpw(CRTC_INDEX, low_address);
\r
352 outp(CRTC_INDEX, 0x13);
\r
353 outp(CRTC_DATA, crtcOffset);
\r
355 /* wait for one retrace */
\r
356 //+=+= while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
358 /* do PEL panning here */
\r
359 outp(AC_INDEX, 0x33);
\r
360 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
363 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
365 VL_ShowPage(page_t *page, boolean vsync, boolean sr) {
\r
366 word high_address, low_address, offset;
\r
369 // calculate offset
\r
370 offset = (word) page->data;
\r
371 offset += page->dy * (page->width >> 2 );
\r
372 offset += page->dx >> 2;
\r
374 // calculate crtcOffset according to virtual width
\r
378 crtcOffset = page->sw >> 3;
\r
382 crtcOffset = page->width >> 3;
\r
386 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
387 low_address = LOW_ADDRESS | (offset << 8);
\r
389 // wait for appropriate timing and then program CRTC
\r
390 if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
391 outpw(CRTC_INDEX, high_address);
\r
392 outpw(CRTC_INDEX, low_address);
\r
393 outp(CRTC_INDEX, 0x13);
\r
394 outp(CRTC_DATA, crtcOffset);
\r
396 // wait for one retrace
\r
397 if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
399 // do PEL panning here
\r
400 outp(AC_INDEX, 0x33);
\r
401 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
402 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
405 //=============================================================================
\r
408 modexPanPage(page_t *page, int dx, int dy) {
\r
414 modexSelectPlane(byte plane) {
\r
415 outp(SC_INDEX, MAP_MASK); /* select plane */
\r
416 outp(SC_DATA, plane);
\r
420 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
422 word pageOff = (word) page->data;
\r
423 word xoff=(x>>2); // xoffset that begins each row
\r
424 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
425 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
426 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
428 byte left = lclip[x&0x03];
\r
429 byte right = rclip[(x+w)&0x03];
\r
431 // handle the case which requires an extra group
\r
432 if((x & 0x03) && !((x+w) & 0x03)) {
\r
436 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
447 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
449 MOV DI, poffset ; go to the first pixel
\r
450 MOV DX, SC_INDEX ; point to the map mask
\r
454 MOV AL, color ; get ready to write colors
\r
456 MOV CX, scanCount ; count the line
\r
457 MOV BL, AL ; remember color
\r
458 MOV AL, left ; do the left clip
\r
459 OUT DX, AL ; set the left clip
\r
460 MOV AL, BL ; restore color
\r
461 STOSB ; write the color
\r
463 JZ SCAN_DONE ; handle 1 group stuff
\r
465 ;-- write the main body of the scanline
\r
466 MOV BL, AL ; remember color
\r
467 MOV AL, 0x0f ; write to all pixels
\r
469 MOV AL, BL ; restore color
\r
470 REP STOSB ; write the color
\r
472 MOV BL, AL ; remeber color
\r
474 OUT DX, AL ; do the right clip
\r
475 MOV AL, BL ; restore color
\r
476 STOSB ; write pixel
\r
477 ADD DI, nextRow ; go to the next row
\r
491 /* moved to src/lib/modex16/16render.c */
\r
493 /* copy a region of video memory from one page to another.
\r
494 * It assumes that the left edge of the tile is the same on both
\r
495 * regions and the memory areas do not overlap.
\r
498 modexCopyPageRegion(page_t *dest, page_t *src,
\r
501 word width, word height)
\r
503 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
504 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
505 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
506 word nextSrcRow = src->stridew - scans - 1;
\r
507 word nextDestRow = dest->stridew - scans - 1;
\r
509 byte left = lclip[sx&0x03];
\r
510 byte right = rclip[(sx+width)&0x03];
\r
512 // handle the case which requires an extra group
\r
513 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
517 // 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
529 MOV AX, SCREEN_SEG ; work in the vga space
\r
534 MOV DX, GC_INDEX ; turn off cpu bits
\r
538 MOV AX, SC_INDEX ; point to the mask register
\r
548 MOV CX, scans ; the number of latches
\r
550 MOV AL, left ; do the left column
\r
555 MOV AL, 0fh ; do the inner columns
\r
557 REP MOVSB ; copy the pixels
\r
559 MOV AL, right ; do the right column
\r
564 MOV AX, SI ; go the start of the next row
\r
565 ADD AX, nextSrcRow ;
\r
568 ADD AX, nextDestRow ;
\r
571 DEC height ; do the rest of the actions
\r
574 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
575 MOV AL, 0ffh ; none from latches
\r
591 /* fade and flash */
\r
593 modexFadeOn(word fade, byte *palette) {
\r
594 fadePalette(-fade, 64, 64/fade+1, palette);
\r
599 modexFadeOff(word fade, byte *palette) {
\r
600 fadePalette(fade, 0, 64/fade+1, palette);
\r
605 modexFlashOn(word fade, byte *palette) {
\r
606 fadePalette(fade, -64, 64/fade+1, palette);
\r
611 modexFlashOff(word fade, byte *palette) {
\r
612 fadePalette(-fade, 0, 64/fade+1, palette);
\r
617 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
621 /* handle the case where we just update */
\r
623 modexPalUpdate(palette);
\r
627 while(iter > 0) { /* FadeLoop */
\r
628 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
629 tmppal[i] = palette[i] - dim;
\r
630 if(tmppal[i] > 127) {
\r
632 } else if(tmppal[i] > 63) {
\r
636 modexPalUpdate(tmppal);
\r
643 /* save and load */
\r
645 modexPalSave(byte *palette) {
\r
648 outp(PAL_READ_REG, 0); /* start at palette entry 0 */
\r
649 for(i=0; i<PAL_SIZE; i++) {
\r
650 palette[i] = inp(PAL_DATA_REG); /* read the palette data */
\r
658 ptr = m a l l o c(PAL_SIZE);
\r
662 printf("Could not allocate palette.\n");
\r
670 modexLoadPalFile(byte *filename, byte *palette) {
\r
674 // free the palette if it exists
\r
675 //if(*palette) { free(*palette); }
\r
677 // allocate the new palette
\r
678 //*palette = modexNewPal();
\r
681 file = fopen(filename, "rb");
\r
683 printf("Could not open palette file: %s\n", filename);
\r
686 /* read the file */
\r
688 while(!feof(file)) {
\r
689 *ptr++ = fgetc(file);
\r
696 void VL_LoadPalFile(const char *filename, byte *palette)
\r
698 VL_LoadPalFilewithoffset(filename, palette, 0);
\r
701 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o)
\r
705 fd = open(filename,O_RDONLY|O_BINARY);
\r
707 read(fd,palette, PAL_SIZE);
\r
710 VL_UpdatePaletteWrite(palette, o);
\r
714 void VL_UpdatePaletteWrite(byte *palette, word o)
\r
717 vga_palette_lseek(/*1+*/o);
\r
718 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
722 modexSavePalFile(char *filename, byte *pal) {
\r
726 /* open the file for writing */
\r
727 file = fopen(filename, "wb");
\r
729 printf("Could not open %s for writing\n", filename);
\r
732 /* write the data to the file */
\r
733 fwrite(pal, 1, PAL_SIZE, file);
\r
741 fadePalette(-1, 64, 1, tmppal);
\r
747 fadePalette(-1, -64, 1, tmppal);
\r
752 //moved to 16_vlpal.c
\r
755 modexPalUpdate(byte *p)
\r
758 //modexWaitBorder();
\r
759 vga_wait_for_vsync();
\r
760 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
761 for(i=0; i<PAL_SIZE/2; i++)
\r
763 outp(PAL_DATA_REG, p[i]);
\r
765 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
766 vga_wait_for_vsync();
\r
767 for(; i<PAL_SIZE; i++)
\r
769 outp(PAL_DATA_REG, p[(i)]);
\r
774 //modexPalUpdate0(byte *p)
\r
775 VL_modexPalScramble(byte *p)
\r
778 //modexWaitBorder();
\r
779 vga_wait_for_vsync();
\r
780 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
781 for(i=0; i<PAL_SIZE/2; i++)
\r
783 outp(PAL_DATA_REG, rand());
\r
785 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
786 vga_wait_for_vsync();
\r
787 for(; i<PAL_SIZE; i++)
\r
789 outp(PAL_DATA_REG, rand());
\r
794 modexPalOverscan(word col)
\r
796 //modexWaitBorder();
\r
797 vga_wait_for_vsync();
\r
798 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
799 outp(PAL_DATA_REG, col);
\r
804 void modexputPixel(page_t *page, int x, int y, byte color)
\r
806 word pageOff = (word) page->data;
\r
807 /* Each address accesses four neighboring pixels, so set
\r
808 Write Plane Enable according to which pixel we want
\r
809 to modify. The plane is determined by the two least
\r
810 significant bits of the x-coordinate: */
\r
811 modexSelectPlane(PLANE(x));
\r
812 //outp(SC_INDEX, 0x02);
\r
813 //outp(SC_DATA, 0x01 << (x & 3));
\r
815 /* The offset of the pixel into the video segment is
\r
816 offset = (width * y + x) / 4, and write the given
\r
817 color to the plane we selected above. Heed the active
\r
818 page start selection. */
\r
819 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
823 byte modexgetPixel(page_t *page, int x, int y)
\r
825 word pageOff = (word) page->data;
\r
826 /* Select the plane from which we must read the pixel color: */
\r
827 outpw(GC_INDEX, 0x04);
\r
828 outpw(GC_INDEX+1, x & 3);
\r
830 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
834 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
836 /* vertical drawing routine by joncampbell123.
\r
838 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
839 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
841 * 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
842 word rows = romFonts[t].charSize;
\r
850 m1 = 0x80; // left half
\r
851 m2 = 0x08; // right half
\r
852 for (colm=0;colm < 4;colm++) {
\r
854 modexSelectPlane(PLANE(plane));
\r
855 for (row=0;row < rows;row++) {
\r
856 fontbyte = romFontsData.l[row];
\r
857 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
858 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
859 drawaddr += page->width >> 2;
\r
864 if ((++plane) == 4) {
\r
871 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)
\r
875 //word addr = (word) romFontsData.l;
\r
883 printf("%s\n", str);
\r
886 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
888 addrq = (page->stridew) * y + (word)(x_draw) +
\r
889 ((word)page->data);
\r
893 w=romFonts[t].charSize;
\r
894 romFontsData.chw=0;
\r
896 for(; *str != '\0'; str++)
\r
902 romFontsData.chw = 0;
\r
903 addrq += (page->stridew) * 8;
\r
909 // load the character into romFontsData.l
\r
910 // no need for inline assembly!
\r
911 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
912 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
913 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
914 x_draw += 8; /* track X for edge of screen */
\r
915 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
917 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
922 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
924 word i, s, o, w, j, xp;
\r
926 word addr = (word) l;
\r
953 for(; *str != '\0'; str++)
\r
956 if((c=='\n'/* || c=="\
\r
957 "*/)/* || chw>=page->width*/)
\r
963 //load the letter 'A'
\r
978 MOV AL, c ; the letter
\r
981 ADD SI, AX ;the address of charcter
\r
1005 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1006 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1015 /* palette dump on display! */
\r
1016 void modexpdump(page_t *pee)
\r
1018 int mult=(QUADWH);
\r
1019 int palq=(mult)*TILEWH;
\r
1022 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1023 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1024 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1030 /////////////////////////////////////////////////////////////////////////////
\r
1032 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1033 // the Virtual screen. //
\r
1035 /////////////////////////////////////////////////////////////////////////////
\r
1036 void modexcls(page_t *page, byte color, byte *Where)
\r
1038 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1039 /* set map mask to all 4 planes */
\r
1040 outpw(SC_INDEX, 0xff02);
\r
1041 //_fmemset(VGA, color, 16000);
\r
1042 _fmemset(Where, color, page->stridew*page->height);
\r
1046 // pattern filler from joncampbell123's code
\r
1048 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1050 unsigned int i,j,o, d,h,s;
\r
1056 w=vga_state.vga_width;
\r
1058 s=vga_state.vga_stride;
\r
1062 h=vga_state.vga_height;
\r
1070 w=video->page[pn].width;
\r
1071 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1072 s=video->page[pn].stridew;
\r
1076 h=video->page[pn].height;
\r
1079 if(!pn) h=video->vh;
\r
1080 else h=video->page[pn].height;
\r
1086 /* fill screen/pattern with a distinctive pattern */
\r
1087 for (i=0;i < w;i++) {
\r
1089 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1090 for (j=0;j < h;j++,o += s)
\r
1091 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1096 modexWaitBorder() {
\r
1097 while(inp(INPUT_STATUS_1) & 8) {
\r
1101 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1107 modexWaitBorder_start()
\r
1109 while(inp(INPUT_STATUS_1) & 8) {
\r
1116 modexWaitBorder_end()
\r
1118 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1124 //===========================================================================
\r
1127 // printings of video memory information
\r
1129 void VL_PrintmodexmemInfo(video_t *v)
\r
1133 // printf("========================================\n");
\r
1134 printf("VL_PrintmodexmemInfo:\n");
\r
1135 // printf("========================================\n");
\r
1136 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
1137 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
1139 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1141 for(i=0; i<v->num_of_pages;i++)
\r
1143 printf(" [%u]=", i);
\r
1144 printf("(%Fp)", (v->page[i].data));
\r
1145 printf(" size=%u ", v->page[i].pagesize);
\r
1146 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1147 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1148 printf("pi=%u", v->page[i].pi);
\r