mirror of https://gitlab.com/nakst/essence
398 lines
9.3 KiB
C
398 lines
9.3 KiB
C
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id:$
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
//
|
|
// 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 General Public License for more details.
|
|
//
|
|
// $Log:$
|
|
//
|
|
// DESCRIPTION:
|
|
// DOOM graphics stuff for X11, UNIX.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "essence/include.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "v_video.h"
|
|
#include "m_argv.h"
|
|
#include "d_event.h"
|
|
#include "d_main.h"
|
|
#include "i_video.h"
|
|
#include "z_zone.h"
|
|
|
|
#include "tables.h"
|
|
#include "doomkeys.h"
|
|
|
|
struct FB_BitField
|
|
{
|
|
uint32_t offset; /* beginning of bitfield */
|
|
uint32_t length; /* length of bitfield */
|
|
};
|
|
|
|
struct FB_ScreenInfo
|
|
{
|
|
uint32_t xres; /* visible resolution */
|
|
uint32_t yres;
|
|
uint32_t xres_virtual; /* virtual resolution */
|
|
uint32_t yres_virtual;
|
|
|
|
uint32_t bits_per_pixel; /* guess what */
|
|
|
|
/* >1 = FOURCC */
|
|
struct FB_BitField red; /* bitfield in s_Fb mem if true color, */
|
|
struct FB_BitField green; /* else only length is significant */
|
|
struct FB_BitField blue;
|
|
struct FB_BitField transp; /* transparency */
|
|
};
|
|
|
|
static struct FB_ScreenInfo s_Fb;
|
|
uint32_t fb_scaling = 1;
|
|
int usemouse = 0;
|
|
|
|
|
|
#ifdef CMAP256
|
|
|
|
boolean palette_changed;
|
|
struct color colors[256];
|
|
|
|
#else // CMAP256
|
|
|
|
static struct color colors[256];
|
|
|
|
|
|
#endif // CMAP256
|
|
|
|
|
|
void I_GetEvent(void);
|
|
|
|
// The screen buffer; this is modified to draw things to the screen
|
|
|
|
byte *I_VideoBuffer = NULL;
|
|
|
|
// If true, game is running as a screensaver
|
|
|
|
boolean screensaver_mode = false;
|
|
|
|
// Flag indicating whether the screen is currently visible:
|
|
// when the screen isnt visible, don't render the screen
|
|
|
|
boolean screenvisible;
|
|
|
|
// Mouse acceleration
|
|
//
|
|
// This emulates some of the behavior of DOS mouse drivers by increasing
|
|
// the speed when the mouse is moved fast.
|
|
//
|
|
// The mouse input values are input directly to the game, but when
|
|
// the values exceed the value of mouse_threshold, they are multiplied
|
|
// by mouse_acceleration to increase the speed.
|
|
|
|
float mouse_acceleration = 2.0;
|
|
int mouse_threshold = 10;
|
|
|
|
// Gamma correction level to use
|
|
|
|
int usegamma = 0;
|
|
|
|
typedef struct
|
|
{
|
|
byte r;
|
|
byte g;
|
|
byte b;
|
|
} col_t;
|
|
|
|
// Palette converted to RGB565
|
|
|
|
static uint16_t rgb565_palette[256];
|
|
|
|
void cmap_to_rgb565(uint16_t * out, uint8_t * in, size_t in_pixels)
|
|
{
|
|
size_t i, j;
|
|
struct color c;
|
|
uint16_t r, g, b;
|
|
|
|
for (i = 0; i < in_pixels; i++)
|
|
{
|
|
c = colors[*in];
|
|
r = ((uint16_t)(c.r >> 3)) << 11;
|
|
g = ((uint16_t)(c.g >> 2)) << 5;
|
|
b = ((uint16_t)(c.b >> 3)) << 0;
|
|
*out = (r | g | b);
|
|
|
|
in++;
|
|
for (j = 0; j < fb_scaling; j++) {
|
|
out++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cmap_to_fb(uint8_t * out, uint8_t * in, size_t in_pixels)
|
|
{
|
|
size_t i, j, k;
|
|
struct color c;
|
|
uint32_t pix;
|
|
uint16_t r, g, b;
|
|
|
|
for (i = 0; i < in_pixels; i++)
|
|
{
|
|
c = colors[*in]; /* R:8 G:8 B:8 format! */
|
|
r = (uint16_t)(c.r >> (8 - s_Fb.red.length));
|
|
g = (uint16_t)(c.g >> (8 - s_Fb.green.length));
|
|
b = (uint16_t)(c.b >> (8 - s_Fb.blue.length));
|
|
pix = r << s_Fb.red.offset;
|
|
pix |= g << s_Fb.green.offset;
|
|
pix |= b << s_Fb.blue.offset;
|
|
|
|
for (k = 0; k < fb_scaling; k++) {
|
|
for (j = 0; j < s_Fb.bits_per_pixel/8; j++) {
|
|
*out = (pix >> (j*8));
|
|
out++;
|
|
}
|
|
}
|
|
in++;
|
|
}
|
|
}
|
|
|
|
void I_InitGraphics (void)
|
|
{
|
|
ES_memset(&s_Fb, 0, sizeof(struct FB_ScreenInfo));
|
|
s_Fb.xres = RES_X;
|
|
s_Fb.yres = RES_Y;
|
|
s_Fb.xres_virtual = s_Fb.xres;
|
|
s_Fb.yres_virtual = s_Fb.yres;
|
|
|
|
#ifdef CMAP256
|
|
|
|
s_Fb.bits_per_pixel = 8;
|
|
|
|
#else // CMAP256
|
|
|
|
s_Fb.bits_per_pixel = 32;
|
|
|
|
s_Fb.blue.length = 8;
|
|
s_Fb.green.length = 8;
|
|
s_Fb.red.length = 8;
|
|
s_Fb.transp.length = 8;
|
|
|
|
s_Fb.blue.offset = 0;
|
|
s_Fb.green.offset = 8;
|
|
s_Fb.red.offset = 16;
|
|
s_Fb.transp.offset = 24;
|
|
|
|
#endif // CMAP256
|
|
|
|
ES_debugf("I_InitGraphics: framebuffer: x_res: %d, y_res: %d, x_virtual: %d, y_virtual: %d, bpp: %d\n",
|
|
s_Fb.xres, s_Fb.yres, s_Fb.xres_virtual, s_Fb.yres_virtual, s_Fb.bits_per_pixel);
|
|
|
|
ES_debugf("I_InitGraphics: framebuffer: RGBA: %d%d%d%d, red_off: %d, green_off: %d, blue_off: %d, transp_off: %d\n",
|
|
s_Fb.red.length, s_Fb.green.length, s_Fb.blue.length, s_Fb.transp.length, s_Fb.red.offset, s_Fb.green.offset, s_Fb.blue.offset, s_Fb.transp.offset);
|
|
|
|
ES_debugf("I_InitGraphics: DOOM screen size: w x h: %d x %d\n", SCREENWIDTH, SCREENHEIGHT);
|
|
|
|
int i = M_CheckParmWithArgs("-scaling", 1);
|
|
if (i > 0) {
|
|
fb_scaling = (uint32_t)ES_atoi(myargv[i + 1]);
|
|
ES_debugf("I_InitGraphics: Scaling factor: %d\n", fb_scaling);
|
|
} else {
|
|
fb_scaling = s_Fb.xres / SCREENWIDTH;
|
|
if (s_Fb.yres / SCREENHEIGHT < fb_scaling)
|
|
fb_scaling = s_Fb.yres / SCREENHEIGHT;
|
|
ES_debugf("I_InitGraphics: Auto-scaling factor: %d\n", fb_scaling);
|
|
}
|
|
|
|
|
|
/* Allocate screen to draw to */
|
|
I_VideoBuffer = (byte*)Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); // For DOOM to draw on
|
|
|
|
screenvisible = true;
|
|
|
|
extern void I_InitInput(void);
|
|
I_InitInput();
|
|
}
|
|
|
|
void I_ShutdownGraphics (void)
|
|
{
|
|
Z_Free (I_VideoBuffer);
|
|
}
|
|
|
|
void I_StartFrame (void)
|
|
{}
|
|
|
|
void I_StartTic (void)
|
|
{
|
|
I_GetEvent();
|
|
}
|
|
|
|
void I_UpdateNoBlit (void)
|
|
{}
|
|
|
|
//
|
|
// I_FinishUpdate
|
|
//
|
|
|
|
void I_FinishUpdate (void)
|
|
{
|
|
int y;
|
|
int x_offset, y_offset, x_offset_end;
|
|
unsigned char *line_in, *line_out;
|
|
|
|
/* Offsets in case FB is bigger than DOOM */
|
|
/* 600 = s_Fb heigt, 200 screenheight */
|
|
/* 600 = s_Fb heigt, 200 screenheight */
|
|
/* 2048 =s_Fb width, 320 screenwidth */
|
|
y_offset = (((s_Fb.yres - (SCREENHEIGHT * fb_scaling)) * s_Fb.bits_per_pixel/8)) / 2;
|
|
x_offset = (((s_Fb.xres - (SCREENWIDTH * fb_scaling)) * s_Fb.bits_per_pixel/8)) / 2; // XXX: siglent FB hack: /4 instead of /2, since it seems to handle the resolution in a funny way
|
|
//x_offset = 0;
|
|
x_offset_end = ((s_Fb.xres - (SCREENWIDTH * fb_scaling)) * s_Fb.bits_per_pixel/8) - x_offset;
|
|
|
|
/* DRAW SCREEN */
|
|
line_in = (unsigned char *) I_VideoBuffer;
|
|
line_out = (unsigned char *) ES_ScreenBuffer;
|
|
|
|
y = SCREENHEIGHT;
|
|
|
|
while (y--)
|
|
{
|
|
size_t i;
|
|
for (i = 0; i < fb_scaling; i++) {
|
|
line_out += x_offset;
|
|
#ifdef CMAP256
|
|
if (fb_scaling == 1) {
|
|
ES_memcpy(line_out, line_in, SCREENWIDTH); /* fb_width is bigger than Doom SCREENWIDTH... */
|
|
} else {
|
|
int j;
|
|
|
|
for (j = 0; j < SCREENWIDTH; j++) {
|
|
int k;
|
|
for (k = 0; k < fb_scaling; k++) {
|
|
line_out[j * fb_scaling + k] = line_in[j];
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
//cmap_to_rgb565((void*)line_out, (void*)line_in, SCREENWIDTH);
|
|
cmap_to_fb((void*)line_out, (void*)line_in, SCREENWIDTH);
|
|
#endif
|
|
line_out += (SCREENWIDTH * fb_scaling * (s_Fb.bits_per_pixel/8)) + x_offset_end;
|
|
}
|
|
line_in += SCREENWIDTH;
|
|
}
|
|
}
|
|
|
|
//
|
|
// I_ReadScreen
|
|
//
|
|
void I_ReadScreen (byte* scr)
|
|
{
|
|
ES_memcpy (scr, I_VideoBuffer, SCREENWIDTH * SCREENHEIGHT);
|
|
}
|
|
|
|
//
|
|
// I_SetPalette
|
|
//
|
|
#define GFX_RGB565(r, g, b) ((((r & 0xF8) >> 3) << 11) | (((g & 0xFC) >> 2) << 5) | ((b & 0xF8) >> 3))
|
|
#define GFX_RGB565_R(color) ((0xF800 & color) >> 11)
|
|
#define GFX_RGB565_G(color) ((0x07E0 & color) >> 5)
|
|
#define GFX_RGB565_B(color) (0x001F & color)
|
|
|
|
void I_SetPalette (byte* palette)
|
|
{
|
|
int i;
|
|
|
|
/* performance boost:
|
|
* map to the right pixel format over here! */
|
|
|
|
for (i=0; i<256; ++i ) {
|
|
colors[i].a = 0;
|
|
colors[i].r = gammatable[usegamma][*palette++];
|
|
colors[i].g = gammatable[usegamma][*palette++];
|
|
colors[i].b = gammatable[usegamma][*palette++];
|
|
}
|
|
|
|
#ifdef CMAP256
|
|
|
|
palette_changed = true;
|
|
|
|
#endif // CMAP256
|
|
}
|
|
|
|
// Given an RGB value, find the closest matching palette index.
|
|
|
|
int I_GetPaletteIndex(int r, int g, int b)
|
|
{
|
|
int best, best_diff, diff;
|
|
int i;
|
|
col_t color;
|
|
|
|
ES_debugf("I_GetPaletteIndex\n");
|
|
|
|
best = 0;
|
|
best_diff = INT_MAX;
|
|
|
|
for (i = 0; i < 256; ++i)
|
|
{
|
|
color.r = GFX_RGB565_R(rgb565_palette[i]);
|
|
color.g = GFX_RGB565_G(rgb565_palette[i]);
|
|
color.b = GFX_RGB565_B(rgb565_palette[i]);
|
|
|
|
diff = (r - color.r) * (r - color.r)
|
|
+ (g - color.g) * (g - color.g)
|
|
+ (b - color.b) * (b - color.b);
|
|
|
|
if (diff < best_diff)
|
|
{
|
|
best = i;
|
|
best_diff = diff;
|
|
}
|
|
|
|
if (diff == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
void I_BeginRead(void)
|
|
{}
|
|
|
|
void I_EndRead(void)
|
|
{}
|
|
|
|
void I_SetWindowTitle(char *title)
|
|
{
|
|
ES_debugf("I_SetWindowTitle: %s\n", title);
|
|
}
|
|
|
|
void I_GraphicsCheckCommandLine(void)
|
|
{}
|
|
|
|
void I_SetGrabMouseCallback(grabmouse_callback_t func)
|
|
{}
|
|
|
|
void I_EnableLoadingDisk(void)
|
|
{}
|
|
|
|
void I_BindVideoVariables(void)
|
|
{}
|
|
|
|
void I_DisplayFPSDots(boolean dots_on)
|
|
{}
|
|
|
|
void I_CheckIsScreensaver(void)
|
|
{}
|