Added hardware-accelerated rendering backend

Still need to add the code for surviving render target losses
This commit is contained in:
Clownacy 2019-07-15 16:47:10 +01:00
parent 21cf78b86d
commit 15bfd00d25
5 changed files with 288 additions and 36 deletions

View file

@ -11,6 +11,7 @@ option(JAPANESE "Enable the Japanese-language build" OFF)
option(FIX_BUGS "Fix certain bugs (see src/Bug Fixes.txt)" OFF) option(FIX_BUGS "Fix certain bugs (see src/Bug Fixes.txt)" OFF)
option(NONPORTABLE "Enable bits of code that aren't portable, but are what the original game used" OFF) option(NONPORTABLE "Enable bits of code that aren't portable, but are what the original game used" OFF)
option(FORCE_LOCAL_LIBS "Compile the built-in versions of SDL2, FreeType, and FLTK instead of using the system-provided ones" OFF) option(FORCE_LOCAL_LIBS "Compile the built-in versions of SDL2, FreeType, and FLTK instead of using the system-provided ones" OFF)
set(RENDERER "Texture" CACHE STRING "Which renderer the game should use: 'Texture' for SDL2's hardware-accelerated Texture API, and 'Software' for a handwritten software renderer")
project(CSE2 LANGUAGES C CXX) project(CSE2 LANGUAGES C CXX)
@ -155,7 +156,6 @@ add_executable(CSE2
src/ValueView.cpp src/ValueView.cpp
src/ValueView.h src/ValueView.h
src/WindowsWrapper.h src/WindowsWrapper.h
src/Backends/SDLSoftware.cpp
src/Backends/Rendering.h src/Backends/Rendering.h
) )
@ -246,6 +246,12 @@ if(NONPORTABLE)
target_compile_definitions(CSE2 PRIVATE NONPORTABLE) target_compile_definitions(CSE2 PRIVATE NONPORTABLE)
endif() endif()
if(RENDERER MATCHES "Texture")
target_sources(CSE2 PRIVATE "src/Backends/SDLTexture.cpp")
elseif(RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/SDLSoftware.cpp")
endif()
# Make some tweaks if we're targetting Windows # Make some tweaks if we're targetting Windows
if(WIN32) if(WIN32)
target_sources(CSE2 PRIVATE "${ASSETS_DIRECTORY}/resources/ICON/ICON.rc") target_sources(CSE2 PRIVATE "${ASSETS_DIRECTORY}/resources/ICON/ICON.rc")

View file

@ -14,8 +14,8 @@ void Backend_DrawScreen(void);
Backend_Surface* Backend_CreateSurface(unsigned int width, unsigned int height); Backend_Surface* Backend_CreateSurface(unsigned int width, unsigned int height);
void Backend_FreeSurface(Backend_Surface *surface); void Backend_FreeSurface(Backend_Surface *surface);
void Backend_LoadPixels(Backend_Surface *surface, const unsigned char *pixels, unsigned int width, unsigned int height, unsigned int pitch); void Backend_LoadPixels(Backend_Surface *surface, const unsigned char *pixels, unsigned int width, unsigned int height, unsigned int pitch);
void Backend_Blit(const Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key); void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key);
void Backend_BlitToScreen(const Backend_Surface *source_surface, const RECT *rect, long x, long y, BOOL colour_key); void Backend_BlitToScreen(Backend_Surface *source_surface, const RECT *rect, long x, long y, BOOL colour_key);
void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue); void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue);
void Backend_ColourFillToScreen(const RECT *rect, unsigned char red, unsigned char green, unsigned char blue); void Backend_ColourFillToScreen(const RECT *rect, unsigned char red, unsigned char green, unsigned char blue);
void Backend_ScreenToSurface(Backend_Surface *surface, const RECT *rect); void Backend_ScreenToSurface(Backend_Surface *surface, const RECT *rect);

View file

