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
369 word high_address, low_address, offset;
\r
372 // calculate offset
\r
373 offset = (word) page->data;
\r
374 offset += page->dy * (page->width >> 2 );
\r
375 offset += page->dx >> 2;
\r
377 // calculate crtcOffset according to virtual width
\r
381 crtcOffset = page->sw >> 3;
\r
385 crtcOffset = page->width >> 3;
\r
389 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
390 low_address = LOW_ADDRESS | (offset << 8);
\r
392 // wait for appropriate timing and then program CRTC
\r
393 if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
394 outpw(CRTC_INDEX, high_address);
\r
395 outpw(CRTC_INDEX, low_address);
\r
396 outp(CRTC_INDEX, 0x13);
\r
397 outp(CRTC_DATA, crtcOffset);
\r
399 // wait for one retrace
\r
400 if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
402 // do PEL panning here
\r
403 outp(AC_INDEX, 0x33);
\r
404 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
405 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
406 vga_state.vga_draw_stride_limit = vga_state.vga_draw_stride = page->stridew;
\r
409 //=============================================================================
\r
412 modexPanPage(page_t *page, int dx, int dy) {
\r
418 modexSelectPlane(byte plane) {
\r
419 outp(SC_INDEX, SC_MAPMASK); /* select plane */
\r
420 outp(SC_DATA, plane);
\r
424 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
426 word pageOff = (word) page->data;
\r
427 word xoff=(x>>2); // xoffset that begins each row
\r
428 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
429 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
430 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
432 byte left = lclip[x&0x03];
\r
433 byte right = rclip[(x+w)&0x03];
\r
435 // handle the case which requires an extra group
\r
436 if((x & 0x03) && !((x+w) & 0x03)) {
\r
440 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
451 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
453 MOV DI, poffset ; go to the first pixel
\r
454 MOV DX, SC_INDEX ; point to the map mask
\r
458 MOV AL, color ; get ready to write colors
\r
460 MOV CX, scanCount ; count the line
\r
461 MOV BL, AL ; remember color
\r
462 MOV AL, left ; do the left clip
\r
463 OUT DX, AL ; set the left clip
\r
464 MOV AL, BL ; restore color
\r
465 STOSB ; write the color
\r
467 JZ SCAN_DONE ; handle 1 group stuff
\r
469 ;-- write the main body of the scanline
\r
470 MOV BL, AL ; remember color
\r
471 MOV AL, 0x0f ; write to all pixels
\r
473 MOV AL, BL ; restore color
\r
474 REP STOSB ; write the color
\r
476 MOV BL, AL ; remeber color
\r
478 OUT DX, AL ; do the right clip
\r
479 MOV AL, BL ; restore color
\r
480 STOSB ; write pixel
\r
481 ADD DI, nextRow ; go to the next row
\r
495 /* moved to src/lib/modex16/16render.c */
\r
497 /* copy a region of video memory from one page to another.
\r
498 * It assumes that the left edge of the tile is the same on both
\r
499 * regions and the memory areas do not overlap.
\r
502 modexCopyPageRegion(page_t *dest, page_t *src,
\r
505 word width, word height)
\r
507 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
508 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
509 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
510 word nextSrcRow = src->stridew - scans - 1;
\r
511 word nextDestRow = dest->stridew - scans - 1;
\r
513 byte left = lclip[sx&0x03];
\r
514 byte right = rclip[(sx+width)&0x03];
\r
516 // handle the case which requires an extra group
\r
517 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
521 // 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
533 MOV AX, SCREEN_SEG ; work in the vga space
\r
538 MOV DX, GC_INDEX ; turn off cpu bits
\r
542 MOV AX, SC_INDEX ; point to the mask register
\r
544 MOV AL, SC_MAPMASK ;
\r
552 MOV CX, scans ; the number of latches
\r
554 MOV AL, left ; do the left column
\r
559 MOV AL, 0fh ; do the inner columns
\r
561 REP MOVSB ; copy the pixels
\r
563 MOV AL, right ; do the right column
\r
568 MOV AX, SI ; go the start of the next row
\r
569 ADD AX, nextSrcRow ;
\r
572 ADD AX, nextDestRow ;
\r
575 DEC height ; do the rest of the actions
\r
578 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
579 MOV AL, 0ffh ; none from latches
\r
595 /* fade and flash */
\r
597 modexFadeOn(word fade, byte *palette) {
\r
598 fadePalette(-fade, 64, 64/fade+1, palette);
\r
603 modexFadeOff(word fade, byte *palette) {
\r
604 fadePalette(fade, 0, 64/fade+1, palette);
\r
609 modexFlashOn(word fade, byte *palette) {
\r
610 fadePalette(fade, -64, 64/fade+1, palette);
\r
615 modexFlashOff(word fade, byte *palette) {
\r
616 fadePalette(-fade, 0, 64/fade+1, palette);
\r
621 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
625 /* handle the case where we just update */
\r
627 modexPalUpdate(palette);
\r
631 while(iter > 0) { /* FadeLoop */
\r
632 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
633 tmppal[i] = palette[i] - dim;
\r
634 if(tmppal[i] > 127) {
\r
636 } else if(tmppal[i] > 63) {
\r
640 modexPalUpdate(tmppal);
\r
647 /* save and load */
\r
649 modexPalSave(byte *palette) {
\r
652 outp(PAL_READ_REG, 0); /* start at palette entry 0 */
\r
653 for(i=0; i<PAL_SIZE; i++) {
\r
654 palette[i] = inp(PAL_DATA_REG); /* read the palette data */
\r
662 ptr = m a l l o c(PAL_SIZE);
\r
666 printf("Could not allocate palette.\n");
\r
674 modexLoadPalFile(byte *filename, byte *palette) {
\r
678 // free the palette if it exists
\r
679 //if(*palette) { free(*palette); }
\r
681 // allocate the new palette
\r
682 //*palette = modexNewPal();
\r
685 file = fopen(filename, "rb");
\r
687 printf("Could not open palette file: %s\n", filename);
\r
690 /* read the file */
\r
692 while(!feof(file)) {
\r
693 *ptr++ = fgetc(file);
\r
699 void VL_LoadPalFile(const char *filename, byte *palette)
\r
701 VL_LoadPalFilewithoffset(filename, palette, 8);
\r
702 VL_LoadPalFileCore(palette);
\r
705 void VL_LoadPalFileCore(byte *palette)
\r
707 VL_LoadPalFilewithoffset("data/16.pal", palette, 0);
\r
710 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o)
\r
714 fd = open(filename,O_RDONLY|O_BINARY);
\r
716 read(fd,palette, PAL_SIZE);
\r
719 VL_UpdatePaletteWrite(palette, o);
\r
723 void VL_UpdatePaletteWrite(byte *palette, word o)
\r
726 vga_palette_lseek(/*1+*/o);
\r
727 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
731 modexSavePalFile(char *filename, byte *pal) {
\r
735 /* open the file for writing */
\r
736 file = fopen(filename, "wb");
\r
738 printf("Could not open %s for writing\n", filename);
\r
741 /* write the data to the file */
\r
742 fwrite(pal, 1, PAL_SIZE, file);
\r
750 fadePalette(-1, 64, 1, tmppal);
\r
756 fadePalette(-1, -64, 1, tmppal);
\r
761 //moved to 16_vlpal.c
\r
764 modexPalUpdate(byte *p)
\r
767 //modexWaitBorder();
\r
768 vga_wait_for_vsync();
\r
769 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
770 for(i=0; i<PAL_SIZE/2; i++)
\r
772 outp(PAL_DATA_REG, p[i]);
\r
774 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
775 vga_wait_for_vsync();
\r
776 for(; i<PAL_SIZE; i++)
\r
778 outp(PAL_DATA_REG, p[(i)]);
\r
783 //modexPalUpdate0(byte *p)
\r
784 VL_modexPalScramble(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, rand());
\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, rand());
\r
803 modexPalOverscan(word col)
\r
805 //modexWaitBorder();
\r
806 vga_wait_for_vsync();
\r
807 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
808 outp(PAL_DATA_REG, col);
\r
813 void modexputPixel(page_t *page, int x, int y, byte color)
\r
815 word pageOff = (word) page->data;
\r
816 /* Each address accesses four neighboring pixels, so set
\r
817 Write Plane Enable according to which pixel we want
\r
818 to modify. The plane is determined by the two least
\r
819 significant bits of the x-coordinate: */
\r
820 modexSelectPlane(PLANE(x));
\r
821 //outp(SC_INDEX, 0x02);
\r
822 //outp(SC_DATA, 0x01 << (x & 3));
\r
824 /* The offset of the pixel into the video segment is
\r
825 offset = (width * y + x) / 4, and write the given
\r
826 color to the plane we selected above. Heed the active
\r
827 page start selection. */
\r
828 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
832 byte modexgetPixel(page_t *page, int x, int y)
\r
834 word pageOff = (word) page->data;
\r
835 /* Select the plane from which we must read the pixel color: */
\r
836 outpw(GC_INDEX, 0x04);
\r
837 outpw(GC_INDEX+1, x & 3);
\r
839 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
843 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
845 /* vertical drawing routine by joncampbell123.
\r
847 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
848 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
850 * 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
851 word rows = romFonts[t].charSize;
\r
859 m1 = 0x80; // left half
\r
860 m2 = 0x08; // right half
\r
861 for (colm=0;colm < 4;colm++) {
\r
863 modexSelectPlane(PLANE(plane));
\r
864 for (row=0;row < rows;row++) {
\r
865 fontbyte = romFontsData.l[row];
\r
866 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
867 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
868 drawaddr += page->width >> 2;
\r
873 if ((++plane) == 4) {
\r
880 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, boolean sw, const byte *str)
\r
884 //word addr = (word) romFontsData.l;
\r
892 printf("%s\n", str);
\r
895 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
897 addrq = (page->stridew) * y + (word)(x_draw) +
\r
898 ((word)page->data);
\r
902 w=romFonts[t].charSize;
\r
903 romFontsData.chw=0;
\r
905 for(; *str != '\0'; str++)
\r
911 romFontsData.chw = 0;
\r
912 addrq += (page->stridew) * 8;
\r
918 // load the character into romFontsData.l
\r
919 // no need for inline assembly!
\r
920 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
921 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
922 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
923 x_draw += 8; /* track X for edge of screen */
\r
924 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
926 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
931 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
933 word i, s, o, w, j, xp;
\r
935 word addr = (word) l;
\r
962 for(; *str != '\0'; str++)
\r
965 if((c=='\n'/* || c=="\
\r
966 "*/)/* || chw>=page->width*/)
\r
972 //load the letter 'A'
\r
987 MOV AL, c ; the letter
\r
990 ADD SI, AX ;the address of charcter
\r
1008 for(i=0; i<w; i++)
\r
1014 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
1015 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
1024 /* palette dump on display! */
\r
1025 void modexpdump(page_t *pee)
\r
1027 int mult=(QUADWH);
\r
1028 int palq=(mult)*TILEWH;
\r
1031 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1032 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1033 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1039 /////////////////////////////////////////////////////////////////////////////
\r
1041 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1042 // the Virtual screen. //
\r
1044 /////////////////////////////////////////////////////////////////////////////
\r
1045 void modexcls(page_t *page, byte color, byte *Where)
\r
1047 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1048 /* set map mask to all 4 planes */
\r
1049 outpw(SC_INDEX, 0xff02);
\r
1050 //_fmemset(VGA, color, 16000);
\r
1051 _fmemset(Where, color, page->stridew*page->height);
\r
1055 // pattern filler from joncampbell123's code
\r
1057 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1059 unsigned int i,j,o, d,h,s;
\r
1065 w=vga_state.vga_width;
\r
1067 s=vga_state.vga_stride;
\r
1071 h=vga_state.vga_height;
\r
1079 w=video->page[pn].width;
\r
1080 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1081 s=video->page[pn].stridew;
\r
1085 h=video->page[pn].height;
\r
1088 if(!pn) h=video->vh;
\r
1089 else h=video->page[pn].height;
\r
1095 /* fill screen/pattern with a distinctive pattern */
\r
1096 for (i=0;i < w;i++) {
\r
1098 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1099 for (j=0;j < h;j++,o += s)
\r
1100 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1105 modexWaitBorder() {
\r
1106 while(inp(INPUT_STATUS_1) & 8) {
\r
1110 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1116 modexWaitBorder_start()
\r
1118 while(inp(INPUT_STATUS_1) & 8) {
\r
1125 modexWaitBorder_end()
\r
1127 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1133 //===========================================================================
\r
1136 // printings of video memory information
\r
1138 void VL_PrintmodexmemInfo(video_t *v)
\r
1142 // printf("========================================\n");
\r
1143 printf("VL_PrintmodexmemInfo:\n");
\r
1144 // printf("========================================\n");
\r
1145 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
1146 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
1148 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1150 for(i=0; i<v->num_of_pages;i++)
\r
1152 printf(" [%u]=", i);
\r
1153 printf("(%Fp)", (v->page[i].data));
\r
1154 printf(" size=%u ", v->page[i].pagesize);
\r
1155 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1156 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1157 printf("pi=%u", v->page[i].pi);
\r