fallout2-ce/src/svga.cc

423 lines
10 KiB
C++
Raw Normal View History

2022-10-05 00:35:05 -07:00
#include "svga.h"
2022-05-19 01:51:26 -07:00
2022-09-15 02:38:23 -07:00
#include <limits.h>
#include <string.h>
#include <SDL.h>
#include "config.h"
2022-05-19 01:51:26 -07:00
#include "draw.h"
#include "interface.h"
2022-05-19 01:51:26 -07:00
#include "memory.h"
2022-10-03 02:41:33 -07:00
#include "mouse.h"
2022-05-28 11:46:58 -07:00
#include "win32.h"
2022-05-19 01:51:26 -07:00
#include "window_manager.h"
#include "window_manager_private.h"
2022-09-23 05:43:44 -07:00
namespace fallout {
2022-10-04 03:15:54 -07:00
static bool createRenderer(int width, int height);
static void destroyRenderer();
2022-08-16 04:24:57 -07:00
2022-05-19 01:51:26 -07:00
// screen rect
Rect _scr_size;
// 0x6ACA18
void (*_scr_blit)(unsigned char* src, int src_pitch, int a3, int src_x, int src_y, int src_width, int src_height, int dest_x, int dest_y) = _GNW95_ShowRect;
// 0x6ACA1C
void (*_zero_mem)() = NULL;
2022-05-19 04:01:17 -07:00
SDL_Window* gSdlWindow = NULL;
SDL_Surface* gSdlSurface = NULL;
2022-07-12 00:10:23 -07:00
SDL_Renderer* gSdlRenderer = NULL;
SDL_Texture* gSdlTexture = NULL;
SDL_Surface* gSdlTextureSurface = NULL;
2022-05-19 04:01:17 -07:00
2022-10-07 14:54:27 -07:00
// TODO: Remove once migration to update-render cycle is completed.
FpsLimiter sharedFpsLimiter;
2022-05-19 01:51:26 -07:00
// 0x4CAD08
int _init_mode_320_200()
{
return _GNW95_init_mode_ex(320, 200, 8);
}
// 0x4CAD40
int _init_mode_320_400()
{
return _GNW95_init_mode_ex(320, 400, 8);
}
// 0x4CAD5C
int _init_mode_640_480_16()
{
return -1;
}
// 0x4CAD64
int _init_mode_640_480()
{
return _init_vesa_mode(640, 480);
}
// 0x4CAD94
int _init_mode_640_400()
{
return _init_vesa_mode(640, 400);
}
// 0x4CADA8
int _init_mode_800_600()
{
return _init_vesa_mode(800, 600);
}
// 0x4CADBC
int _init_mode_1024_768()
{
return _init_vesa_mode(1024, 768);
}
// 0x4CADD0
int _init_mode_1280_1024()
{
return _init_vesa_mode(1280, 1024);
}
// 0x4CADF8
void _get_start_mode_()
{
}
// 0x4CADFC
void _zero_vid_mem()
{
if (_zero_mem) {
_zero_mem();
}
}
// 0x4CAE1C
int _GNW95_init_mode_ex(int width, int height, int bpp)
{
2022-05-19 04:01:17 -07:00
bool fullscreen = true;
int scale = 1;
2022-05-19 04:01:17 -07:00
Config resolutionConfig;
if (configInit(&resolutionConfig)) {
if (configRead(&resolutionConfig, "f2_res.ini", false)) {
int screenWidth;
if (configGetInt(&resolutionConfig, "MAIN", "SCR_WIDTH", &screenWidth)) {
width = screenWidth;
}
int screenHeight;
if (configGetInt(&resolutionConfig, "MAIN", "SCR_HEIGHT", &screenHeight)) {
height = screenHeight;
}
bool windowed;
if (configGetBool(&resolutionConfig, "MAIN", "WINDOWED", &windowed)) {
fullscreen = !windowed;
}
int scaleValue;
if (configGetInt(&resolutionConfig, "MAIN", "SCALE_2X", &scaleValue)) {
scale = scaleValue + 1; // 0 = 1x, 1 = 2x
// Only allow scaling if resulting game resolution is >= 640x480
if ((width / scale) < 640 || (height / scale) < 480) {
scale = 1;
} else {
width /= scale;
height /= scale;
}
}
configGetBool(&resolutionConfig, "IFACE", "IFACE_BAR_MODE", &gInterfaceBarMode);
2022-11-07 02:35:22 -08:00
configGetInt(&resolutionConfig, "IFACE", "IFACE_BAR_WIDTH", &gInterfaceBarWidth);
2022-11-07 05:05:34 -08:00
configGetInt(&resolutionConfig, "IFACE", "IFACE_BAR_SIDE_ART", &gInterfaceSidePanelsImageId);
configGetBool(&resolutionConfig, "IFACE", "IFACE_BAR_SIDES_ORI", &gInterfaceSidePanelsExtendFromScreenEdge);
2022-05-19 04:01:17 -07:00
}
configFree(&resolutionConfig);
}
if (_GNW95_init_window(width, height, fullscreen, scale) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (directDrawInit(width, height, bpp) == -1) {
return -1;
}
_scr_size.left = 0;
_scr_size.top = 0;
_scr_size.right = width - 1;
_scr_size.bottom = height - 1;
2022-12-08 06:26:28 -08:00
_mouse_blit_trans = NULL;
_scr_blit = _GNW95_ShowRect;
_zero_mem = _GNW95_zero_vid_mem;
_mouse_blit = _GNW95_ShowRect;
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4CAECC
int _init_vesa_mode(int width, int height)
{
return _GNW95_init_mode_ex(width, height, 8);
}
// 0x4CAEDC
int _GNW95_init_window(int width, int height, bool fullscreen, int scale)
2022-05-19 01:51:26 -07:00
{
2022-05-23 01:44:49 -07:00
if (gSdlWindow == NULL) {
2022-07-12 00:10:23 -07:00
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
2022-05-19 04:01:17 -07:00
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
return -1;
}
2022-05-19 01:51:26 -07:00
2022-10-14 01:40:11 -07:00
Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI;
2022-07-12 00:10:23 -07:00
if (fullscreen) {
windowFlags |= SDL_WINDOW_FULLSCREEN;
}
gSdlWindow = SDL_CreateWindow(gProgramWindowTitle, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width * scale, height * scale, windowFlags);
2022-05-19 04:01:17 -07:00
if (gSdlWindow == NULL) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-10-04 03:15:54 -07:00
if (!createRenderer(width, height)) {
destroyRenderer();
2022-07-12 00:10:23 -07:00
2022-10-04 03:15:54 -07:00
SDL_DestroyWindow(gSdlWindow);
gSdlWindow = NULL;
2022-07-12 00:10:23 -07:00
2022-10-04 03:15:54 -07:00
return -1;
2022-05-19 04:01:17 -07:00
}
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4CAF9C
int directDrawInit(int width, int height, int bpp)
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL) {
2022-05-19 01:51:26 -07:00
unsigned char* palette = directDrawGetPalette();
directDrawFree();
if (directDrawInit(width, height, bpp) == -1) {
return -1;
}
directDrawSetPalette(palette);
return 0;
}
2022-05-19 04:01:17 -07:00
gSdlSurface = SDL_CreateRGBSurface(0, width, height, bpp, 0, 0, 0, 0);
2022-05-19 01:51:26 -07:00
2022-12-08 06:26:28 -08:00
SDL_Color colors[256];
for (int index = 0; index < 256; index++) {
colors[index].r = index;
colors[index].g = index;
colors[index].b = index;
colors[index].a = 255;
2022-05-19 01:51:26 -07:00
}
2022-05-24 13:19:36 -07:00
2022-12-08 06:26:28 -08:00
SDL_SetPaletteColors(gSdlSurface->format->palette, colors, 0, 256);
2022-05-24 13:19:36 -07:00
return 0;
2022-05-19 01:51:26 -07:00
}
// 0x4CB1B0
void directDrawFree()
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL) {
SDL_FreeSurface(gSdlSurface);
gSdlSurface = NULL;
2022-05-19 01:51:26 -07:00
}
}
// 0x4CB310
void directDrawSetPaletteInRange(unsigned char* palette, int start, int count)
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) {
SDL_Color colors[256];
2022-05-19 01:51:26 -07:00
if (count != 0) {
for (int index = 0; index < count; index++) {
2022-05-19 04:01:17 -07:00
colors[index].r = palette[index * 3] << 2;
colors[index].g = palette[index * 3 + 1] << 2;
colors[index].b = palette[index * 3 + 2] << 2;
colors[index].a = 255;
2022-05-19 01:51:26 -07:00
}
}
2022-05-19 04:01:17 -07:00
SDL_SetPaletteColors(gSdlSurface->format->palette, colors, start, count);
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL);
2022-05-19 01:51:26 -07:00
}
}
// 0x4CB568
void directDrawSetPalette(unsigned char* palette)
{
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) {
SDL_Color colors[256];
2022-05-19 01:51:26 -07:00
for (int index = 0; index < 256; index++) {
2022-05-19 04:01:17 -07:00
colors[index].r = palette[index * 3] << 2;
colors[index].g = palette[index * 3 + 1] << 2;
colors[index].b = palette[index * 3 + 2] << 2;
colors[index].a = 255;
2022-05-19 01:51:26 -07:00
}
2022-05-19 04:01:17 -07:00
SDL_SetPaletteColors(gSdlSurface->format->palette, colors, 0, 256);
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL);
2022-05-19 01:51:26 -07:00
}
}
// 0x4CB68C
unsigned char* directDrawGetPalette()
{
2022-12-08 06:26:28 -08:00
// 0x6ACA24
static unsigned char palette[768];
2022-05-19 04:01:17 -07:00
if (gSdlSurface != NULL && gSdlSurface->format->palette != NULL) {
SDL_Color* colors = gSdlSurface->format->palette->colors;
2022-05-19 01:51:26 -07:00
for (int index = 0; index < 256; index++) {
2022-05-19 04:01:17 -07:00
SDL_Color* color = &(colors[index]);
2022-12-08 06:26:28 -08:00
palette[index * 3] = color->r >> 2;
palette[index * 3 + 1] = color->g >> 2;
palette[index * 3 + 2] = color->b >> 2;
2022-05-19 01:51:26 -07:00
}
}
2022-12-08 06:26:28 -08:00
return palette;
2022-05-19 01:51:26 -07:00
}
// 0x4CB850
void _GNW95_ShowRect(unsigned char* src, int srcPitch, int a3, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY)
{
2022-05-19 04:01:17 -07:00
blitBufferToBuffer(src + srcPitch * srcY + srcX, srcWidth, srcHeight, srcPitch, (unsigned char*)gSdlSurface->pixels + gSdlSurface->pitch * destY + destX, gSdlSurface->pitch);
SDL_Rect srcRect;
srcRect.x = destX;
srcRect.y = destY;
srcRect.w = srcWidth;
srcRect.h = srcHeight;
SDL_Rect destRect;
destRect.x = destX;
destRect.y = destY;
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, &srcRect, gSdlTextureSurface, &destRect);
2022-05-19 01:51:26 -07:00
}
// Clears drawing surface.
//
// 0x4CBBC8
void _GNW95_zero_vid_mem()
{
if (!gProgramIsActive) {
return;
}
2022-05-24 13:19:36 -07:00
unsigned char* surface = (unsigned char*)gSdlSurface->pixels;
2022-07-07 00:52:54 -07:00
for (int y = 0; y < gSdlSurface->h; y++) {
2022-05-24 13:19:36 -07:00
memset(surface, 0, gSdlSurface->w);
surface += gSdlSurface->pitch;
2022-05-19 01:51:26 -07:00
}
2022-07-12 00:10:23 -07:00
SDL_BlitSurface(gSdlSurface, NULL, gSdlTextureSurface, NULL);
2022-05-19 01:51:26 -07:00
}
2022-05-20 15:50:14 -07:00
int screenGetWidth()
{
// TODO: Make it on par with _xres;
2022-05-20 15:56:07 -07:00
return rectGetWidth(&_scr_size);
2022-05-20 15:50:14 -07:00
}
int screenGetHeight()
{
// TODO: Make it on par with _yres.
2022-05-20 15:56:07 -07:00
return rectGetHeight(&_scr_size);
2022-05-20 15:50:14 -07:00
}
2022-05-20 16:29:59 -07:00
int screenGetVisibleHeight()
{
int windowBottomMargin = 0;
if (!gInterfaceBarMode) {
windowBottomMargin = INTERFACE_BAR_HEIGHT;
}
return screenGetHeight() - windowBottomMargin;
}
2022-10-04 03:15:54 -07:00
static bool createRenderer(int width, int height)
{
gSdlRenderer = SDL_CreateRenderer(gSdlWindow, -1, 0);
if (gSdlRenderer == NULL) {
return false;
}
if (SDL_RenderSetLogicalSize(gSdlRenderer, width, height) != 0) {
return false;
}
gSdlTexture = SDL_CreateTexture(gSdlRenderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_STREAMING, width, height);
if (gSdlTexture == NULL) {
return false;
}
Uint32 format;
if (SDL_QueryTexture(gSdlTexture, &format, NULL, NULL, NULL) != 0) {
return false;
}
gSdlTextureSurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, SDL_BITSPERPIXEL(format), format);
if (gSdlTextureSurface == NULL) {
return false;
}
return true;
}
static void destroyRenderer()
{
if (gSdlTextureSurface != NULL) {
SDL_FreeSurface(gSdlTextureSurface);
gSdlTextureSurface = NULL;
}
if (gSdlTexture != NULL) {
SDL_DestroyTexture(gSdlTexture);
gSdlTexture = NULL;
}
if (gSdlRenderer != NULL) {
SDL_DestroyRenderer(gSdlRenderer);
gSdlRenderer = NULL;
}
}
2022-10-04 23:23:27 -07:00
void handleWindowSizeChanged()
{
destroyRenderer();
createRenderer(screenGetWidth(), screenGetHeight());
}
2022-10-06 09:10:01 -07:00
void renderPresent()
{
SDL_UpdateTexture(gSdlTexture, NULL, gSdlTextureSurface->pixels, gSdlTextureSurface->pitch);
SDL_RenderClear(gSdlRenderer);
SDL_RenderCopy(gSdlRenderer, gSdlTexture, NULL, NULL);
SDL_RenderPresent(gSdlRenderer);
}
2022-09-23 05:43:44 -07:00
} // namespace fallout