@ -78,6 +78,7 @@ Backend_Surface* Backend_CreateSurface(unsigned int width, unsigned int height)
void Backend_FreeSurface(Backend_Surface *surface) void Backend_FreeSurface(Backend_Surface *surface)
{ {
free(surface->pixels); free(surface->pixels);
free(surface);
} }
void Backend_LoadPixels(Backend_Surface *surface, const unsigned char *pixels, unsigned int width, unsigned int height, unsigned int pitch) void Backend_LoadPixels(Backend_Surface *surface, const unsigned char *pixels, unsigned int width, unsigned int height, unsigned int pitch)
@ -91,7 +92,7 @@ void Backend_LoadPixels(Backend_Surface *surface, const unsigned char *pixels, u
} }
} }
void Backend_Blit(const Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key) void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key)
{ {
RECT rect_clamped; RECT rect_clamped;
@ -163,7 +164,7 @@ void Backend_Blit(const Backend_Surface *source_surface, const RECT *rect, Backe
} }
} }
void Backend_BlitToScreen(const Backend_Surface *source_surface, const RECT *rect, long x, long y, BOOL colour_key) void Backend_BlitToScreen(Backend_Surface *source_surface, const RECT *rect, long x, long y, BOOL colour_key)
{ {
Backend_Blit(source_surface, rect, &framebuffer, x, y, colour_key); Backend_Blit(source_surface, rect, &framebuffer, x, y, colour_key);
} }

276
src/Backends/SDLTexture.cpp Normal file
View file

