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
48 in.h.al = gv->video.old_mode;
\r
49 int86(0x10, &in, &out);
\r
51 default: // init the video
\r
52 // get old video mode
\r
54 //int86(0x10, &in, &out);
\r
55 gv->video.old_mode = vgaGetMode();//out.h.al;
\r
57 modexEnter(vq, cmem, gv);
\r
63 vgaSetMode(byte mode)
\r
67 regs.h.ah = SET_MODE;
\r
69 int86(VIDEO_INT, ®s, ®s);
\r
70 //int10_setmode(mode);
\r
73 //---------------------------------------------------
\r
75 // Use the bios to get the current video mode
\r
78 byte/*FIXME: why long? "long" is 32-bit datatype, VGA modes are 8-bit numbers. */
\r
81 return int10_getmode();
\r
84 /* -========================= Entry Points ==========================- */
\r
85 void modexEnter(sword vq, boolean cmem, global_game_variables_t *gv)
\r
88 struct vga_mode_params cm;
\r
91 vgaSetMode(VGA_256_COLOR_MODE);
\r
92 vga_enable_256color_modex();
\r
94 update_state_from_vga();
\r
95 vga_read_crtc_mode(&cm);
\r
97 /* reprogram the CRT controller */
\r
98 //outp(CRTC_INDEX, 0x11); /* VSync End reg contains register write prot */
\r
99 //outp(CRTC_DATA, 0x7f); /* get current write protect on varios regs */
\r
104 //CRTParmCount = sizeof(ModeX_320x240regs) / sizeof(ModeX_320x240regs[0]);
\r
105 /*for(i=0; i<CRTParmCount; i++) {
\r
106 outpw(CRTC_INDEX, ModeX_320x240regs[i]);
\r
108 /* width and height */
\r
109 gv->video.page[0].sw = vga_state.vga_width = 320; // VGA lib currently does not update this
\r
110 gv->video.page[0].sh = vga_state.vga_height = 240; // VGA lib currently does not update this
\r
111 /* virtual width and height. match screen, at first */
\r
112 gv->video.page[0].height = gv->video.page[0].sh;
\r
113 gv->video.page[0].width = gv->video.page[0].sw;
\r
115 // mode X BYTE mode
\r
118 // 320x240 mode 60Hz
\r
119 cm.horizontal_total=0x5f + 5; /* CRTC[0] -5 */
\r
120 cm.horizontal_display_end=0x4f + 1; /* CRTC[1] -1 */
\r
121 cm.horizontal_blank_start=0x50 + 1; /* CRTC[2] */
\r
122 // cm.horizontal_blank_end=0x82 + 1; /* CRTC[3] bit 0-4 & CRTC[5] bit 7 *///skewing ^^;
\r
123 cm.horizontal_start_retrace=0x54;/* CRTC[4] */
\r
124 cm.horizontal_end_retrace=0x80; /* CRTC[5] bit 0-4 */
\r
125 //cm.horizontal_start_delay_after_total=0x3e; /* CRTC[3] bit 5-6 */
\r
126 //cm.horizontal_start_delay_after_retrace=0x41; /* CRTC[5] bit 5-6 */
\r
127 cm.vertical_total = 0x20D + 2;
\r
128 cm.vertical_start_retrace = 0x1EA;
\r
129 cm.vertical_end_retrace = 0x1EC;
\r
130 cm.vertical_display_end = 480;
\r
131 cm.vertical_blank_start = 0x1E7 + 1;
\r
132 cm.vertical_blank_end = 0x206 + 1;
\r
133 cm.clock_select = 0; /* misc register = 0xE3 25MHz */
\r
136 cm.offset = (vga_state.vga_width / (4 * 2)); // 320 wide (40 x 4 pixel groups x 2)
\r
138 case 2: // TODO: 160x120 according to ModeX_160x120regs
\r
140 case 3: // TODO: 160x120 according to ModeX_320x200regs
\r
142 case 4: // TODO: 160x120 according to ModeX_192x144regs
\r
144 case 5: // TODO: 160x120 according to ModeX_256x192regs
\r
150 vga_state.vga_stride = cm.offset * 2;
\r
151 vga_write_crtc_mode(&cm,0);
\r
153 /* clear video memory */
\r
157 /* clear video memory */
\r
158 dword far*ptr=(dword far*)vga_state.vga_graphics_ram;//VGA; /* used for faster screen clearing */
\r
159 vga_write_sequencer(2/*map mask register*/,0xf/*all 4 planes*/);
\r
160 for(i = 0;i < 0x4000; i++) ptr[i] = 0x0000; // 0x4000 x dword = 64KB
\r
161 /* fix up the palette and everything */
\r
162 modexPalBlack(); //reset the palette~
\r
170 /* VGAmodeX restores original mode and palette */
\r
171 vgaSetMode(TEXT_MODE);
\r
175 modexDefaultPage(page_t *p)
\r
179 /* default page values */
\r
181 //page.data = (byte far *)(vga_state.vga_graphics_ram);
\r
182 page.data = (vga_state.vga_graphics_ram);
\r
187 page.width = p->sw+TILEWHD;
\r
188 page.height = p->sh+TILEWHD;
\r
189 page.ti.tw = page.sw/TILEWH;
\r
190 page.ti.th = page.sh/TILEWH;
\r
191 page.ti.tilesw=page.width/TILEWH;
\r
192 page.ti.tilesh=page.height/TILEWH;
\r
193 page.ti.tilemidposscreenx = page.ti.tw/2;
\r
194 page.ti.tilemidposscreeny = (page.ti.th/2)+1;
\r
195 page.stridew=page.width/4;
\r
196 page.pagesize = (word)(page.stridew)*page.height;
\r
197 page.pi=page.width*4;
\r
203 /* returns the next page in contiguous memory
\r
204 * the next page will be the same size as p, by default
\r
207 modexNextPage(page_t *p) {
\r
210 result.data = p->data + (p->pagesize);
\r
211 result.dx = p->dx; // not used anymore we use page[0].dx
\r
212 result.dy = p->dy; // not used anymore we use page[0].dy
\r
215 result.width = p->width;
\r
216 result.height = p->height;
\r
217 result.ti.tw = p->ti.tw;
\r
218 result.ti.th = p->ti.th;
\r
219 result.ti.tilesw = p->ti.tilesw;
\r
220 result.ti.tilesh = p->ti.tilesh;
\r
221 result.stridew=p->stridew;
\r
222 result.pagesize = p->pagesize;
\r
223 result.pi=result.width*4;
\r
224 result.id = p->id+1;
\r
229 //next page with defined dimentions~
\r
231 modexNextPageFlexibleSize(page_t *p, word x, word y)
\r
235 result.data = p->data + (p->pagesize); /* compute the offset */
\r
236 result.dx = 0; // not used anymore we use page[0].dx
\r
237 result.dy = 0; // not used anymore we use page[0].dy
\r
242 result.ti.tw = result.sw/TILEWH;
\r
243 result.ti.th = result.sh/TILEWH;
\r
244 result.ti.tilesw=result.width/TILEWH;
\r
245 result.ti.tilesh=result.height/TILEWH;
\r
246 result.id = p->id+1;
\r
247 result.stridew=result.width/4;//p->sw/4;
\r
248 result.pagesize = (word)(result.stridew)*result.height;
\r
249 /* switch(result.id)
\r
252 result.pi=p->width*4;
\r
258 result.pi=result.width*4;
\r
263 void modexCalcVmemRemain(video_t *video)
\r
266 //printf("\n\n 1st vmem_remain=%u\n", video->vmem_remain);
\r
267 for(i=0; i<video->num_of_pages; i++)
\r
269 video->vmem_remain-=video->page[i].pagesize;
\r
270 //printf(" [%u], video->page[%u].pagesize=%u\n", i, i, video->page[i].pagesize);
\r
271 //printf(" [%u], vmem_remain=%u\n", i, video->vmem_remain);
\r
275 void VL_Initofs(video_t *video)
\r
277 if(!video->vga_state.bgps)
\r
279 video->ofs.offscreen_ofs = video->page[0].pagesize+video->page[1].pagesize;//(vga_state.vga_stride * vga_state.vga_height);
\r
280 video->ofs.pattern_ofs = (uint16_t)video->page[2].data;
\r
282 video->ofs.offscreen_ofs = 0;
\r
283 video->ofs.pattern_ofs = 0;//(uint16_t)video->page[0].data;
\r
287 void modexHiganbanaPageSetup(video_t *video)
\r
289 video->vmem_remain=65535U;
\r
290 video->num_of_pages=0;
\r
291 (video->page[0]) = modexDefaultPage(&(video->page[0])); video->num_of_pages++; //video->page[0].width += (TILEWHD); video->page[0].height += (TILEWHD);
\r
292 (video->page[1]) = modexNextPage(&(video->page[0])); video->num_of_pages++;
\r
293 //0000 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), (video->page[0]).width, TILEWH*4); video->num_of_pages++;
\r
294 //0000 (video->page[3]) = (video->page[2]); video->num_of_pages++;
\r
295 //// (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), TILEWH*4, TILEWH*4); video->num_of_pages++;
\r
296 //// (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].sw, 208); video->num_of_pages++;
\r
297 (video->page[2]) = modexNextPageFlexibleSize(&(video->page[1]), video->page[0].width, 96); video->num_of_pages++;
\r
298 (video->page[3]) = modexNextPageFlexibleSize(&(video->page[2]), video->page[0].width, 96); video->num_of_pages++;
\r
299 modexCalcVmemRemain(video);
\r
301 video->sp=video->p = 0; //showpage
\r
302 video->dorender = 1; //render
\r
303 video->vh=video->page[0].height+video->page[1].height+video->page[2].height+video->page[3].height;
\r
307 video->vga_state.omemptr= vga_state.vga_graphics_ram;
\r
308 video->vga_state.vga_draw_stride= vga_state.vga_draw_stride;
\r
309 video->vga_state.vga_draw_stride_limit= vga_state.vga_draw_stride_limit;
\r
310 //sprite render switch and bgpreservation switch
\r
311 video->vga_state.rss= 1;
\r
312 video->vga_state.bgps= 1;
\r
314 //setup the buffersize
\r
315 video->page[0].dx=video->page[0].dy=
\r
316 video->page[1].dx=video->page[1].dy=TILEWH; // 1 tile size buffer
\r
317 video->page[2].dx=video->page[2].dy=
\r
318 video->page[3].dx=video->page[3].dy=0; // cache pages are buffer wwww
\r
322 // move page to appropriate part and show it
\r
325 modexShowPage(page_t *page) {
\r
326 word high_address, low_address, offset;
\r
329 /* calculate offset */
\r
330 offset = (word) page->data;
\r
331 offset += page[0].dy * (page->width >> 2 );
\r
332 offset += page[0].dx >> 2;
\r
334 /* calculate crtcOffset according to virtual width */
\r
335 crtcOffset = page->width >> 3;
\r
337 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
338 low_address = LOW_ADDRESS | (offset << 8);
\r
340 /* wait for appropriate timing and then program CRTC */
\r
341 //+=+= while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
342 outpw(CRTC_INDEX, high_address);
\r
343 outpw(CRTC_INDEX, low_address);
\r
344 outp(CRTC_INDEX, 0x13);
\r
345 outp(CRTC_DATA, crtcOffset);
\r
347 /* wait for one retrace */
\r
348 //+=+= while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
350 /* do PEL panning here */
\r
351 outp(AC_INDEX, 0x33);
\r
352 outp(AC_INDEX, (page[0].dx & 0x03) << 1);
\r
355 //args: page, vertical sync switch, screen resolution switch, page0 switch
\r
357 VL_ShowPage(page_t *page, boolean vsync, boolean sr) {
\r
358 word high_address, low_address, offset;
\r
361 // calculate offset
\r
362 offset = (word) page->data;
\r
363 offset += page->dy * (page->width >> 2 );
\r
364 offset += page->dx >> 2;
\r
366 // calculate crtcOffset according to virtual width
\r
370 crtcOffset = page->sw >> 3;
\r
374 crtcOffset = page->width >> 3;
\r
378 high_address = HIGH_ADDRESS | (offset & 0xff00);
\r
379 low_address = LOW_ADDRESS | (offset << 8);
\r
381 // wait for appropriate timing and then program CRTC
\r
382 if(vsync) while ((inp(INPUT_STATUS_1) & DISPLAY_ENABLE));
\r
383 outpw(CRTC_INDEX, high_address);
\r
384 outpw(CRTC_INDEX, low_address);
\r
385 outp(CRTC_INDEX, 0x13);
\r
386 outp(CRTC_DATA, crtcOffset);
\r
388 // wait for one retrace
\r
389 if(vsync) while (!(inp(INPUT_STATUS_1) & VRETRACE));
\r
391 // do PEL panning here
\r
392 outp(AC_INDEX, 0x33);
\r
393 outp(AC_INDEX, (page->dx & 0x03) << 1);
\r
394 vga_state.vga_graphics_ram = (VGA_RAM_PTR)page->data;
\r
397 //=============================================================================
\r
400 modexPanPage(page_t *page, int dx, int dy) {
\r
406 modexSelectPlane(byte plane) {
\r
407 outp(SC_INDEX, MAP_MASK); /* select plane */
\r
408 outp(SC_DATA, plane);
\r
412 modexClearRegion(page_t *page, int x, int y, int w, int h, byte color)
\r
414 word pageOff = (word) page->data;
\r
415 word xoff=(x>>2); // xoffset that begins each row
\r
416 word poffset = pageOff + y*(page->stridew) + xoff; // starting offset
\r
417 word scanCount=w>>2; // number of iterations per row (excluding right clip)
\r
418 word nextRow = page->stridew-scanCount-1; // loc of next row
\r
419 byte lclip[] = {0x0f, 0x0e, 0x0c, 0x08}; // clips for rectangles not on 4s
\r
420 byte rclip[] = {0x00, 0x01, 0x03, 0x07};
\r
421 byte left = lclip[x&0x03];
\r
422 byte right = rclip[(x+w)&0x03];
\r
424 // handle the case which requires an extra group
\r
425 if((x & 0x03) && !((x+w) & 0x03)) {
\r
429 //printf("modexClearRegion(x=%u, y=%u, w=%u, h=%u, left=%u, right=%u)\n", x, y, w, h, left, right);
\r
440 MOV AX, SCREEN_SEG ; go to the VGA memory
\r
442 MOV DI, poffset ; go to the first pixel
\r
443 MOV DX, SC_INDEX ; point to the map mask
\r
447 MOV AL, color ; get ready to write colors
\r
449 MOV CX, scanCount ; count the line
\r
450 MOV BL, AL ; remember color
\r
451 MOV AL, left ; do the left clip
\r
452 OUT DX, AL ; set the left clip
\r
453 MOV AL, BL ; restore color
\r
454 STOSB ; write the color
\r
456 JZ SCAN_DONE ; handle 1 group stuff
\r
458 ;-- write the main body of the scanline
\r
459 MOV BL, AL ; remember color
\r
460 MOV AL, 0x0f ; write to all pixels
\r
462 MOV AL, BL ; restore color
\r
463 REP STOSB ; write the color
\r
465 MOV BL, AL ; remeber color
\r
467 OUT DX, AL ; do the right clip
\r
468 MOV AL, BL ; restore color
\r
469 STOSB ; write pixel
\r
470 ADD DI, nextRow ; go to the next row
\r
484 /* moved to src/lib/modex16/16render.c */
\r
486 /* copy a region of video memory from one page to another.
\r
487 * It assumes that the left edge of the tile is the same on both
\r
488 * regions and the memory areas do not overlap.
\r
491 modexCopyPageRegion(page_t *dest, page_t *src,
\r
494 word width, word height)
\r
496 word doffset = (word)dest->data + dy*(dest->stridew) + (dx>>2);
\r
497 word soffset = (word)src->data + sy*(src->stridew) + (sx>>2);
\r
498 word scans = vga_state.vga_stride+8; //++++0000 the quick and dirty fix of the major issue with p16 video display wwww
\r
499 word nextSrcRow = src->stridew - scans - 1;
\r
500 word nextDestRow = dest->stridew - scans - 1;
\r
501 byte lclip[] = {0x0f, 0x0e, 0x0c, 0x08}; // clips for rectangles not on 4s
\r
502 byte rclip[] = {0x00, 0x01, 0x03, 0x07};
\r
503 byte left = lclip[sx&0x03];
\r
504 byte right = rclip[(sx+width)&0x03];
\r
506 // handle the case which requires an extra group
\r
507 if((sx & 0x03) && !((sx+width) & 0x03)) {
\r
511 // 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
523 MOV AX, SCREEN_SEG ; work in the vga space
\r
528 MOV DX, GC_INDEX ; turn off cpu bits
\r
532 MOV AX, SC_INDEX ; point to the mask register
\r
542 MOV CX, scans ; the number of latches
\r
544 MOV AL, left ; do the left column
\r
549 MOV AL, 0fh ; do the inner columns
\r
551 REP MOVSB ; copy the pixels
\r
553 MOV AL, right ; do the right column
\r
558 MOV AX, SI ; go the start of the next row
\r
559 ADD AX, nextSrcRow ;
\r
562 ADD AX, nextDestRow ;
\r
565 DEC height ; do the rest of the actions
\r
568 MOV DX, GC_INDEX+1 ; go back to CPU data
\r
569 MOV AL, 0ffh ; none from latches
\r
584 /* fade and flash */
\r
586 modexFadeOn(word fade, byte *palette) {
\r
587 fadePalette(-fade, 64, 64/fade+1, palette);
\r
592 modexFadeOff(word fade, byte *palette) {
\r
593 fadePalette(fade, 0, 64/fade+1, palette);
\r
598 modexFlashOn(word fade, byte *palette) {
\r
599 fadePalette(fade, -64, 64/fade+1, palette);
\r
604 modexFlashOff(word fade, byte *palette) {
\r
605 fadePalette(-fade, 0, 64/fade+1, palette);
\r
610 fadePalette(sbyte fade, sbyte start, word iter, byte *palette) {
\r
614 /* handle the case where we just update */
\r
616 modexPalUpdate(palette);
\r
620 while(iter > 0) { /* FadeLoop */
\r
621 for(i=0; i<PAL_SIZE; i++) { /* loadpal_loop */
\r
622 tmppal[i] = palette[i] - dim;
\r
623 if(tmppal[i] > 127) {
\r
625 } else if(tmppal[i] > 63) {
\r
629 modexPalUpdate(tmppal);
\r
636 /* save and load */
\r
638 modexPalSave(byte *palette) {
\r
641 outp(PAL_READ_REG, 0); /* start at palette entry 0 */
\r
642 for(i=0; i<PAL_SIZE; i++) {
\r
643 palette[i] = inp(PAL_DATA_REG); /* read the palette data */
\r
651 ptr = m a l l o c(PAL_SIZE);
\r
655 printf("Could not allocate palette.\n");
\r
663 modexLoadPalFile(byte *filename, byte *palette) {
\r
667 // free the palette if it exists
\r
668 //if(*palette) { free(*palette); }
\r
670 // allocate the new palette
\r
671 //*palette = modexNewPal();
\r
674 file = fopen(filename, "rb");
\r
676 printf("Could not open palette file: %s\n", filename);
\r
679 /* read the file */
\r
681 while(!feof(file)) {
\r
682 *ptr++ = fgetc(file);
\r
689 void VL_LoadPalFile(const char *filename, byte *palette)
\r
691 VL_LoadPalFilewithoffset(filename, palette, 0);
\r
694 void VL_LoadPalFilewithoffset(const char *filename, byte *palette, word o)
\r
698 fd = open(filename,O_RDONLY|O_BINARY);
\r
700 read(fd,palette, PAL_SIZE);
\r
703 VL_UpdatePaletteWrite(palette, o);
\r
707 void VL_UpdatePaletteWrite(byte *palette, word o)
\r
710 vga_palette_lseek(/*1+*/o);
\r
711 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
715 modexSavePalFile(char *filename, byte *pal) {
\r
719 /* open the file for writing */
\r
720 file = fopen(filename, "wb");
\r
722 printf("Could not open %s for writing\n", filename);
\r
725 /* write the data to the file */
\r
726 fwrite(pal, 1, PAL_SIZE, file);
\r
734 fadePalette(-1, 64, 1, tmppal);
\r
740 fadePalette(-1, -64, 1, tmppal);
\r
745 //moved to 16_vlpal.c
\r
748 modexPalUpdate(byte *p)
\r
751 //modexWaitBorder();
\r
752 vga_wait_for_vsync();
\r
753 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
754 for(i=0; i<PAL_SIZE/2; i++)
\r
756 outp(PAL_DATA_REG, p[i]);
\r
758 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
759 vga_wait_for_vsync();
\r
760 for(; i<PAL_SIZE; i++)
\r
762 outp(PAL_DATA_REG, p[(i)]);
\r
767 modexPalUpdate0(byte *p)
\r
770 //modexWaitBorder();
\r
771 vga_wait_for_vsync();
\r
772 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
773 for(i=0; i<PAL_SIZE/2; i++)
\r
775 outp(PAL_DATA_REG, rand());
\r
777 //modexWaitBorder(); /* waits one retrace -- less flicker */
\r
778 vga_wait_for_vsync();
\r
779 for(; i<PAL_SIZE; i++)
\r
781 outp(PAL_DATA_REG, rand());
\r
786 modexPalOverscan(word col)
\r
788 //modexWaitBorder();
\r
789 vga_wait_for_vsync();
\r
790 outp(PAL_WRITE_REG, 0); /* start at the beginning of palette */
\r
791 outp(PAL_DATA_REG, col);
\r
794 void modexputPixel(page_t *page, int x, int y, byte color)
\r
796 word pageOff = (word) page->data;
\r
797 /* Each address accesses four neighboring pixels, so set
\r
798 Write Plane Enable according to which pixel we want
\r
799 to modify. The plane is determined by the two least
\r
800 significant bits of the x-coordinate: */
\r
801 modexSelectPlane(PLANE(x));
\r
802 //outp(SC_INDEX, 0x02);
\r
803 //outp(SC_DATA, 0x01 << (x & 3));
\r
805 /* The offset of the pixel into the video segment is
\r
806 offset = (width * y + x) / 4, and write the given
\r
807 color to the plane we selected above. Heed the active
\r
808 page start selection. */
\r
809 VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff] = color;
\r
813 byte modexgetPixel(page_t *page, int x, int y)
\r
815 word pageOff = (word) page->data;
\r
816 /* Select the plane from which we must read the pixel color: */
\r
817 outpw(GC_INDEX, 0x04);
\r
818 outpw(GC_INDEX+1, x & 3);
\r
820 return VGA[(unsigned)((page->width/4) * y) + (x / 4) + pageOff];
\r
824 void modexDrawChar(page_t *page, int x/*for planar selection only*/, word t, word col, word bgcol, word addr)
\r
826 /* vertical drawing routine by joncampbell123.
\r
828 * optimize for VGA mode X planar memory to minimize the number of times we do I/O write to map mask register.
\r
829 * so, we enumerate over columns (not rows!) to draw every 4th pixel. bit masks are used because of the font bitmap.
\r
831 * 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
832 word rows = romFonts[t].charSize;
\r
840 m1 = 0x80; // left half
\r
841 m2 = 0x08; // right half
\r
842 for (colm=0;colm < 4;colm++) {
\r
844 modexSelectPlane(PLANE(plane));
\r
845 for (row=0;row < rows;row++) {
\r
846 fontbyte = romFontsData.l[row];
\r
847 vga_state.vga_graphics_ram[drawaddr ] = (fontbyte & m1) ? col : bgcol;
\r
848 vga_state.vga_graphics_ram[drawaddr+1] = (fontbyte & m2) ? col : bgcol;
\r
849 drawaddr += page->width >> 2;
\r
854 if ((++plane) == 4) {
\r
861 void modexprint(page_t *page, sword x, sword y, word t, boolean tlsw, word col, word bgcol, const byte *str)
\r
865 //word addr = (word) romFontsData.l;
\r
870 if(tlsw){ x-=page->tlx; y-=page->tly; }
\r
872 addrq = (page->stridew) * y + (word)(x_draw) +
\r
873 ((word)page->data);
\r
877 w=romFonts[t].charSize;
\r
878 romFontsData.chw=0;
\r
880 for(; *str != '\0'; str++)
\r
886 romFontsData.chw = 0;
\r
887 addrq += (page->stridew) * 8;
\r
893 // load the character into romFontsData.l
\r
894 // no need for inline assembly!
\r
895 // NTS: It might even be faster to just let the modexDrawChar point directly at ROM font than to copy per char! --J.C.
\r
896 _fmemcpy(romFontsData.l,MK_FP(s,o+(w*c))/*ROM font location*/,w/*char size*/);
\r
897 modexDrawChar(page, x_draw/*for mode X planar use*/, t, col, bgcol, addrr);
\r
898 x_draw += 8; /* track X for edge of screen */
\r
899 addrr += 2; /* move 8 pixels over (2 x 4 planar pixels per byte) */
\r
901 //printf("print xy:%dx%d tlxy:%dx%d\n", x, y, page->tlx, page->tly);
\r
904 void modexprintbig(page_t *page, word x, word y, word t, word col, word bgcol, const byte *str)
\r
906 word i, s, o, w, j, xp;
\r
908 word addr = (word) l;
\r
935 for(; *str != '\0'; str++)
\r
938 if((c=='\n'/* || c=="\
\r
939 "*/)/* || chw>=page->width*/)
\r
945 //load the letter 'A'
\r
960 MOV AL, c ; the letter
\r
963 ADD SI, AX ;the address of charcter
\r
987 //modexputPixel(page, x+xp+chw, y+i, l[i] & j ? col:bgcol);
\r
988 modexClearRegion(page, (x+xp+chw)*8, (y+i)*8, 8, 8, l[i] & j ? col:bgcol);
\r
997 /* palette dump on display! */
\r
998 void modexpdump(page_t *pee)
\r
1000 int mult=(QUADWH);
\r
1001 int palq=(mult)*TILEWH;
\r
1004 for(paly=TILEWH*8; paly<palq+TILEWH*8; paly+=mult){
\r
1005 for(palx=TILEWH*12; palx<palq+TILEWH*12; palx+=mult){
\r
1006 modexClearRegion(pee, palx+TILEWH, paly+TILEWH, mult, mult, palcol);
\r
1012 /////////////////////////////////////////////////////////////////////////////
\r
1014 // cls() - This clears the screen to the specified color, on the VGA or on //
\r
1015 // the Virtual screen. //
\r
1017 /////////////////////////////////////////////////////////////////////////////
\r
1018 void modexcls(page_t *page, byte color, byte *Where)
\r
1020 //modexClearRegion(page, 0, 0, page->width, page->height, color);
\r
1021 /* set map mask to all 4 planes */
\r
1022 outpw(SC_INDEX, 0xff02);
\r
1023 //_fmemset(VGA, color, 16000);
\r
1024 _fmemset(Where, color, page->stridew*page->height);
\r
1028 // pattern filler from joncampbell123's code
\r
1030 void VL_PatternDraw(video_t *video, word pn, boolean sw, boolean allsw)
\r
1032 unsigned int i,j,o, d,h,s;
\r
1038 w=vga_state.vga_width;
\r
1040 s=vga_state.vga_stride;
\r
1044 h=vga_state.vga_height;
\r
1052 w=video->page[pn].width;
\r
1053 d=(0x10000UL - (uint16_t)video->page[pn].data);
\r
1054 s=video->page[pn].stridew;
\r
1058 h=video->page[pn].height;
\r
1061 if(!pn) h=video->vh;
\r
1062 else h=video->page[pn].height;
\r
1068 /* fill screen/pattern with a distinctive pattern */
\r
1069 for (i=0;i < w;i++) {
\r
1071 vga_write_sequencer(0x02/*map mask*/,1 << (i&3));
\r
1072 for (j=0;j < h;j++,o += s)
\r
1073 vga_state.vga_graphics_ram[o] = (i^j)&15; // VRL samples put all colors in first 15!
\r
1078 modexWaitBorder() {
\r
1079 while(inp(INPUT_STATUS_1) & 8) {
\r
1083 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1089 modexWaitBorder_start()
\r
1091 while(inp(INPUT_STATUS_1) & 8) {
\r
1098 modexWaitBorder_end()
\r
1100 while(!(inp(INPUT_STATUS_1) & 8)) {
\r
1107 // printings of video memory information
\r
1109 void VL_PrintmodexmemInfo(video_t *v)
\r
1113 // printf("========================================\n");
\r
1114 printf("VL_PrintmodexmemInfo:\n");
\r
1115 // printf("========================================\n");
\r
1116 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
1117 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
1119 printf(" Free Video Memory: %u\n", v->vmem_remain);
\r
1121 for(i=0; i<v->num_of_pages;i++)
\r
1123 printf(" [%u]=", i);
\r
1124 printf("(%Fp)", (v->page[i].data));
\r
1125 printf(" size=%u ", v->page[i].pagesize);
\r
1126 printf("w=%-3lu h=%-3lu ", (unsigned long)v->page[i].width, (unsigned long)v->page[i].height);
\r
1127 printf("sw=%-3lu sh=%-3lu ", (unsigned long)v->page[i].sw, (unsigned long)v->page[i].sh);
\r
1128 printf("pi=%u", v->page[i].pi);
\r