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 if(!gv->video.VL_Initiated)
\r
60 // get old video mode
\r
62 //int86(0x10, &in, &out);
\r
63 gv->video.old_mode = vgaGetMode();//out.h.al;
\r
65 modexEnter(vq, cmem, gv);
\r
71 vgaSetMode(byte mode)
\r
75 regs.h.ah = SET_MODE;
\r
77 int86(VIDEO_INT, ®s, ®s);
\r
78 //int10_setmode(mode);
\r
81 //---------------------------------------------------
\r
83 // Use the bios to get the current video mode
\r
86 byte/*FIXME: why long? "long" is 32-bit datatype, VGA modes are 8-bit numbers. */
\r
89 return int10_getmode();
\r
92 /* -========================= Entry Points ==========================- */
\r
93 void modexEnter(sword vq, boolean cmem, global_game_variables_t *gv)
\r
96 struct vga_mode_params cm;
\r
99 vgaSetMode(VGA_256_COLOR_MODE);
\r
100 vga_enable_256color_modex();
\r
102 update_state_from_vga();
\r
103 vga_read_crtc_mode(&cm);
\r
105 /* reprogram the CRT controller */
\r
106 //outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */
\r
107 //outp(CRTC_DATA, 0x7f); /* get current write protect on varios regs */
\r
112 //CRTParmCount = sizeof(ModeX_320x240regs) / sizeof(ModeX_320x240regs[0]);
\r
113 /*for(i=0; i<CRTParmCount; i++) {
\r
114 outpw(CRTC_INDEX, ModeX_320x240regs[i]);
\r
116 /* width and height */
\r
117 gv->video.page[0].sw = vga_state.vga_width = 320; // VGA lib currently does not update this
\r
118 gv->video.page[0].sh = vga_state.vga_height = 240; // VGA lib currently does not update this
\r
119 /* virtual width and height. match screen, at first */
\r
120 gv->video.page[0].height = gv->video.page[0].sh;
\r
121 gv->video.page[0].width = gv->video.page[0].sw;
\r
123 // mode X BYTE mode
\r
126 // 320x240 mode 60Hz
\r
127 cm.horizontal_total=0x5f + 5; /* CRTC[0] -5 */
\r
128 cm.horizontal_display_end=0x4f + 1; /* CRTC[1] -1 */
\r
129 cm.horizontal_blank_start=0x50 + 1; /* CRTC[2] */
\r
130 // cm.horizontal_blank_end=0x82 + 1; /* CRTC[3] bit 0-4 & CRTC[5] bit 7 *///skewing ^^;
\r
131 cm.horizontal_start_retrace=0x54;/* CRTC[4] */
\r
132 cm.horizontal_end_retrace=0x80; /* CRTC[5] bit 0-4 */
\r
133 //cm.horizontal_start_delay_after_total=0x3e; /* CRTC[3] bit 5-6 */
\r
134 //cm.horizontal_start_delay_after_retrace=0x41; /* CRTC[5] bit 5-6 */
\r
135 cm.vertical_total = 0x20D + 2;
\r
136 cm.vertical_start_retrace = 0x1EA;
\r
137 cm.vertical_end_retrace = 0x1EC;
\r
138 cm.vertical_display_end = 480;
\r
139 cm.vertical_blank_start = 0x1E7 + 1;
\r
140 cm.vertical_blank_end = 0x206 + 1;
\r
141 cm.clock_select = 0; /* misc register = 0xE3 25MHz */
\r
144 cm.offset = (vga_state.vga_width / (4 * 2)); // 320 wide (40 x 4 pixel groups x 2)
\r
146 case 2: // TODO: 160x120 according to ModeX_160x120regs
\r
148 case 3: // TODO: 160x120 according to ModeX_320x200regs
\r
150 case 4: // TODO: 160x120 according to ModeX_192x144regs
\r
152 case 5: // TODO: 160x120 according to ModeX_256x192regs
\r
158 vga_state.vga_stride = cm.offset * 2;
\r
159 vga_write_crtc_mode(&cm,0);
\r
161 /* clear video memory */
\r
165 /* clear video memory */
\r
166 dword far*ptr=(dword far*)vga_state.vga_graphics_ram;//VGA; /* used for faster screen clearing */
\r
167 vga_write_sequencer(2/*map mask register*/,0xf/*all 4 planes*/);
\r
168 for(i = 0;i < 0x4000; i++) ptr[i] = 0x0000; // 0x4000 x dword = 64KB
\r
169 /* fix up the palette and everything */
\r
170 modexPalBlack(); //reset the palette~
\r
174 // VL_SetLineWidth (cm.offset, &gv->video.ofs);
\r
175 gv->video.VL_Started=1;
\r
180 /* VGAmodeX restores original mode and palette */
\r
181 vgaSetMode(TEXT_MODE);
\r
185 modexDefaultPage(page_t *p)
\r
189 /* default page values */
\r
191 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
192 page.data = (vga_state.vga_graphics_ram);
\r
197 page.width = p->sw+TILEWHD;
\r
198 page.height = p->sh+TILEWHD;
\r
199 page.ti.tw = page.sw/TILEWH;
\r
200 page.ti.th = page.sh/TILEWH;
\r
201 page.ti.tilesw=page.width/TILEWH;
\r
202 page.ti.tilesh=page.height/TILEWH;
\r
203 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
204 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
205 page.stridew=page.width/4;
\r
206 page.pagesize = (word)(page.stridew)*page.height;
\r
207 page.pi=page.width*4;
\r
213 /* returns the next page in contiguous memory
\r
214 * the next page will be the same size as p, by default
\r
217 modexNextPage(page_t *p) {
\r
220 result.data = p->data + (p->pagesize);
\r
221 result.dx = p->dx; // not used anymore we use page[0].dx
\r
222 result.dy = p->dy; // not used anymore we use page[0].dy
\r
225 result.width = p->width;
\r
226 result.height = p->height;
\r
227 result.ti.tw = p->ti.tw;
\r
228 result.ti.th = p->ti.th;
\r
229 result.ti.tilesw = p->ti.tilesw;
\r
230 result.ti.tilesh = p->ti.tilesh;
\r
231 result.stridew=p->stridew;
\r
232 result.pagesize = p->pagesize;
\r
233 result.pi=result.width*4;
\r
234 result.id = p->id+1;
\r
239 //next page with defined dimentions~
\r
241 modexNextPageFlexibleSize(page_t *p, word x, word y)
\r
245 result.data = p->data + (p->pagesize); /* compute the offset */
\r
246 result.dx = 0; // not used anymore we use page[0].dx
\r
247 result.dy = 0; // not used anymore we use page[0].dy
\r
252 result.ti.tw = result.sw/TILEWH;
\r
253 result.ti.th = result.sh/TILEWH;
\r
254 result.ti.tilesw=result.width/TILEWH;
\r
255 result.ti.tilesh=result.height/TILEWH;
\r
256 result.id = p->id+1;
\r
257 result.stridew=result.width/4;//p->sw/4;
\r
258 result.pagesize = (word)(result.stridew)*result.height;
\r
259 /* switch(result.id)
\r
262 result.pi=p->width*4;
\r
268 result.pi=result.width*4;
\r
273 void modexCalcVmemRemain(video_t *video)
\r
276 //printf("\n\n 1st vmem_remain=%u\n", video->vmem_remain);
\r
277 for(i=0; i<video->num_of_pages; i++)
\r
279 video->vmem_remain-=video->page[i].pagesize;
\r
280 //printf(" [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);
\r
281 //printf(" [%u], vmem_remain=%u\n", i, video->vmem_remain);
\r
285 void VL_Initofs(video_t *video)
\r
287 if(!video->vga_state.bgps)
\r
289 video->ofs.offscreen_ofs = video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);
\r
290 video->ofs.pattern_ofs = (uint16_t)video->page[2].data;
\r
292 video->ofs.offscreen_ofs = 0;
\r
293 video->ofs.pattern_ofs = 0;//(uint16_t)video->page[0].data;
\r
297 void modexHiganbanaPageSetup(video_t *video)
\r
299 video->vmem_remain=65535U;
\r
300 video->num_of_pages=0;
\r
301 (video->page[0]) = modexDefaultPage(&(video->page[0])); video->num_of_pages++; //video->page[0].width += (TILEWHD); video->page[0].height += (TILEWHD);
\r
302 (video->page[1]) = modexNextPage(&(video->page[0])); video->num_of_pages++;
\r
303 //0000 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), (video->page[0]).width, TILEWH*4); video->num_of_pages++;
\r
304 //0000 (video->page[3]) = (video->page[2]); video->num_of_pages++;
\r
305 //// (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), TILEWH*4, TILEWH*4); video->num_of_pages++;
\r
306 //// (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].sw, 208); video->num_of_pages++;
\r
307 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), video->page[0].width, 96); video->num_of_pages++;
\r
308 (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].width, 96); video->num_of_pages++;
\r
309 modexCalcVmemRemain(video);
\r
311 video->sp=video->p = 0; //showpage
\r
312 video->dorender = 1; //render
\r
313 video->vh=video->page[0].height+video->page[1].height+video->page[2].height+video->page[3].height;
\r
317 video->vga_state.omemptr= vga_state.vga_graphics_ram;
\r
318 video->vga_state.vga_draw_stride= vga_state.vga_draw_stride;
\r
319 video->vga_state.vga_draw_stride_limit= vga_state.vga_draw_stride_limit;
\r
320 //sprite render switch and bgpreservation switch
\r
321 video->vga_state.rss= 1;
\r
322 video->vga_state.bgps= 1;
\r
324 //setup the buffersize
\r
325 video->page[0].dx=video->page[0].dy=
\r
326 video->page[1].dx=video->page[1].dy=TILEWH; // 1 tile size buffer
\r
327 video->page[2].dx=video->page[2].dy=
\r
328 video->page[3].dx=video->page[3].dy=0; // cache pages are buffer wwww
\r
332 // move page to appropriate part and show it
\r
335 modexShowPage(page_t *page) {
\r
336 word high_address, low_address, offset;
\r
339 /* calculate offset */
\r
340 offset = (word) page->data;
\r
341 offset += page[0].dy * (page->width >> 2 );
\r
342 offset += page[0].dx >> 2;
\r
344 /* calculate crtcOffset according to virtual width */
\r
345 crtcOffset = page->width >> 3;
\r
347 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
348 low_address = LOW_ADDRESS | (offset << 8);
\r
350 /* wait for appropriate timing and then program CRTC */
\r
351 //+=+= while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
352 outpw(CRTC_INDEX, high_address);
\r
353 outpw(CRTC_INDEX, low_address);
\r
354 outp(CRTC_INDEX, 0x13);
\r
355 outp(CRTC_DATA, crtcOffset);
\r
357 /* wait for one retrace */
\r
358 //+=+= while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
360 /* do PEL panning here */
\r
361 outp(AC_INDEX, 0x33);
\r
362 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
365 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
367 VL_ShowPage(page_t *page, boolean vsync, boolean sr) {
\r
368 word high_address, low_address, offset;
\r
371 // calculate offset
\r
372 offset = (word) page->data;
\r
373 offset += page->dy * (page->width >> 2 );
\r
374 offset += page->dx >> 2;
\r
376 // calculate crtcOffset according to virtual width
\r
380 crtcOffset = page->sw >> 3;
\r
384 crtcOffset = page->width >> 3;
\r
388 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
389 low_address = LOW_ADDRESS | (offset << 8);
\r
391 // wait for appropriate timing and then program CRTC
\r
392 if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
393 outpw(CRTC_INDEX, high_address);
\r
394 outpw(CRTC_INDEX, low_address);
\r
395 outp(CRTC_INDEX, 0x13);
\r
396 outp(CRTC_DATA, crtcOffset);
\r
398 // wait for one retrace
\r
399 if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
401 // do PEL panning here
\r
402 outp(AC_INDEX, 0x33);
\r
403 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
404 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
407 //=============================================================================
\r
410 modexPanPage(page_t *page, int dx, int dy) {
\r
416 modexSelectPlane(byte plane) {
\r
417 outp(SC_INDEX, SC_MAPMASK); /* select plane */
\r
418 outp(SC_DATA, plane);
\r
422 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
424 word pageOff = (word) page->data;
\r
425 word xoff=(x>>2); // xoffset that begins each row
\r
426 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
427 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
428 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
430 byte left = lclip[x&0x03];
\r
431 byte right = rclip[(x+w)&0x03];
\r
433 // handle the case which requires an extra group
\r
434 if((x & 0x03) && !((x+w) & 0x03)) {
\r
438 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
449 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
451 MOV DI, poffset ; go to the first pixel
\r
452 MOV DX, SC_INDEX ; point to the map mask
\r
456 MOV AL, color ; get ready to write colors
\r
458 MOV CX, scanCount ; count the line
\r
459 MOV BL, AL ; remember color
\r
460 MOV AL, left ; do the left clip
\r
461 OUT DX, AL ; set the left clip
\r
462 MOV AL, BL ; restore color
\r
463 STOSB ; write the color
\r
465 JZ SCAN_DONE ; handle 1 group stuff
\r
467 ;-- write the main body of the scanline
\r
468 MOV BL, AL ; remember color
\r
469 MOV AL, 0x0f ; write to all pixels
\r
471 MOV AL, BL ; restore color
\r
472 REP STOSB ; write the color
\r
474 MOV BL, AL ; remeber color
\r
476 OUT DX, AL ; do the right clip
\r
477 MOV AL, BL ; restore color
\r
478 STOSB ; write pixel
\r
479 ADD DI, nextRow ; go to the next row
\r
493 /* moved to src/lib/modex16/16render.c */
\r
495 /* copy a region of video memory from one page to another.
\r
496 * It assumes that the left edge of the tile is the same on both
\r
497 * regions and the memory areas do not overlap.
\r
500 modexCopyPageRegion(page_t *dest, page_t *src,
\r
503 word width, word height)
\r
505 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
506 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
507 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
508 word nextSrcRow = src->stridew - scans - 1;
\r
509 word nextDestRow = dest->stridew - scans - 1;
\r
511 byte left = lclip[sx&0x03];
\r
512 byte right = rclip[(sx+width)&0x03];
\r
514 // handle the case which requires an extra group
\r
515 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
519 // 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
531 MOV AX, SCREEN_SEG ; work in the vga space
\r
536 MOV DX, GC_INDEX ; turn off cpu bits
\r
540 MOV AX, SC_INDEX ; point to the mask register
\r
542 MOV AL, SC_MAPMASK ;
\r
550 MOV CX, scans ; the number of latches
\r
552 MOV AL, left ; do the left column
\r
557 MOV AL, 0fh ; do the inner columns
\r
559 REP MOVSB ; copy the pixels
\r
561 MOV AL, right ; do the right column
\r
566 MOV AX, SI ; go the start of the next row
\r
567 ADD AX, nextSrcRow ;
\r
570 ADD AX, nextDestRow ;
\r
573 DEC height ; do the rest of the actions
\r
576 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
577 MOV AL, 0ffh ; none from latches
\r
593 /* fade and flash */
\r
595 modexFadeOn(word fade, byte *palette) {
\r
596 fadePalette(-fade, 64, 64/fade+1, palette);
\r
601 modexFadeOff(word fade, byte *palette) {
\r
602 fadePalette(fade, 0, 64/fade+1, palette);
\r
607 modexFlashOn(word fade, byte *palette) {
\r
608 fadePalette(fade, -64, 64/fade+1, palette);
\r
613 modexFlashOff(word fade, byte *palette) {
\r
614 fadePalette(-fade, 0, 64/fade+1, palette);
\r
619 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
623 /* handle the case where we just update */
\r
625 modexPalUpdate(palette);
\r
629 while(iter > 0) { /* FadeLoop */
\r
630 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
631 tmppal[i] = palette[i] - dim;
\r
632 if(tmppal[i] > 127) {
\r
634 } else if(tmppal[i] > 63) {
\r
638 modexPalUpdate(tmppal);
\r
645 /* save and load */
\r
647 modexPalSave(byte *palette) {
\r
650 outp(PAL_READ_REG, 0); /* start at palette entry 0 */
\r
651 for(i=0; i<PAL_SIZE; i++) {
\r
652 palette[i] = inp(PAL_DATA_REG); /* read the palette data */
\r
660 ptr = m a l l o c(PAL_SIZE);
\r
664 printf("Could not allocate palette.\n");
\r
672 modexLoadPalFile(byte *filename, byte *palette) {
\r
676 // free the palette if it exists
\r
677 //if(*palette) { free(*palette); }
\r
679 // allocate the new palette
\r
680 //*palette = modexNewPal();
\r
683 file = fopen(filename, "rb");
\r
685 printf("Could not open palette file: %s\n", filename);
\r
688 /* read the file */
\r
690 while(!feof(file)) {
\r
691 *ptr++ = fgetc(file);
\r
698 void VL_LoadPalFile(const char *filename, byte *palette)
\r
700 VL_LoadPalFilewithoffset(filename, palette, 0);
\r
703 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o)
\r
707 fd = open(filename,O_RDONLY|O_BINARY);
\r
709 read(fd,palette, PAL_SIZE);
\r
712 VL_UpdatePaletteWrite(palette, o);
\r
716 void VL_UpdatePaletteWrite(byte *palette, word o)
\r
719 vga_palette_lseek(/*1+*/o);
\r
720 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
724 modexSavePalFile(char *filename, byte *pal) {
\r
728 /* open the file for writing */
\r
729 file = fopen(filename, "wb");
\r
731 printf("Could not open %s for writing\n", filename);
\r
734 /* write the data to the file */
\r
735 fwrite(pal, 1, PAL_SIZE, file);
\r
743 fadePalette(-1, 64, 1, tmppal);
\r
749 fadePalette(-1, -64, 1, tmppal);
\r
754 //moved to 16_vlpal.c
\r
757 modexPalUpdate(byte *p)
\r
760 //modexWaitBorder();
\r
761 vga_wait_for_vsync();
\r
762 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
763 for(i=0; i<PAL_SIZE/2; i++)
\r
765 outp(PAL_DATA_REG, p[i]);
\r
767 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
768 vga_wait_for_vsync();
\r
769 for(; i<PAL_SIZE; i++)
\r
771 outp(PAL_DATA_REG, p[(i)]);
\r
776 //modexPalUpdate0(byte *p)
\r
777 VL_modexPalScramble(byte *p)
\r
780 //modexWaitBorder();
\r
781 vga_wait_for_vsync();
\r
782 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
783 for(i=0; i<PAL_SIZE/2; i++)
\r
785 outp(PAL_DATA_REG, rand());
\r
787 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
788 vga_wait_for_vsync();
\r
789 for(; i<PAL_SIZE; i++)
\r
791 outp(PAL_DATA_REG, rand());
\r
796 modexPalOverscan(word col)
\r
798 //modexWaitBorder();
\r
799 vga_wait_for_vsync();
\r
800 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
801 outp(PAL_DATA_REG, col);
\r
806 void modexputPixel(page_t *page, int x, int y, byte color)
\r
808 word pageOff = (word) page->data;
\r
809 /* Each address accesses four neighboring pixels, so set
\r
810 Write Plane Enable according to which pixel we want
\r
811 to modify. The plane is determined by the two least
\r
812 significant bits of the x-coordinate: */
\r
813 modexSelectPlane(PLANE(x));
\r
814 //outp(SC_INDEX, 0x02);
\r
815 //outp(SC_DATA, 0x01 << (x & 3));
\r
817 /* The offset of the pixel into the video segment is
\r
818 offset = (width * y + x) / 4, and write the given
\r
819 color to the plane we selected above. Heed the active
\r
820 page start selection. */
\r
821 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
825 byte modexgetPixel(page_t *page, int x, int y)
\r
827 word pageOff = (word) page->data;
\r
828 /* Select the plane from which we must read the pixel color: */
\r
829 outpw(GC_INDEX, 0x04);
\r
830 outpw(GC_INDEX+1, x & 3);
\r
832 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
836 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
838 /* vertical drawing routine by joncampbell123.
\r
840 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
841 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
843 * 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
844 word rows = romFonts[t].charSize;
\r
852 m1 = 0x80; // left half
\r
853 m2 = 0x08; // right half
\r
854 for (colm=0;colm < 4;colm++) {
\r
856 modexSelectPlane(PLANE(plane));
\r
857 for (row=0;row < rows;row++) {
\r
858 fontbyte = romFontsData.l[row];
\r
859 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
860 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
861 drawaddr += page->width >> 2;
\r
866 if ((++plane) == 4) {
\r
873 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)
\r
877 //word addr = (word) romFontsData.l;
\r
885 printf("%s\n", str);
\r
888 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
890 addrq = (page->stridew) * y + (word)(x_draw) +
\r
891 ((word)page->data);
\r
895 w=romFonts[t].charSize;
\r
896 romFontsData.chw=0;
\r
898 for(; *str != '\0'; str++)
\r
904 romFontsData.chw = 0;
\r
905 addrq += (page->stridew) * 8;
\r
911 // load the character into romFontsData.l
\r
912 // no need for inline assembly!
\r
913 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
914 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
915 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
916 x_draw += 8; /* track X for edge of screen */
\r
917 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
919 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
924 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
926 word i, s, o, w, j, xp;
\r
928 word addr = (word) l;
\r
955 for(; *str != '\0'; str++)
\r
958 if((c=='\n'/* || c=="\
\r
959 "*/)/* || chw>=page->width*/)
\r
965 //load the letter 'A'
\r
980 MOV AL, c ; the letter
\r
983 ADD SI, AX ;the address of charcter
\r
1001 for(i=0; i<w; i++)
\r
1007 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1008 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1017 /* palette dump on display! */
\r
1018 void modexpdump(page_t *pee)
\r
1020 int mult=(QUADWH);
\r
1021 int palq=(mult)*TILEWH;
\r
1024 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1025 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1026 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1032 /////////////////////////////////////////////////////////////////////////////
\r
1034 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1035 // the Virtual screen. //
\r
1037 /////////////////////////////////////////////////////////////////////////////
\r
1038 void modexcls(page_t *page, byte color, byte *Where)
\r
1040 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1041 /* set map mask to all 4 planes */
\r
1042 outpw(SC_INDEX, 0xff02);
\r
1043 //_fmemset(VGA, color, 16000);
\r
1044 _fmemset(Where, color, page->stridew*page->height);
\r
1048 // pattern filler from joncampbell123's code
\r
1050 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1052 unsigned int i,j,o, d,h,s;
\r
1058 w=vga_state.vga_width;
\r
1060 s=vga_state.vga_stride;
\r
1064 h=vga_state.vga_height;
\r
1072 w=video->page[pn].width;
\r
1073 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1074 s=video->page[pn].stridew;
\r
1078 h=video->page[pn].height;
\r
1081 if(!pn) h=video->vh;
\r
1082 else h=video->page[pn].height;
\r
1088 /* fill screen/pattern with a distinctive pattern */
\r
1089 for (i=0;i < w;i++) {
\r
1091 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1092 for (j=0;j < h;j++,o += s)
\r
1093 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1098 modexWaitBorder() {
\r
1099 while(inp(INPUT_STATUS_1) & 8) {
\r
1103 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1109 modexWaitBorder_start()
\r
1111 while(inp(INPUT_STATUS_1) & 8) {
\r
1118 modexWaitBorder_end()
\r
1120 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1126 //===========================================================================
\r
1129 // printings of video memory information
\r
1131 void VL_PrintmodexmemInfo(video_t *v)
\r
1135 // printf("========================================\n");
\r
1136 printf("VL_PrintmodexmemInfo:\n");
\r
1137 // printf("========================================\n");
\r
1138 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
1139 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
1141 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1143 for(i=0; i<v->num_of_pages;i++)
\r
1145 printf(" [%u]=", i);
\r
1146 printf("(%Fp)", (v->page[i].data));
\r
1147 printf(" size=%u ", v->page[i].pagesize);
\r
1148 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1149 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1150 printf("pi=%u", v->page[i].pi);
\r