@ -0,0 +1,276 @@
#include "Rendering.h"
#include <stddef.h>
#include <stdlib.h>
#include "SDL.h"
#include "../WindowsWrapper.h"
#include "../Font.h"
struct Backend_Surface
{
BOOL needs_syncing;
SDL_Surface *sdl_surface;
SDL_Texture *texture;
};
static SDL_Renderer *renderer;
static SDL_Texture *screen_texture;
static void FlushSurface(Backend_Surface *surface)
{
unsigned char *buffer = (unsigned char*)malloc(surface->sdl_surface->w * surface->sdl_surface->h * 4);
unsigned char *buffer_pointer = buffer;
// Convert the SDL_Surface's colour-keyed pixels to RGBA32
for (int h = 0; h < surface->sdl_surface->h; ++h)
{
unsigned char *src_pixel = (unsigned char*)surface->sdl_surface->pixels + (h * surface->sdl_surface->pitch);
for (int w = 0; w < surface->sdl_surface->w; ++w)
{
*buffer_pointer++ = src_pixel[0];
*buffer_pointer++ = src_pixel[1];
*buffer_pointer++ = src_pixel[2];
if (src_pixel[0] != 0 || src_pixel[1] != 0 || src_pixel[2] != 0) // Assumes the colour key will always be #00000000 (black)
*buffer_pointer++ = 0xFF;
else
*buffer_pointer++ = 0;
src_pixel += 3;
}
}
SDL_UpdateTexture(surface->texture, NULL, buffer, surface->sdl_surface->w * 4);
free(buffer);
}
static void RectToSDLRect(const RECT *rect, SDL_Rect *sdl_rect)
{
sdl_rect->x = (int)rect->left;
sdl_rect->y = (int)rect->top;
sdl_rect->w = (int)(rect->right - rect->left);
sdl_rect->h = (int)(rect->bottom - rect->top);
if (sdl_rect->w < 0)
sdl_rect->w = 0;
if (sdl_rect->h < 0)
sdl_rect->h = 0;
}
BOOL Backend_Init(SDL_Window *window)
{
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
if (renderer == NULL)
return FALSE;
int width, height;
SDL_GetRendererOutputSize(renderer, &width, &height);
screen_texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, width, height);
SDL_SetRenderTarget(renderer, screen_texture);
return TRUE;
}
void Backend_Deinit(void)
{
SDL_DestroyRenderer(renderer);
}
void Backend_DrawScreen(void)
{
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, screen_texture, NULL, NULL);
SDL_SetRenderTarget(renderer, screen_texture);
SDL_RenderPresent(renderer);
}
Backend_Surface* Backend_CreateSurface(unsigned int width, unsigned int height)
{
Backend_Surface *surface = (Backend_Surface*)malloc(sizeof(Backend_Surface));
if (surface == NULL)
return NULL;
surface->sdl_surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, SDL_PIXELFORMAT_RGB24);
if (surface->sdl_surface == NULL)
{
free(surface);
return NULL;
}
surface->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, width, height);
if (surface->texture == NULL)
{
SDL_FreeSurface(surface->sdl_surface);
free(surface);
return NULL;
}
SDL_SetColorKey(surface->sdl_surface, SDL_TRUE, SDL_MapRGB(surface->sdl_surface->format, 0, 0, 0));
surface->needs_syncing = FALSE;
return surface;
}
void Backend_FreeSurface(Backend_Surface *surface)
{
SDL_FreeSurface(surface->sdl_surface);
free(surface);
}
void Backend_LoadPixels(Backend_Surface *surface, const unsigned char *pixels, unsigned int width, unsigned int height, unsigned int pitch)
{
for (unsigned int h = 0; h < height; ++h)
{
const unsigned char *src_row = &pixels[h * pitch];
unsigned char *dst_row = (unsigned char*)surface->sdl_surface->pixels + h * surface->sdl_surface->pitch;
memcpy(dst_row, src_row, width * 3);
}
surface->needs_syncing = TRUE;
}
void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key)
{
if (source_surface->needs_syncing)
{
FlushSurface(source_surface);
source_surface->needs_syncing = FALSE;
}
SDL_Rect source_rect;
RectToSDLRect(rect, &source_rect);
SDL_Rect destination_rect = {x, y, source_rect.w, source_rect.h};
// Blit the surface
SDL_SetSurfaceBlendMode(source_surface->sdl_surface, colour_key ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
SDL_BlitSurface(source_surface->sdl_surface, &source_rect, destination_surface->sdl_surface, &destination_rect);
// Now blit the texture
SDL_SetTextureBlendMode(source_surface->texture, colour_key ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
SDL_SetRenderTarget(renderer, destination_surface->texture);
SDL_RenderCopy(renderer, source_surface->texture, &source_rect, &destination_rect);
SDL_SetRenderTarget(renderer, screen_texture);
}
void Backend_BlitToScreen(Backend_Surface *source_surface, const RECT *rect, long x, long y, BOOL colour_key)
{
if (source_surface->needs_syncing)
{
FlushSurface(source_surface);
source_surface->needs_syncing = FALSE;
}
SDL_Rect source_rect;
RectToSDLRect(rect, &source_rect);
SDL_Rect destination_rect = {x, y, source_rect.w, source_rect.h};
// Blit the texture
SDL_SetTextureBlendMode(source_surface->texture, colour_key ? SDL_BLENDMODE_BLEND : SDL_BLENDMODE_NONE);
SDL_RenderCopy(renderer, source_surface->texture, &source_rect, &destination_rect);
}
void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue)
{
SDL_Rect sdl_rect;
RectToSDLRect(rect, &sdl_rect);
// Blit the surface
SDL_FillRect(surface->sdl_surface, &sdl_rect, SDL_MapRGB(surface->sdl_surface->format, red, green, blue));
// Check colour-key
if (red == 0 && green == 0 && blue == 0)
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
else
SDL_SetRenderDrawColor(renderer, red, green, blue, 0xFF);
// Draw colour
SDL_SetRenderTarget(renderer, surface->texture);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
SDL_RenderFillRect(renderer, &sdl_rect);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderTarget(renderer, screen_texture);
}
void Backend_ColourFillToScreen(const RECT *rect, unsigned char red, unsigned char green, unsigned char blue)
{
SDL_Rect sdl_rect;
RectToSDLRect(rect, &sdl_rect);
// Draw colour
SDL_SetRenderDrawColor(renderer, red, green, blue, 0xFF);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
SDL_RenderFillRect(renderer, &sdl_rect);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
}
void Backend_ScreenToSurface(Backend_Surface *surface, const RECT *rect)
{
SDL_Rect sdl_rect;
RectToSDLRect(rect, &sdl_rect);
//
// Copy screen to surface
//
// Get renderer size
int w, h;
SDL_GetRendererOutputSize(renderer, &w, &h);
// Get surface of what's currently rendered on screen
SDL_Surface *screen_surface = SDL_CreateRGBSurfaceWithFormat(0, w, h, 0, SDL_PIXELFORMAT_RGB24);
SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_RGB24, screen_surface->pixels, screen_surface->pitch);
// Copy to specified surface
SDL_BlitSurface(screen_surface, &sdl_rect, surface->sdl_surface, &sdl_rect);
// Cleanup
SDL_FreeSurface(screen_surface);
//
// Copy screen to texture
//
SDL_SetRenderTarget(renderer, surface->texture);
SDL_RenderCopy(renderer, screen_texture, &sdl_rect, &sdl_rect);
SDL_SetRenderTarget(renderer, screen_texture);
}
void Backend_DrawText(Backend_Surface *surface, FontObject *font, int x, int y, const char *text, unsigned long colour)
{
DrawText(font, (unsigned char*)surface->sdl_surface->pixels, surface->sdl_surface->pitch, surface->sdl_surface->w, surface->sdl_surface->h, x, y, colour, text, strlen(text));
surface->needs_syncing = TRUE;
}
void Backend_DrawTextToScreen(FontObject *font, int x, int y, const char *text, unsigned long colour)
{
// Painfully slow. Really need to add hardware-accelerated font rendering.
int surface_width, surface_height;
SDL_GetRendererOutputSize(renderer, &surface_width, &surface_height);
SDL_Surface *screen_surface = SDL_CreateRGBSurfaceWithFormat(0, surface_width, surface_height, 0, SDL_PIXELFORMAT_RGB24);
SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_RGB24, screen_surface->pixels, screen_surface->pitch);
DrawText(font, (unsigned char*)screen_surface->pixels, screen_surface->pitch, screen_surface->w, screen_surface->h, x, y, colour, text, strlen(text));
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, screen_surface);
SDL_FreeSurface(screen_surface);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_DestroyTexture(texture);
}

