?? tl_vga.c
字號:
/*** thinlib (c) 2000 Matthew Conte (matt@conte.com)****** This program is free software; you can redistribute it and/or** modify it under the terms of version 2 of the GNU Library General ** Public License as published by the Free Software Foundation.**** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Library General Public License for more details. To obtain a ** copy of the GNU Library General Public License, write to the Free ** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.**** Any permitted reproduction of these routines, in whole or in part,** must bear this legend.****** tl_vga.c**** VGA-related thinlib functions** $Id: tl_vga.c,v 1.9 2001/03/12 06:06:55 matt Exp $*/#include <stdio.h>#include <string.h>#include <dpmi.h>#include <dos.h>#include "tl_types.h"#include "tl_bmp.h"#include "tl_vga.h"#include "tl_djgpp.h"#define DEFAULT_OVERSCAN 0#define MODE_TEXT 0x03#define MODE_13H 0x13/* VGA card register addresses */#define VGA_ATTR 0x3C0 /* Attribute reg */#define VGA_MISC 0x3C2 /* Misc. output register */#define VGA_SEQ_ADDR 0x3C4 /* Base port of sequencer */#define VGA_SEQ_DATA 0x3C5 /* Data port of sequencer */#define VGA_CRTC_ADDR 0x3D4 /* Base port of CRT controller */#define VGA_CRTC_DATA 0x3D5 /* Data port of CRT controller */#define VGA_STATUS 0x3DA /* Input status #1 register */#define VGA_PAL_READ 0x3C7 /* Palette read address */#define VGA_PAL_WRITE 0x3C8 /* Palette write address */#define VGA_PAL_DATA 0x3C9 /* Palette data register *//* generic VGA CRTC register indexes */#define HZ_DISPLAY_TOTAL 0x00#define HZ_DISPLAY_END 0x01#define CRTC_OVERFLOW 0x07#define VT_DISPLAY_END 0x12#define MEM_OFFSET 0x13/* indices into our register array */#define CLOCK_INDEX 0#define H_TOTAL_INDEX 1#define H_DISPLAY_INDEX 2#define H_BLANKING_START_INDEX 3#define H_BLANKING_END_INDEX 4#define H_RETRACE_START_INDEX 5#define H_RETRACE_END_INDEX 6#define V_TOTAL_INDEX 7#define OVERFLOW_INDEX 8#define MAXIMUM_SCANLINE_INDEX 10#define V_RETRACE_START_INDEX 11#define V_RETRACE_END_INDEX 12#define V_END_INDEX 13#define MEM_OFFSET_INDEX 14#define UNDERLINE_LOC_INDEX 15#define V_BLANKING_START_INDEX 16#define V_BLANKING_END_INDEX 17#define MODE_CONTROL_INDEX 18#define MEMORY_MODE_INDEX 20typedef struct vgareg_s{ int port; int index; uint8 value;} vgareg_t;typedef struct vgamode_s{ int width; int height; char *name; vgareg_t *regs;} vgamode_t;/* 60 Hz */static vgareg_t mode_256x224[] ={ { 0x3C2, 0x00, 0xE3 }, { 0x3D4, 0x00, 0x5F }, { 0x3D4, 0x01, 0x3F }, { 0x3D4, 0x02, 0x40 }, { 0x3D4, 0x03, 0x82 }, { 0x3D4, 0x04, 0x4A }, { 0x3D4, 0x05, 0x9A }, { 0x3D4, 0x06, 0x0B }, { 0x3D4, 0x07, 0xB2 }, { 0x3D4, 0x08, 0x00 }, { 0x3D4, 0x09, 0x61 }, { 0x3d4, 0x10, 0x00 }, { 0x3D4, 0x11, 0xAC }, { 0x3D4, 0x12, 0xBF }, { 0x3D4, 0x13, 0x20 }, { 0x3D4, 0x14, 0x40 }, { 0x3D4, 0x15, 0x01 }, { 0x3D4, 0x16, 0x0A }, { 0x3D4, 0x17, 0xA3 }, { 0x3C4, 0x01, 0x01 }, { 0x3C4, 0x04, 0x0E }, { 0, 0, 0 }};static vgareg_t mode_256x240[] ={ { 0x3c2, 0x00, 0xe3},{ 0x3d4, 0x00, 0x55},{ 0x3d4, 0x01, 0x3f}, { 0x3d4, 0x02, 0x80},{ 0x3d4, 0x03, 0x90},{ 0x3d4, 0x04, 0x49}, { 0x3d4, 0x05, 0x80},{ 0x3D4, 0x06, 0x43},{ 0x3d4, 0x07, 0xb2}, { 0x3d4, 0x08, 0x00},{ 0x3D4, 0x09, 0x61},{ 0x3d4, 0x10, 0x04}, { 0x3d4, 0x11, 0xac},{ 0x3D4, 0x12, 0xdf},{ 0x3d4, 0x13, 0x20}, { 0x3d4, 0x14, 0x40},{ 0x3d4, 0x15, 0x07},{ 0x3D4, 0x16, 0x11}, { 0x3d4, 0x17, 0xa3},{ 0x3c4, 0x01, 0x01},{ 0x3c4, 0x04, 0x0e}, { 0, 0, 0 }};static vgareg_t mode_256x256[] ={ { 0x3C2, 0x00, 0xE3 }, { 0x3D4, 0x00, 0x5F }, { 0x3D4, 0x01, 0x3F }, { 0x3D4, 0x02, 0x40 }, { 0x3D4, 0x03, 0x82 }, { 0x3D4, 0x04, 0x4A }, { 0x3D4, 0x05, 0x9A }, { 0x3D4, 0x06, 0x23 }, { 0x3D4, 0x07, 0xB2 }, { 0x3D4, 0x08, 0x00 }, { 0x3D4, 0x09, 0x61 }, { 0x3D4, 0x10, 0x0A }, { 0x3D4, 0x11, 0xAC }, { 0x3D4, 0x12, 0xFF }, { 0x3D4, 0x13, 0x20 }, { 0x3D4, 0x14, 0x40 }, { 0x3D4, 0x15, 0x07 }, { 0x3D4, 0x16, 0x1A }, { 0x3D4, 0x17, 0xA3 }, { 0x3C4, 0x01, 0x01 }, { 0x3C4, 0x04, 0x0E }, { 0, 0, 0 }};/* 60 Hz */static vgareg_t mode_256x256wide[] ={ { 0x3C2, 0x00, 0xE3 }, { 0x3D4, 0x00, 0x52 }, { 0x3D4, 0x01, 0x3F }, { 0x3D4, 0x02, 0x80 }, { 0x3D4, 0x03, 0x90 }, { 0x3D4, 0x04, 0x49 }, { 0x3D4, 0x05, 0x80 }, { 0x3D4, 0x06, 0x55 }, { 0x3D4, 0x07, 0xB2 }, { 0x3D4, 0x08, 0x00 }, { 0x3D4, 0x09, 0x61 }, { 0x3D4, 0x10, 0x20 }, { 0x3D4, 0x11, 0xAC }, { 0x3D4, 0x12, 0xFF }, { 0x3D4, 0x13, 0x20 }, { 0x3D4, 0x14, 0x40 }, { 0x3D4, 0x15, 0x07 }, { 0x3D4, 0x16, 0x1A }, { 0x3D4, 0x17, 0xA3 }, { 0x3C4, 0x01, 0x01 }, { 0x3C4, 0x04, 0x0E }, { 0, 0, 0 }};/* 60 Hz */static vgareg_t mode_288x224[] ={ { 0x3C2, 0x00, 0xE3 }, { 0x3D4, 0x00, 0x5F }, { 0x3D4, 0x01, 0x47 }, { 0x3D4, 0x02, 0x50 }, { 0x3D4, 0x03, 0x82 }, { 0x3D4, 0x04, 0x50 }, { 0x3D4, 0x05, 0x80 }, { 0x3D4, 0x06, 0x08 }, { 0x3D4, 0x07, 0x3E }, { 0x3D4, 0x08, 0x00 }, { 0x3D4, 0x09, 0x41 }, { 0x3D4, 0x10, 0xDA }, { 0x3D4, 0x11, 0x9C }, { 0x3D4, 0x12, 0xBF }, { 0x3D4, 0x13, 0x24 }, { 0x3D4, 0x14, 0x40 }, { 0x3D4, 0x15, 0xC7 }, { 0x3D4, 0x16, 0x04 }, { 0x3D4, 0x17, 0xA3 }, { 0x3C4, 0x01, 0x01 }, { 0x3C4, 0x04, 0x0E }, { 0, 0, 0 }};static vgareg_t mode_320x200[] ={ { 0, 0, 0 }};static vgamode_t vidmodes[] ={ { 288, 224, "288x224", mode_288x224 }, { 256, 224, "256x224", mode_256x224 }, { 256, 240, "256x240", mode_256x240 }, { 256, 256, "256x256 (wide)", mode_256x256wide }, { 256, 256, "256x256", mode_256x256 }, { 320, 200, "320x200", mode_320x200 }, { 0, 0, NULL, 0 }};static bitmap_t *screen = NULL;static bitmap_t *hardware = NULL;/* current VGA mode */static vgamode_t *vga_mode = NULL;/* eek */static int center_x, center_y;static vgareg_t *tweak_addscanlines(vgareg_t *inreg, int entries){ static vgareg_t outreg[32]; int maxscan,maxscanout; int overflow,overflowout; int ytotalin,ytotalout; int ydispin,ydispout; int vrsin,vrsout,vreout,vblksout,vblkeout; /* first - check's it not already a 'non doubled' line mode */ maxscan = inreg[MAXIMUM_SCANLINE_INDEX].value; if ((maxscan & 1) == 0) /* it is, so just return the array as is */ return inreg; /* copy across our standard display array */ memcpy (&outreg, inreg, entries * sizeof(vgareg_t)); /* keep hold of the overflow register - as we'll need to refer to it a lot */ overflow = inreg[OVERFLOW_INDEX].value; /* set a large line compare value - as we won't be doing any split window scrolling etc.*/ maxscanout = 0x40; /* half all the y values */ /* total */ ytotalin = inreg[V_TOTAL_INDEX].value; ytotalin |= ((overflow & 1)<<0x08) | ((overflow & 0x20)<<0x04); ytotalout = ytotalin >> 1; /* display enable end */ ydispin = inreg[13].value | ((overflow & 0x02)<< 0x07) | ((overflow & 0x040) << 0x03); ydispin ++; ydispout = ydispin >> 1; ydispout --; overflowout = ((ydispout & 0x100) >> 0x07) | ((ydispout && 0x200) >> 0x03); outreg[V_END_INDEX].value = (ydispout & 0xff); /* avoid top over scan */ if ((ytotalin - ydispin) < 40 && !center_y) { vrsout = ydispout; /* give ourselves a scanline cushion */ ytotalout += 2; } else { /* vertical retrace start */ vrsin = inreg[V_RETRACE_START_INDEX].value | ((overflow & 0x04)<<0x06) | ((overflow & 0x80)<<0x02); vrsout = vrsin >> 1; } /* check it's legal */ if (vrsout < ydispout) vrsout = ydispout; /* update our output overflow */ overflowout |= (((vrsout & 0x100) >> 0x06) | ((vrsout & 0x200) >> 0x02)); outreg[V_RETRACE_START_INDEX].value = (vrsout & 0xff); /* vertical retrace end */ vreout = vrsout + 2; /* make sure the retrace fits into our adjusted display size */ if (vreout > (ytotalout - 9)) ytotalout = vreout + 9; /* write out the vertical retrace end */ outreg[V_RETRACE_END_INDEX].value &= ~0x0f; outreg[V_RETRACE_END_INDEX].value |= (vreout & 0x0f); /* vertical blanking start */ vblksout = ydispout + 1; /* check it's legal */ if(vblksout > vreout) vblksout = vreout; /* save the overflow value */ overflowout |= ((vblksout & 0x100) >> 0x05); maxscanout |= ((vblksout & 0x200) >> 0x04); /* write the v blank value out */ outreg[V_BLANKING_START_INDEX].value = (vblksout & 0xff); /* vertical blanking end */ vblkeout = vreout + 1; /* make sure the blanking fits into our adjusted display size */ if (vblkeout > (ytotalout - 9)) ytotalout = vblkeout + 9; /* write out the vertical blanking total */ outreg[V_BLANKING_END_INDEX].value = (vblkeout & 0xff); /* update our output overflow */ overflowout |= ((ytotalout & 0x100) >> 0x08) | ((ytotalout & 0x200) >> 0x04); /* write out the new vertical total */ outreg[V_TOTAL_INDEX].value = (ytotalout & 0xff); /* write out our over flows */ outreg[OVERFLOW_INDEX].value = overflowout; /* finally the max scan line */ outreg[MAXIMUM_SCANLINE_INDEX].value = maxscanout; /* and we're done */ return outreg;}static void tweak_centermode(vgareg_t *pReg){ int center; int hrt_start, hrt_end, hrt, hblnk_start, hblnk_end; int vrt_start, vrt_end, vert_total, vert_display, vblnk_start, vrt, vblnk_end; if (!pReg) return; /* vertical retrace width */ vrt = 2; /* check the clock speed, to work out the retrace width */ if (pReg[CLOCK_INDEX].value == 0xe7) hrt = 11; else hrt = 10; /* our center x tweak value */ center = center_x; /* check for double width scanline rather than half clock (15.75kHz modes) */ if( pReg[H_TOTAL_INDEX].value > 0x96) { center<<=1; hrt<<=1; } /* set the hz retrace */ hrt_start = pReg[H_RETRACE_START_INDEX].value; hrt_start += center; /* make sure it's legal */ if (hrt_start <= pReg[H_DISPLAY_INDEX].value) hrt_start = pReg[H_DISPLAY_INDEX].value + 1; pReg[H_RETRACE_START_INDEX].value = hrt_start; /* set hz retrace end */ hrt_end = hrt_start + hrt; /* make sure it's legal */ if( hrt_end > pReg[H_TOTAL_INDEX].value) hrt_end = pReg[H_TOTAL_INDEX].value; /* set the hz blanking */ hblnk_start = pReg[H_DISPLAY_INDEX].value + 1; /* make sure it's legal */ if (hblnk_start > hrt_start) hblnk_start = pReg[H_RETRACE_START_INDEX].value; pReg[H_BLANKING_START_INDEX].value = hblnk_start; /* the horizontal blanking end */ hblnk_end = hrt_end + 2; /* make sure it's legal */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -