780 lines
20 KiB
C
780 lines
20 KiB
C
/*
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
* running old operating systems and software designed for IBM
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
* system designs based on the PCI bus.
|
|
*
|
|
* This file is part of the 86Box distribution.
|
|
*
|
|
* Main video-rendering module.
|
|
*
|
|
* Video timing settings -
|
|
*
|
|
* 8-bit - 1mb/sec
|
|
* B = 8 ISA clocks
|
|
* W = 16 ISA clocks
|
|
* L = 32 ISA clocks
|
|
*
|
|
* Slow 16-bit - 2mb/sec
|
|
* B = 6 ISA clocks
|
|
* W = 8 ISA clocks
|
|
* L = 16 ISA clocks
|
|
*
|
|
* Fast 16-bit - 4mb/sec
|
|
* B = 3 ISA clocks
|
|
* W = 3 ISA clocks
|
|
* L = 6 ISA clocks
|
|
*
|
|
* Slow VLB/PCI - 8mb/sec (ish)
|
|
* B = 4 bus clocks
|
|
* W = 8 bus clocks
|
|
* L = 16 bus clocks
|
|
*
|
|
* Mid VLB/PCI -
|
|
* B = 4 bus clocks
|
|
* W = 5 bus clocks
|
|
* L = 10 bus clocks
|
|
*
|
|
* Fast VLB/PCI -
|
|
* B = 3 bus clocks
|
|
* W = 3 bus clocks
|
|
* L = 4 bus clocks
|
|
*
|
|
* Version: @(#)video.c 1.0.18 2018/03/02
|
|
*
|
|
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
|
* Miran Grca, <mgrca8@gmail.com>
|
|
*
|
|
* Copyright 2008-2018 Sarah Walker.
|
|
* Copyright 2016-2018 Miran Grca.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <wchar.h>
|
|
#include <math.h>
|
|
#include "../86box.h"
|
|
#include "../cpu/cpu.h"
|
|
#include "../machine/machine.h"
|
|
#include "../io.h"
|
|
#include "../mem.h"
|
|
#include "../rom.h"
|
|
#include "../config.h"
|
|
#include "../timer.h"
|
|
#include "../plat.h"
|
|
#include "video.h"
|
|
#include "vid_svga.h"
|
|
|
|
|
|
enum {
|
|
VIDEO_ISA = 0,
|
|
VIDEO_BUS
|
|
};
|
|
|
|
bitmap_t *screen = NULL,
|
|
*buffer = NULL,
|
|
*buffer32 = NULL;
|
|
uint8_t fontdat[2048][8]; /* IBM CGA font */
|
|
uint8_t fontdatm[2048][16]; /* IBM MDA font */
|
|
uint8_t fontdatw[512][32]; /* Wyse700 font */
|
|
uint8_t fontdat8x12[256][16]; /* MDSI Genius font */
|
|
uint8_t fontdatksc5601[16384][32]; /* Korean KSC-5601 font */
|
|
uint32_t pal_lookup[256];
|
|
int xsize = 1,
|
|
ysize = 1;
|
|
int cga_palette = 0;
|
|
uint32_t *video_6to8 = NULL,
|
|
*video_15to32 = NULL,
|
|
*video_16to32 = NULL;
|
|
int egareads = 0,
|
|
egawrites = 0,
|
|
changeframecount = 2;
|
|
uint8_t rotatevga[8][256];
|
|
int frames = 0;
|
|
int fullchange = 0;
|
|
uint8_t edatlookup[4][4];
|
|
int overscan_x = 0,
|
|
overscan_y = 0;
|
|
int video_timing_read_b = 0,
|
|
video_timing_read_w = 0,
|
|
video_timing_read_l = 0;
|
|
int video_timing_write_b = 0,
|
|
video_timing_write_w = 0,
|
|
video_timing_write_l = 0;
|
|
int video_res_x = 0,
|
|
video_res_y = 0,
|
|
video_bpp = 0;
|
|
int video_timing[6][4] = {
|
|
{ VIDEO_ISA, 8, 16, 32 },
|
|
{ VIDEO_ISA, 6, 8, 16 },
|
|
{ VIDEO_ISA, 3, 3, 6 },
|
|
{ VIDEO_BUS, 4, 8, 16 },
|
|
{ VIDEO_BUS, 4, 5, 10 },
|
|
{ VIDEO_BUS, 3, 3, 4 }
|
|
};
|
|
static int video_force_resize;
|
|
PALETTE cgapal = {
|
|
{0,0,0}, {0,42,0}, {42,0,0}, {42,21,0},
|
|
{0,0,0}, {0,42,42}, {42,0,42}, {42,42,42},
|
|
{0,0,0}, {21,63,21}, {63,21,21}, {63,63,21},
|
|
{0,0,0}, {21,63,63}, {63,21,63}, {63,63,63},
|
|
|
|
{0,0,0}, {0,0,42}, {0,42,0}, {0,42,42},
|
|
{42,0,0}, {42,0,42}, {42,21,00}, {42,42,42},
|
|
{21,21,21}, {21,21,63}, {21,63,21}, {21,63,63},
|
|
{63,21,21}, {63,21,63}, {63,63,21}, {63,63,63},
|
|
|
|
{0,0,0}, {0,21,0}, {0,0,42}, {0,42,42},
|
|
{42,0,21}, {21,10,21}, {42,0,42}, {42,0,63},
|
|
{21,21,21}, {21,63,21}, {42,21,42}, {21,63,63},
|
|
{63,0,0}, {42,42,0}, {63,21,42}, {41,41,41},
|
|
|
|
{0,0,0}, {0,42,42}, {42,0,0}, {42,42,42},
|
|
{0,0,0}, {0,42,42}, {42,0,0}, {42,42,42},
|
|
{0,0,0}, {0,63,63}, {63,0,0}, {63,63,63},
|
|
{0,0,0}, {0,63,63}, {63,0,0}, {63,63,63},
|
|
};
|
|
PALETTE cgapal_mono[6] = {
|
|
{ /* 0 - green, 4-color-optimized contrast. */
|
|
{0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x17,0x05},
|
|
{0x01,0x1a,0x06},{0x02,0x28,0x09},{0x02,0x2c,0x0a},
|
|
{0x03,0x39,0x0d},{0x03,0x3c,0x0e},{0x00,0x07,0x01},
|
|
{0x01,0x13,0x04},{0x01,0x1f,0x07},{0x01,0x23,0x08},
|
|
{0x02,0x31,0x0b},{0x02,0x35,0x0c},{0x05,0x3f,0x11},{0x0d,0x3f,0x17},
|
|
},
|
|
{ /* 1 - green, 16-color-optimized contrast. */
|
|
{0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x15,0x05},
|
|
{0x01,0x17,0x05},{0x01,0x21,0x08},{0x01,0x24,0x08},
|
|
{0x02,0x2e,0x0b},{0x02,0x31,0x0b},{0x01,0x22,0x08},
|
|
{0x02,0x28,0x09},{0x02,0x30,0x0b},{0x02,0x32,0x0c},
|
|
{0x03,0x39,0x0d},{0x03,0x3b,0x0e},{0x09,0x3f,0x14},{0x0d,0x3f,0x17},
|
|
},
|
|
{ /* 2 - amber, 4-color-optimized contrast. */
|
|
{0x00,0x00,0x00},{0x15,0x05,0x00},{0x20,0x0b,0x00},
|
|
{0x24,0x0d,0x00},{0x33,0x18,0x00},{0x37,0x1b,0x00},
|
|
{0x3f,0x26,0x01},{0x3f,0x2b,0x06},{0x0b,0x02,0x00},
|
|
{0x1b,0x08,0x00},{0x29,0x11,0x00},{0x2e,0x14,0x00},
|
|
{0x3b,0x1e,0x00},{0x3e,0x21,0x00},{0x3f,0x32,0x0a},{0x3f,0x38,0x0d},
|
|
},
|
|
{ /* 3 - amber, 16-color-optimized contrast. */
|
|
{0x00,0x00,0x00},{0x15,0x05,0x00},{0x1e,0x09,0x00},
|
|
{0x21,0x0b,0x00},{0x2b,0x12,0x00},{0x2f,0x15,0x00},
|
|
{0x38,0x1c,0x00},{0x3b,0x1e,0x00},{0x2c,0x13,0x00},
|
|
{0x32,0x17,0x00},{0x3a,0x1e,0x00},{0x3c,0x1f,0x00},
|
|
{0x3f,0x27,0x01},{0x3f,0x2a,0x04},{0x3f,0x36,0x0c},{0x3f,0x38,0x0d},
|
|
},
|
|
{ /* 4 - grey, 4-color-optimized contrast. */
|
|
{0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x15,0x17,0x18},
|
|
{0x18,0x1a,0x1b},{0x24,0x25,0x25},{0x27,0x28,0x28},
|
|
{0x33,0x34,0x32},{0x37,0x38,0x35},{0x09,0x0a,0x0b},
|
|
{0x11,0x12,0x13},{0x1c,0x1e,0x1e},{0x20,0x22,0x22},
|
|
{0x2c,0x2d,0x2c},{0x2f,0x30,0x2f},{0x3c,0x3c,0x38},{0x3f,0x3f,0x3b},
|
|
},
|
|
{ /* 5 - grey, 16-color-optimized contrast. */
|
|
{0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x13,0x14,0x15},
|
|
{0x15,0x17,0x18},{0x1e,0x20,0x20},{0x20,0x22,0x22},
|
|
{0x29,0x2a,0x2a},{0x2c,0x2d,0x2c},{0x1f,0x21,0x21},
|
|
{0x23,0x25,0x25},{0x2b,0x2c,0x2b},{0x2d,0x2e,0x2d},
|
|
{0x34,0x35,0x33},{0x37,0x37,0x34},{0x3e,0x3e,0x3a},{0x3f,0x3f,0x3b},
|
|
}
|
|
};
|
|
|
|
|
|
static struct {
|
|
int x, y, y1, y2, w, h;
|
|
int busy;
|
|
int buffer_in_use;
|
|
|
|
thread_t *blit_thread;
|
|
event_t *wake_blit_thread;
|
|
event_t *blit_complete;
|
|
event_t *buffer_not_in_use;
|
|
} blit_data;
|
|
|
|
|
|
static void (*blit_func)(int x, int y, int y1, int y2, int w, int h);
|
|
|
|
|
|
static
|
|
void blit_thread(void *param)
|
|
{
|
|
while (1) {
|
|
thread_wait_event(blit_data.wake_blit_thread, -1);
|
|
thread_reset_event(blit_data.wake_blit_thread);
|
|
|
|
if (blit_func)
|
|
blit_func(blit_data.x, blit_data.y,
|
|
blit_data.y1, blit_data.y2,
|
|
blit_data.w, blit_data.h);
|
|
|
|
blit_data.busy = 0;
|
|
thread_set_event(blit_data.blit_complete);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
video_setblit(void(*blit)(int,int,int,int,int,int))
|
|
{
|
|
blit_func = blit;
|
|
}
|
|
|
|
|
|
void
|
|
video_blit_complete(void)
|
|
{
|
|
blit_data.buffer_in_use = 0;
|
|
|
|
thread_set_event(blit_data.buffer_not_in_use);
|
|
}
|
|
|
|
|
|
void
|
|
video_wait_for_blit(void)
|
|
{
|
|
while (blit_data.busy)
|
|
thread_wait_event(blit_data.blit_complete, -1);
|
|
thread_reset_event(blit_data.blit_complete);
|
|
}
|
|
|
|
|
|
void
|
|
video_wait_for_buffer(void)
|
|
{
|
|
while (blit_data.buffer_in_use)
|
|
thread_wait_event(blit_data.buffer_not_in_use, -1);
|
|
thread_reset_event(blit_data.buffer_not_in_use);
|
|
}
|
|
|
|
|
|
void
|
|
video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h)
|
|
{
|
|
if (h <= 0) return;
|
|
|
|
video_wait_for_blit();
|
|
|
|
blit_data.busy = 1;
|
|
blit_data.buffer_in_use = 1;
|
|
blit_data.x = x;
|
|
blit_data.y = y;
|
|
blit_data.y1 = y1;
|
|
blit_data.y2 = y2;
|
|
blit_data.w = w;
|
|
blit_data.h = h;
|
|
|
|
thread_set_event(blit_data.wake_blit_thread);
|
|
}
|
|
|
|
|
|
void
|
|
video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h)
|
|
{
|
|
int yy, xx;
|
|
|
|
if (h <= 0) return;
|
|
|
|
for (yy = 0; yy < h; yy++)
|
|
{
|
|
if ((y + yy) >= 0 && (y + yy) < buffer->h)
|
|
{
|
|
for (xx = 0; xx < w; xx++)
|
|
*(uint32_t *) &(buffer32->line[y + yy][(x + xx) << 2]) = pal_lookup[buffer->line[y + yy][x + xx]];
|
|
}
|
|
}
|
|
|
|
video_blit_memtoscreen(x, y, y1, y2, w, h);
|
|
}
|
|
|
|
|
|
void
|
|
cgapal_rebuild(void)
|
|
{
|
|
int c;
|
|
|
|
/* We cannot do this (yet) if we have not been enabled yet. */
|
|
if (video_6to8 == NULL) return;
|
|
|
|
for (c=0; c<256; c++) {
|
|
pal_lookup[c] = makecol(video_6to8[cgapal[c].r],
|
|
video_6to8[cgapal[c].g],
|
|
video_6to8[cgapal[c].b]);
|
|
}
|
|
|
|
if ((cga_palette > 1) && (cga_palette < 8)) {
|
|
if (vid_cga_contrast != 0) {
|
|
for (c=0; c<16; c++) {
|
|
pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r],
|
|
video_6to8[cgapal_mono[cga_palette - 2][c].g],
|
|
video_6to8[cgapal_mono[cga_palette - 2][c].b]);
|
|
pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r],
|
|
video_6to8[cgapal_mono[cga_palette - 2][c].g],
|
|
video_6to8[cgapal_mono[cga_palette - 2][c].b]);
|
|
pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r],
|
|
video_6to8[cgapal_mono[cga_palette - 2][c].g],
|
|
video_6to8[cgapal_mono[cga_palette - 2][c].b]);
|
|
pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r],
|
|
video_6to8[cgapal_mono[cga_palette - 2][c].g],
|
|
video_6to8[cgapal_mono[cga_palette - 2][c].b]);
|
|
}
|
|
} else {
|
|
for (c=0; c<16; c++) {
|
|
pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r],
|
|
video_6to8[cgapal_mono[cga_palette - 1][c].g],
|
|
video_6to8[cgapal_mono[cga_palette - 1][c].b]);
|
|
pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r],
|
|
video_6to8[cgapal_mono[cga_palette - 1][c].g],
|
|
video_6to8[cgapal_mono[cga_palette - 1][c].b]);
|
|
pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r],
|
|
video_6to8[cgapal_mono[cga_palette - 1][c].g],
|
|
video_6to8[cgapal_mono[cga_palette - 1][c].b]);
|
|
pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r],
|
|
video_6to8[cgapal_mono[cga_palette - 1][c].g],
|
|
video_6to8[cgapal_mono[cga_palette - 1][c].b]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cga_palette == 8)
|
|
pal_lookup[0x16] = makecol(video_6to8[42],video_6to8[42],video_6to8[0]);
|
|
}
|
|
|
|
|
|
static video_timings_t timing_dram = {VIDEO_BUS, 0,0,0, 0,0,0}; /*No additional waitstates*/
|
|
static video_timings_t timing_pc1512 = {VIDEO_BUS, 0,0,0, 0,0,0}; /*PC1512 video code handles waitstates itself*/
|
|
static video_timings_t timing_pc1640 = {VIDEO_ISA, 8,16,32, 8,16,32};
|
|
static video_timings_t timing_pc200 = {VIDEO_ISA, 8,16,32, 8,16,32};
|
|
static video_timings_t timing_m24 = {VIDEO_ISA, 8,16,32, 8,16,32};
|
|
static video_timings_t timing_t1000 = {VIDEO_ISA, 8,16,32, 8,16,32};
|
|
static video_timings_t timing_pvga1a = {VIDEO_ISA, 6, 8,16, 6, 8,16};
|
|
static video_timings_t timing_wd90c11 = {VIDEO_ISA, 3, 3, 6, 5, 5,10};
|
|
static video_timings_t timing_vga = {VIDEO_ISA, 8,16,32, 8,16,32};
|
|
static video_timings_t timing_ps1_svga = {VIDEO_ISA, 6, 8,16, 6, 8,16};
|
|
static video_timings_t timing_t3100e = {VIDEO_ISA, 8,16,32, 8,16,32};
|
|
static video_timings_t timing_endeavor = {VIDEO_BUS, 3, 2, 4,25,25,40};
|
|
|
|
void
|
|
video_update_timing(void)
|
|
{
|
|
video_timings_t *timing;
|
|
int new_gfxcard;
|
|
|
|
if (video_speed == -1) {
|
|
new_gfxcard = 0;
|
|
|
|
switch(romset) {
|
|
case ROM_IBMPCJR:
|
|
case ROM_TANDY:
|
|
case ROM_TANDY1000HX:
|
|
case ROM_TANDY1000SL2:
|
|
timing = &timing_dram;
|
|
break;
|
|
case ROM_PC1512:
|
|
timing = &timing_pc1512;
|
|
break;
|
|
case ROM_PC1640:
|
|
timing = &timing_pc1640;
|
|
break;
|
|
case ROM_PC200:
|
|
timing = &timing_pc200;
|
|
break;
|
|
case ROM_OLIM24:
|
|
timing = &timing_m24;
|
|
break;
|
|
case ROM_PC2086:
|
|
case ROM_PC3086:
|
|
timing = &timing_pvga1a;
|
|
break;
|
|
case ROM_T1000:
|
|
case ROM_T1200:
|
|
timing = &timing_t1000;
|
|
break;
|
|
case ROM_MEGAPC:
|
|
case ROM_MEGAPCDX:
|
|
timing = &timing_wd90c11;
|
|
break;
|
|
case ROM_IBMPS1_2011:
|
|
case ROM_IBMPS2_M30_286:
|
|
case ROM_IBMPS2_M50:
|
|
case ROM_IBMPS2_M55SX:
|
|
case ROM_IBMPS2_M80:
|
|
timing = &timing_vga;
|
|
break;
|
|
case ROM_IBMPS1_2121:
|
|
case ROM_IBMPS1_2133:
|
|
timing = &timing_ps1_svga;
|
|
break;
|
|
case ROM_T3100E:
|
|
timing = &timing_t3100e;
|
|
break;
|
|
case ROM_ENDEAVOR:
|
|
timing = &timing_endeavor;
|
|
break;
|
|
default:
|
|
new_gfxcard = video_old_to_new(gfxcard);
|
|
timing = video_card_gettiming(new_gfxcard);
|
|
break;
|
|
}
|
|
|
|
if (timing->type == VIDEO_ISA) {
|
|
video_timing_read_b = ISA_CYCLES(timing->read_b);
|
|
video_timing_read_w = ISA_CYCLES(timing->read_w);
|
|
video_timing_read_l = ISA_CYCLES(timing->read_l);
|
|
video_timing_write_b = ISA_CYCLES(timing->write_b);
|
|
video_timing_write_w = ISA_CYCLES(timing->write_w);
|
|
video_timing_write_l = ISA_CYCLES(timing->write_l);
|
|
} else {
|
|
video_timing_read_b = (int)(bus_timing * timing->read_b);
|
|
video_timing_read_w = (int)(bus_timing * timing->read_w);
|
|
video_timing_read_l = (int)(bus_timing * timing->read_l);
|
|
video_timing_write_b = (int)(bus_timing * timing->write_b);
|
|
video_timing_write_w = (int)(bus_timing * timing->write_w);
|
|
video_timing_write_l = (int)(bus_timing * timing->write_l);
|
|
}
|
|
} else {
|
|
if (video_timing[video_speed][0] == VIDEO_ISA) {
|
|
video_timing_read_b = ISA_CYCLES(video_timing[video_speed][1]);
|
|
video_timing_read_w = ISA_CYCLES(video_timing[video_speed][2]);
|
|
video_timing_read_l = ISA_CYCLES(video_timing[video_speed][3]);
|
|
video_timing_write_b = ISA_CYCLES(video_timing[video_speed][1]);
|
|
video_timing_write_w = ISA_CYCLES(video_timing[video_speed][2]);
|
|
video_timing_write_l = ISA_CYCLES(video_timing[video_speed][3]);
|
|
} else {
|
|
video_timing_read_b = (int)(bus_timing * video_timing[video_speed][1]);
|
|
video_timing_read_w = (int)(bus_timing * video_timing[video_speed][2]);
|
|
video_timing_read_l = (int)(bus_timing * video_timing[video_speed][3]);
|
|
video_timing_write_b = (int)(bus_timing * video_timing[video_speed][1]);
|
|
video_timing_write_w = (int)(bus_timing * video_timing[video_speed][2]);
|
|
video_timing_write_l = (int)(bus_timing * video_timing[video_speed][3]);
|
|
}
|
|
}
|
|
|
|
if (cpu_16bitbus) {
|
|
video_timing_read_l = video_timing_read_w * 2;
|
|
video_timing_write_l = video_timing_write_w * 2;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
calc_6to8(int c)
|
|
{
|
|
int ic, i8;
|
|
double d8;
|
|
|
|
ic = c;
|
|
if (ic == 64)
|
|
ic = 63;
|
|
else
|
|
ic &= 0x3f;
|
|
d8 = (ic / 63.0) * 255.0;
|
|
i8 = (int) d8;
|
|
|
|
return(i8 & 0xff);
|
|
}
|
|
|
|
|
|
int
|
|
calc_15to32(int c)
|
|
{
|
|
int b, g, r;
|
|
double db, dg, dr;
|
|
|
|
b = (c & 31);
|
|
g = ((c >> 5) & 31);
|
|
r = ((c >> 10) & 31);
|
|
db = (((double) b) / 31.0) * 255.0;
|
|
dg = (((double) g) / 31.0) * 255.0;
|
|
dr = (((double) r) / 31.0) * 255.0;
|
|
b = (int) db;
|
|
g = ((int) dg) << 8;
|
|
r = ((int) dr) << 16;
|
|
|
|
return(b | g | r);
|
|
}
|
|
|
|
|
|
int
|
|
calc_16to32(int c)
|
|
{
|
|
int b, g, r;
|
|
double db, dg, dr;
|
|
|
|
b = (c & 31);
|
|
g = ((c >> 5) & 63);
|
|
r = ((c >> 11) & 31);
|
|
db = (((double) b) / 31.0) * 255.0;
|
|
dg = (((double) g) / 63.0) * 255.0;
|
|
dr = (((double) r) / 31.0) * 255.0;
|
|
b = (int) db;
|
|
g = ((int) dg) << 8;
|
|
r = ((int) dr) << 16;
|
|
|
|
return(b | g | r);
|
|
}
|
|
|
|
|
|
void
|
|
hline(bitmap_t *b, int x1, int y, int x2, uint32_t col)
|
|
{
|
|
if (y < 0 || y >= buffer->h)
|
|
return;
|
|
|
|
if (b == buffer)
|
|
memset(&b->line[y][x1], col, x2 - x1);
|
|
else
|
|
memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4);
|
|
}
|
|
|
|
|
|
void
|
|
blit(bitmap_t *src, bitmap_t *dst, int x1, int y1, int x2, int y2, int xs, int ys)
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
stretch_blit(bitmap_t *src, bitmap_t *dst, int x1, int y1, int xs1, int ys1, int x2, int y2, int xs2, int ys2)
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
rectfill(bitmap_t *b, int x1, int y1, int x2, int y2, uint32_t col)
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
set_palette(PALETTE p)
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
destroy_bitmap(bitmap_t *b)
|
|
{
|
|
if (b->dat != NULL)
|
|
free(b->dat);
|
|
free(b);
|
|
}
|
|
|
|
|
|
bitmap_t *
|
|
create_bitmap(int x, int y)
|
|
{
|
|
bitmap_t *b = malloc(sizeof(bitmap_t) + (y * sizeof(uint8_t *)));
|
|
int c;
|
|
|
|
b->dat = malloc(x * y * 4);
|
|
for (c = 0; c < y; c++)
|
|
b->line[c] = b->dat + (c * x * 4);
|
|
b->w = x;
|
|
b->h = y;
|
|
|
|
return(b);
|
|
}
|
|
|
|
|
|
void
|
|
video_init(void)
|
|
{
|
|
int c, d, e;
|
|
|
|
/* Account for overscan. */
|
|
buffer32 = create_bitmap(2048, 2048);
|
|
|
|
buffer = create_bitmap(2048, 2048);
|
|
for (c = 0; c < 64; c++) {
|
|
cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21;
|
|
cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21;
|
|
cgapal[c + 64].b = (((c & 1) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21;
|
|
if ((c & 0x17) == 6)
|
|
cgapal[c + 64].g >>= 1;
|
|
}
|
|
for (c = 0; c < 64; c++) {
|
|
cgapal[c + 128].r = (((c & 4) ? 2 : 0) | ((c & 0x20) ? 1 : 0)) * 21;
|
|
cgapal[c + 128].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21;
|
|
cgapal[c + 128].b = (((c & 1) ? 2 : 0) | ((c & 0x08) ? 1 : 0)) * 21;
|
|
}
|
|
|
|
for (c = 0; c < 256; c++) {
|
|
e = c;
|
|
for (d = 0; d < 8; d++) {
|
|
rotatevga[d][c] = e;
|
|
e = (e >> 1) | ((e & 1) ? 0x80 : 0);
|
|
}
|
|
}
|
|
for (c = 0; c < 4; c++) {
|
|
for (d = 0; d < 4; d++) {
|
|
edatlookup[c][d] = 0;
|
|
if (c & 1) edatlookup[c][d] |= 1;
|
|
if (d & 1) edatlookup[c][d] |= 2;
|
|
if (c & 2) edatlookup[c][d] |= 0x10;
|
|
if (d & 2) edatlookup[c][d] |= 0x20;
|
|
}
|
|
}
|
|
|
|
video_6to8 = malloc(4 * 256);
|
|
for (c = 0; c < 256; c++)
|
|
video_6to8[c] = calc_6to8(c);
|
|
video_15to32 = malloc(4 * 65536);
|
|
#if 0
|
|
for (c = 0; c < 65536; c++)
|
|
video_15to32[c] = ((c & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 10) & 31) << 19);
|
|
#endif
|
|
for (c = 0; c < 65536; c++)
|
|
video_15to32[c] = calc_15to32(c);
|
|
|
|
video_16to32 = malloc(4 * 65536);
|
|
#if 0
|
|
for (c = 0; c < 65536; c++)
|
|
video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19);
|
|
#endif
|
|
for (c = 0; c < 65536; c++)
|
|
video_16to32[c] = calc_16to32(c);
|
|
|
|
blit_data.wake_blit_thread = thread_create_event();
|
|
blit_data.blit_complete = thread_create_event();
|
|
blit_data.buffer_not_in_use = thread_create_event();
|
|
blit_data.blit_thread = thread_create(blit_thread, NULL);
|
|
}
|
|
|
|
|
|
void
|
|
video_close(void)
|
|
{
|
|
thread_kill(blit_data.blit_thread);
|
|
thread_destroy_event(blit_data.buffer_not_in_use);
|
|
thread_destroy_event(blit_data.blit_complete);
|
|
thread_destroy_event(blit_data.wake_blit_thread);
|
|
|
|
free(video_6to8);
|
|
free(video_15to32);
|
|
free(video_16to32);
|
|
|
|
destroy_bitmap(buffer);
|
|
destroy_bitmap(buffer32);
|
|
}
|
|
|
|
|
|
uint8_t
|
|
video_force_resize_get(void)
|
|
{
|
|
return video_force_resize;
|
|
}
|
|
|
|
|
|
void
|
|
video_force_resize_set(uint8_t res)
|
|
{
|
|
video_force_resize = res;
|
|
}
|
|
|
|
|
|
void
|
|
loadfont(wchar_t *s, int format)
|
|
{
|
|
FILE *f;
|
|
int c,d;
|
|
|
|
f = rom_fopen(s, L"rb");
|
|
if (f == NULL) {
|
|
pclog("VIDEO: cannot load font '%ls', fmt=%d\n", s, format);
|
|
return;
|
|
}
|
|
|
|
switch (format) {
|
|
case 0: /* MDA */
|
|
for (c=0; c<256; c++)
|
|
for (d=0; d<8; d++)
|
|
fontdatm[c][d] = fgetc(f);
|
|
for (c=0; c<256; c++)
|
|
for (d=0; d<8; d++)
|
|
fontdatm[c][d+8] = fgetc(f);
|
|
(void)fseek(f, 4096+2048, SEEK_SET);
|
|
for (c=0; c<256; c++)
|
|
for (d=0; d<8; d++)
|
|
fontdat[c][d] = fgetc(f);
|
|
break;
|
|
|
|
case 1: /* PC200 */
|
|
for (c=0; c<256; c++)
|
|
for (d=0; d<8; d++)
|
|
fontdatm[c][d] = fgetc(f);
|
|
for (c=0; c<256; c++)
|
|
for (d=0; d<8; d++)
|
|
fontdatm[c][d+8] = fgetc(f);
|
|
(void)fseek(f, 4096, SEEK_SET);
|
|
for (c=0; c<256; c++) {
|
|
for (d=0; d<8; d++)
|
|
fontdat[c][d] = fgetc(f);
|
|
for (d=0; d<8; d++) (void)fgetc(f);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
case 2: /* CGA */
|
|
for (c=0; c<256; c++)
|
|
for (d=0; d<8; d++)
|
|
fontdat[c][d] = fgetc(f);
|
|
break;
|
|
|
|
case 3: /* Wyse 700 */
|
|
for (c=0; c<512; c++)
|
|
for (d=0; d<32; d++)
|
|
fontdatw[c][d] = fgetc(f);
|
|
break;
|
|
|
|
case 4: /* MDSI Genius */
|
|
for (c=0; c<256; c++)
|
|
for (d=0; d<16; d++)
|
|
fontdat8x12[c][d] = fgetc(f);
|
|
break;
|
|
|
|
case 5: /* Toshiba 3100e */
|
|
for (d = 0; d < 2048; d += 512) /* Four languages... */
|
|
{
|
|
for (c = d; c < d+256; c++)
|
|
{
|
|
fread(&fontdatm[c][8], 1, 8, f);
|
|
}
|
|
for (c = d+256; c < d+512; c++)
|
|
{
|
|
fread(&fontdatm[c][8], 1, 8, f);
|
|
}
|
|
for (c = d; c < d+256; c++)
|
|
{
|
|
fread(&fontdatm[c][0], 1, 8, f);
|
|
}
|
|
for (c = d+256; c < d+512; c++)
|
|
{
|
|
fread(&fontdatm[c][0], 1, 8, f);
|
|
}
|
|
fseek(f, 4096, SEEK_CUR); /* Skip blank section */
|
|
for (c = d; c < d+256; c++)
|
|
{
|
|
fread(&fontdat[c][0], 1, 8, f);
|
|
}
|
|
for (c = d+256; c < d+512; c++)
|
|
{
|
|
fread(&fontdat[c][0], 1, 8, f);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 6: /* Korean KSC-5601 */
|
|
for (c=0;c<16384;c++)
|
|
{
|
|
for (d=0;d<32;d++)
|
|
{
|
|
fontdatksc5601[c][d]=getc(f);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
(void)fclose(f);
|
|
}
|