View file

@ -343,27 +343,6 @@ BOOL ReloadBitmap_Resource(const char *res, Surface_Ids surf_no)
{ {
return LoadBitmap_Resource(res, surf_no, FALSE); return LoadBitmap_Resource(res, surf_no, FALSE);
} }
/*
static SDL_Rect RectToSDLRect(RECT *rect)
{
SDL_Rect SDLRect = {(int)rect->left, (int)rect->top, (int)(rect->right - rect->left), (int)(rect->bottom - rect->top)};
if (SDLRect.w < 0)
SDLRect.w = 0;
if (SDLRect.h < 0)
SDLRect.h = 0;
return SDLRect;
}
static SDL_Rect RectToSDLRectScaled(RECT *rect)
{
SDL_Rect SDLRect = RectToSDLRect(rect);
SDLRect.x *= magnification;
SDLRect.y *= magnification;
SDLRect.w *= magnification;
SDLRect.h *= magnification;
return SDLRect;
}
*/
static void ScaleRect(const RECT *source_rect, RECT *destination_rect) static void ScaleRect(const RECT *source_rect, RECT *destination_rect)
{ {
@ -379,17 +358,10 @@ void BackupSurface(Surface_Ids surf_no, const RECT *rect)
ScaleRect(rect, &frameRect); ScaleRect(rect, &frameRect);
Backend_ScreenToSurface(surf[surf_no].backend, &frameRect); Backend_ScreenToSurface(surf[surf_no].backend, &frameRect);
//surf[surf_no].needs_updating = TRUE;
} }
static void DrawBitmap(const RECT *rcView, int x, int y, const RECT *rect, Surface_Ids surf_no, BOOL transparent) static void DrawBitmap(const RECT *rcView, int x, int y, const RECT *rect, Surface_Ids surf_no, BOOL transparent)
{ {
/* if (surf[surf_no].needs_updating)
{
FlushSurface(surf_no);
surf[surf_no].needs_updating = FALSE;
}
*/
RECT frameRect; RECT frameRect;
frameRect.left = rect->left; frameRect.left = rect->left;
@ -445,7 +417,6 @@ void Surface2Surface(int x, int y, const RECT *rect, int to, int from)
ScaleRect(rect, &frameRect); ScaleRect(rect, &frameRect);
Backend_Blit(surf[from].backend, &frameRect, surf[to].backend, x * magnification, y * magnification, TRUE); Backend_Blit(surf[from].backend, &frameRect, surf[to].backend, x * magnification, y * magnification, TRUE);
//surf[to].needs_updating = TRUE;
} }
unsigned long GetCortBoxColor(unsigned long col) unsigned long GetCortBoxColor(unsigned long col)
@ -481,7 +452,6 @@ void CortBox2(const RECT *rect, unsigned long col, Surface_Ids surf_no)
const unsigned char col_blue = (unsigned char)((col >> 16) & 0xFF); const unsigned char col_blue = (unsigned char)((col >> 16) & 0xFF);
Backend_ColourFill(surf[surf_no].backend, &destRect, col_red, col_green, col_blue); Backend_ColourFill(surf[surf_no].backend, &destRect, col_red, col_green, col_blue);
//surf[surf_no].needs_updating = TRUE;
} }
#ifdef WINDOWS #ifdef WINDOWS
@ -591,7 +561,6 @@ void PutText(int x, int y, const char *text, unsigned long color)
void PutText2(int x, int y, const char *text, unsigned long color, Surface_Ids surf_no) void PutText2(int x, int y, const char *text, unsigned long color, Surface_Ids surf_no)
{ {
Backend_DrawText(surf[surf_no].backend, gFont, x * magnification, y * magnification, text, color); Backend_DrawText(surf[surf_no].backend, gFont, x * magnification, y * magnification, text, color);
//surf[surf_no].needs_updating = TRUE;
} }
void EndTextObject() void EndTextObject()