ref: 21cf78b86d1025081e59d3edffc59a8ef5b18148
parent: 3ef9b67b1d9ee27137d51494ee63460e89ec45fb
author: Clownacy <Clownacy@users.noreply.github.com>
date: Mon Jul 15 09:41:19 EDT 2019
Split Draw.cpp into common code and backend code Should be easy to add the new hardware renderer now
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -155,6 +155,8 @@
src/ValueView.cpp
src/ValueView.h
src/WindowsWrapper.h
+ src/Backends/SDLSoftware.cpp
+ src/Backends/Rendering.h
)
set(RESOURCES
--- /dev/null
+++ b/src/Backends/Rendering.h
@@ -1,0 +1,23 @@
+#pragma once
+
+#include "SDL.h"
+
+#include "../WindowsWrapper.h"
+
+#include "../Font.h"
+
+struct Backend_Surface;
+
+BOOL Backend_Init(SDL_Window *window);
+void Backend_Deinit(void);
+void Backend_DrawScreen(void);
+Backend_Surface* Backend_CreateSurface(unsigned int width, unsigned int height);
+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_Blit(const 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_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_ScreenToSurface(Backend_Surface *surface, const RECT *rect);
+void Backend_DrawText(Backend_Surface *surface, FontObject *font, int x, int y, const char *text, unsigned long colour);
+void Backend_DrawTextToScreen(FontObject *font, int x, int y, const char *text, unsigned long colour);
--- /dev/null
+++ b/src/Backends/SDLSoftware.cpp
@@ -1,0 +1,239 @@
+#include "Rendering.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "SDL.h"
+
+#include "../WindowsWrapper.h"
+
+#include "../Font.h"
+
+struct Backend_Surface
+{
+ unsigned char *pixels;
+ unsigned int width;
+ unsigned int height;
+ unsigned int pitch;
+};
+
+static SDL_Window *window;
+static SDL_Surface *window_surface;
+static SDL_Surface *screen_surface;
+
+static Backend_Surface framebuffer;
+
+BOOL Backend_Init(SDL_Window *p_window)
+{
+ window = p_window;
+
+ window_surface = SDL_GetWindowSurface(window);
+
+ screen_surface = SDL_CreateRGBSurfaceWithFormat(0, window_surface->w, window_surface->h, 0, SDL_PIXELFORMAT_RGB24);
+
+ if (screen_surface == NULL)
+ return FALSE;
+
+ framebuffer.pixels = (unsigned char*)screen_surface->pixels;
+ framebuffer.width = screen_surface->w;
+ framebuffer.height = screen_surface->h;
+ framebuffer.pitch = screen_surface->pitch;
+
+ return TRUE;
+}
+
+void Backend_Deinit(void)
+{
+ SDL_FreeSurface(screen_surface);
+}
+
+void Backend_DrawScreen(void)
+{
+ SDL_BlitSurface(screen_surface, NULL, window_surface, NULL);
+ SDL_UpdateWindowSurface(window);
+}
+
+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->pixels = (unsigned char*)malloc(width * height * 3);
+
+ if (surface->pixels == NULL)
+ {
+ free(surface);
+ return NULL;
+ }
+
+ surface->width = width;
+ surface->height = height;
+ surface->pitch = width * 3;
+
+ return surface;
+}
+
+void Backend_FreeSurface(Backend_Surface *surface)
+{
+ free(surface->pixels);
+}
+
+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 = &surface->pixels[h * surface->pitch];
+
+ memcpy(dst_row, src_row, width * 3);
+ }
+}
+
+void Backend_Blit(const Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key)
+{
+ RECT rect_clamped;
+
+ rect_clamped.left = rect->left;
+ rect_clamped.top = rect->top;
+ rect_clamped.right = rect->right;
+ rect_clamped.bottom = rect->bottom;
+
+ // Clamp the rect and coordinates so we don't write outside the pixel buffer
+ long overflow;
+
+ overflow = 0 - x;
+ if (overflow > 0)
+ {
+ rect_clamped.left += overflow;
+ x += overflow;
+ }
+
+ overflow = 0 - y;
+ if (overflow > 0)
+ {
+ rect_clamped.top += overflow;
+ y += overflow;
+ }
+
+ overflow = (x + (rect_clamped.right - rect_clamped.left)) - destination_surface->width;
+ if (overflow > 0)
+ {
+ rect_clamped.right -= overflow;
+ }
+
+ overflow = (y + (rect_clamped.bottom - rect_clamped.top)) - destination_surface->height;
+ if (overflow > 0)
+ {
+ rect_clamped.bottom -= overflow;
+ }
+
+ // Do the actual blitting
+ if (colour_key)
+ {
+ for (long j = 0; j < rect_clamped.bottom - rect_clamped.top; ++j)
+ {
+ unsigned char *source_pointer = &source_surface->pixels[((rect_clamped.top + j) * source_surface->pitch) + (rect_clamped.left * 3)];
+ unsigned char *destination_pointer = &destination_surface->pixels[((y + j) * destination_surface->pitch) + (x * 3)];
+
+ for (long i = 0; i < rect_clamped.right - rect_clamped.left; ++i)
+ {
+ if (source_pointer[0] != 0 || source_pointer[1] != 0 || source_pointer[2] != 0) // Assumes the colour key will always be #00000000 (black)
+ {
+ destination_pointer[0] = source_pointer[0];
+ destination_pointer[1] = source_pointer[1];
+ destination_pointer[2] = source_pointer[2];
+ }
+
+ source_pointer += 3;
+ destination_pointer += 3;
+ }
+ }
+ }
+ else
+ {
+ for (long j = 0; j < rect_clamped.bottom - rect_clamped.top; ++j)
+ {
+ unsigned char *source_pointer = &source_surface->pixels[((rect_clamped.top + j) * source_surface->pitch) + (rect_clamped.left * 3)];
+ unsigned char *destination_pointer = &destination_surface->pixels[((y + j) * destination_surface->pitch) + (x * 3)];
+
+ memcpy(destination_pointer, source_pointer, (rect_clamped.right - rect_clamped.left) * 3);
+ }
+ }
+}
+
+void Backend_BlitToScreen(const Backend_Surface *source_surface, const RECT *rect, long x, long y, BOOL colour_key)
+{
+ Backend_Blit(source_surface, rect, &framebuffer, x, y, colour_key);
+}
+
+void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue)
+{
+ RECT rect_clamped;
+
+ rect_clamped.left = rect->left;
+ rect_clamped.top = rect->top;
+ rect_clamped.right = rect->right;
+ rect_clamped.bottom = rect->bottom;
+
+ // Clamp the rect so it doesn't write outside the pixel buffer
+ long overflow;
+
+ overflow = 0 - rect_clamped.left;
+ if (overflow > 0)
+ {
+ rect_clamped.left += overflow;
+ }
+
+ overflow = 0 - rect_clamped.top;
+ if (overflow > 0)
+ {
+ rect_clamped.top += overflow;
+ }
+
+ overflow = rect_clamped.right - surface->width;
+ if (overflow > 0)
+ {
+ rect_clamped.right -= overflow;
+ }
+
+ overflow = rect_clamped.bottom - surface->height;
+ if (overflow > 0)
+ {
+ rect_clamped.bottom -= overflow;
+ }
+
+ for (long j = 0; j < rect_clamped.bottom - rect_clamped.top; ++j)
+ {
+ unsigned char *source_pointer = &surface->pixels[((rect_clamped.top + j) * surface->pitch) + (rect_clamped.left * 3)];
+
+ for (long i = 0; i < rect_clamped.right - rect_clamped.left; ++i)
+ {
+ *source_pointer++ = red;
+ *source_pointer++ = green;
+ *source_pointer++ = blue;
+ }
+ }
+}
+
+void Backend_ColourFillToScreen(const RECT *rect, unsigned char red, unsigned char green, unsigned char blue)
+{
+ Backend_ColourFill(&framebuffer, rect, red, green, blue);
+}
+
+void Backend_ScreenToSurface(Backend_Surface *surface, const RECT *rect)
+{
+ Backend_Blit(&framebuffer, rect, surface, rect->left, rect->top, FALSE);
+}
+
+void Backend_DrawText(Backend_Surface *surface, FontObject *font, int x, int y, const char *text, unsigned long colour)
+{
+ DrawText(font, surface->pixels, surface->pitch, surface->width, surface->height, x, y, colour, text, strlen(text));
+ //surf[surf_no].needs_updating = TRUE;
+}
+
+void Backend_DrawTextToScreen(FontObject *font, int x, int y, const char *text, unsigned long colour)
+{
+ Backend_DrawText(&framebuffer, font, x, y, text, colour);
+}
--- a/src/Draw.cpp
+++ b/src/Draw.cpp
@@ -14,21 +14,17 @@
#include "Font.h"
#include "Resource.h"
#include "Tags.h"
+#include "Backends/Rendering.h"
struct SURFACE
{
BOOL in_use;
- unsigned char *pixels;
- unsigned int width;
- unsigned int height;
- unsigned int pitch;
+ Backend_Surface *backend;
};
SDL_Window *gWindow;
-static SDL_Surface *gWindowSurface;
-static SDL_Surface *gSurface;
-static SURFACE framebuffer;
+static SDL_PixelFormat *rgb24_pixel_format; // Needed because SDL2 is stupid
RECT grcGame = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
RECT grcFull = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
@@ -68,8 +64,7 @@
SDL_Delay(1);
}
- SDL_BlitSurface(gSurface, NULL, gWindowSurface, NULL);
- SDL_UpdateWindowSurface(gWindow);
+ Backend_DrawScreen();
return TRUE;
}
@@ -98,18 +93,10 @@
}
// Create renderer
- gWindowSurface = SDL_GetWindowSurface(gWindow);
-
- gSurface = SDL_CreateRGBSurfaceWithFormat(0, WINDOW_WIDTH * magnification, WINDOW_HEIGHT * magnification, 0, SDL_PIXELFORMAT_RGB24);
-
- if (gSurface == NULL)
+ if (!Backend_Init(gWindow))
return FALSE;
- framebuffer.in_use = TRUE;
- framebuffer.pixels = (unsigned char*)gSurface->pixels;
- framebuffer.width = WINDOW_WIDTH * magnification;
- framebuffer.height = WINDOW_HEIGHT * magnification;
- framebuffer.pitch = gSurface->pitch;
+ rgb24_pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_RGB24);
return TRUE;
}
@@ -116,13 +103,13 @@
void EndDirectDraw()
{
+ SDL_FreeFormat(rgb24_pixel_format);
+
// Release all surfaces
for (int i = 0; i < SURFACE_ID_MAX; i++)
ReleaseSurface(i);
- framebuffer.in_use = FALSE;
-
- SDL_FreeSurface(gSurface);
+ Backend_Deinit();
}
static BOOL IsEnableBitmap(SDL_RWops *fp)
@@ -143,7 +130,7 @@
// Release the surface we want to release
if (surf[s].in_use)
{
- free(surf[s].pixels);
+ Backend_FreeSurface(surf[s].backend);
surf[s].in_use = FALSE;
}
}
@@ -171,14 +158,11 @@
else
{
// Create surface
- surf[surf_no].pixels = (unsigned char*)malloc((bxsize * magnification) * (bysize * magnification) * 3);
- surf[surf_no].width = bxsize * magnification;
- surf[surf_no].height = bysize * magnification;
- surf[surf_no].pitch = surf[surf_no].width * 3;
+ surf[surf_no].backend = Backend_CreateSurface(bxsize * magnification, bysize * magnification);
- if (surf[surf_no].pixels == NULL)
+ if (surf[surf_no].backend == NULL)
{
- printf("Failed to allocate surface pixel buffer %d\n", surf_no);
+ printf("Failed to create backend surface %d\n", surf_no);
}
else
{
@@ -218,7 +202,7 @@
if (create_surface == FALSE || MakeSurface_Generic(surface->w, surface->h, surf_no, FALSE))
{
- SDL_Surface *converted_surface = SDL_ConvertSurface(surface, gSurface->format, 0);
+ SDL_Surface *converted_surface = SDL_ConvertSurface(surface, rgb24_pixel_format, 0);
if (converted_surface == NULL)
{
@@ -230,21 +214,17 @@
if (magnification == 1)
{
// Just copy the pixels the way they are
- for (int h = 0; h < converted_surface->h; ++h)
- {
- const unsigned char *src_row = (unsigned char*)converted_surface->pixels + h * converted_surface->pitch;
- unsigned char *dst_row = surf[surf_no].pixels + h * surf[surf_no].pitch;
-
- memcpy(dst_row, src_row, converted_surface->w * 3);
- }
+ Backend_LoadPixels(surf[surf_no].backend, (unsigned char*)converted_surface->pixels, converted_surface->w, converted_surface->h, converted_surface->pitch);
}
else
{
// Upscale the bitmap to the game's internal resolution
+ unsigned char *pixels = (unsigned char*)malloc((converted_surface->w * magnification) * (converted_surface->h * magnification) * 3);
+
for (int h = 0; h < converted_surface->h; ++h)
{
const unsigned char *src_row = (unsigned char*)converted_surface->pixels + h * converted_surface->pitch;
- unsigned char *dst_row = surf[surf_no].pixels + h * surf[surf_no].pitch * magnification;
+ unsigned char *dst_row = pixels + h * (converted_surface->w * magnification * 3) * magnification;
const unsigned char *src_ptr = src_row;
unsigned char *dst_ptr = dst_row;
@@ -262,8 +242,11 @@
}
for (int i = 1; i < magnification; ++i)
- memcpy(dst_row + i * surf[surf_no].pitch, dst_row, converted_surface->w * magnification * 3);
+ memcpy(dst_row + i * converted_surface->w * magnification * 3, dst_row, converted_surface->w * magnification * 3);
}
+
+ Backend_LoadPixels(surf[surf_no].backend, pixels, converted_surface->w * magnification, converted_surface->h * magnification, converted_surface->w * magnification * 3);
+ free(pixels);
}
SDL_FreeSurface(converted_surface);
@@ -390,133 +373,12 @@
destination_rect->bottom = source_rect->bottom * magnification;
}
-static void Blit(const SURFACE *source_surface, const RECT *rect, SURFACE *destination_surface, long x, long y, BOOL colour_key)
-{
- RECT rect_clamped;
-
- rect_clamped.left = rect->left;
- rect_clamped.top = rect->top;
- rect_clamped.right = rect->right;
- rect_clamped.bottom = rect->bottom;
-
- // Clamp the rect and coordinates so we don't write outside the pixel buffer
- long overflow;
-
- overflow = 0 - x;
- if (overflow > 0)
- {
- rect_clamped.left += overflow;
- x += overflow;
- }
-
- overflow = 0 - y;
- if (overflow > 0)
- {
- rect_clamped.top += overflow;
- y += overflow;
- }
-
- overflow = (x + (rect_clamped.right - rect_clamped.left)) - destination_surface->width;
- if (overflow > 0)
- {
- rect_clamped.right -= overflow;
- }
-
- overflow = (y + (rect_clamped.bottom - rect_clamped.top)) - destination_surface->height;
- if (overflow > 0)
- {
- rect_clamped.bottom -= overflow;
- }
-
- // Do the actual blitting
- if (colour_key)
- {
- for (long j = 0; j < rect_clamped.bottom - rect_clamped.top; ++j)
- {
- unsigned char *source_pointer = &source_surface->pixels[((rect_clamped.top + j) * source_surface->pitch) + (rect_clamped.left * 3)];
- unsigned char *destination_pointer = &destination_surface->pixels[((y + j) * destination_surface->pitch) + (x * 3)];
-
- for (long i = 0; i < rect_clamped.right - rect_clamped.left; ++i)
- {
- if (source_pointer[0] != 0 || source_pointer[1] != 0 || source_pointer[2] != 0) // Assumes the colour key will always be #00000000 (black)
- {
- destination_pointer[0] = source_pointer[0];
- destination_pointer[1] = source_pointer[1];
- destination_pointer[2] = source_pointer[2];
- }
-
- source_pointer += 3;
- destination_pointer += 3;
- }
- }
- }
- else
- {
- for (long j = 0; j < rect_clamped.bottom - rect_clamped.top; ++j)
- {
- unsigned char *source_pointer = &source_surface->pixels[((rect_clamped.top + j) * source_surface->pitch) + (rect_clamped.left * 3)];
- unsigned char *destination_pointer = &destination_surface->pixels[((y + j) * destination_surface->pitch) + (x * 3)];
-
- memcpy(destination_pointer, source_pointer, (rect_clamped.right - rect_clamped.left) * 3);
- }
- }
-}
-
-static void ColourFill(SURFACE *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue)
-{
- RECT rect_clamped;
-
- rect_clamped.left = rect->left;
- rect_clamped.top = rect->top;
- rect_clamped.right = rect->right;
- rect_clamped.bottom = rect->bottom;
-
- // Clamp the rect so it doesn't write outside the pixel buffer
- long overflow;
-
- overflow = 0 - rect_clamped.left;
- if (overflow > 0)
- {
- rect_clamped.left += overflow;
- }
-
- overflow = 0 - rect_clamped.top;
- if (overflow > 0)
- {
- rect_clamped.top += overflow;
- }
-
- overflow = rect_clamped.right - surface->width;
- if (overflow > 0)
- {
- rect_clamped.right -= overflow;
- }
-
- overflow = rect_clamped.bottom - surface->height;
- if (overflow > 0)
- {
- rect_clamped.bottom -= overflow;
- }
-
- for (long j = 0; j < rect_clamped.bottom - rect_clamped.top; ++j)
- {
- unsigned char *source_pointer = &surface->pixels[((rect_clamped.top + j) * surface->pitch) + (rect_clamped.left * 3)];
-
- for (long i = 0; i < rect_clamped.right - rect_clamped.left; ++i)
- {
- *source_pointer++ = red;
- *source_pointer++ = green;
- *source_pointer++ = blue;
- }
- }
-}
-
void BackupSurface(Surface_Ids surf_no, const RECT *rect)
{
RECT frameRect;
ScaleRect(rect, &frameRect);
- Blit(&framebuffer, &frameRect, &surf[surf_no], frameRect.left, frameRect.top, FALSE);
+ Backend_ScreenToSurface(surf[surf_no].backend, &frameRect);
//surf[surf_no].needs_updating = TRUE;
}
@@ -563,7 +425,7 @@
frameRect.bottom *= magnification;
// Draw to screen
- Blit(&surf[surf_no], &frameRect, &framebuffer, x * magnification, y * magnification, transparent);
+ Backend_BlitToScreen(surf[surf_no].backend, &frameRect, x * magnification, y * magnification, transparent);
}
void PutBitmap3(const RECT *rcView, int x, int y, const RECT *rect, Surface_Ids surf_no) // Transparency
@@ -582,7 +444,7 @@
RECT frameRect;
ScaleRect(rect, &frameRect);
- Blit(&surf[from], &frameRect, &surf[to], x * magnification, y * magnification, TRUE);
+ Backend_Blit(surf[from].backend, &frameRect, surf[to].backend, x * magnification, y * magnification, TRUE);
//surf[to].needs_updating = TRUE;
}
@@ -604,7 +466,7 @@
const unsigned char col_green = (unsigned char)((col >> 8) & 0xFF);
const unsigned char col_blue = (unsigned char)((col >> 16) & 0xFF);
- ColourFill(&framebuffer, &destRect, col_red, col_green, col_blue);
+ Backend_ColourFillToScreen(&destRect, col_red, col_green, col_blue);
}
void CortBox2(const RECT *rect, unsigned long col, Surface_Ids surf_no)
@@ -618,7 +480,7 @@
const unsigned char col_green = (unsigned char)((col >> 8) & 0xFF);
const unsigned char col_blue = (unsigned char)((col >> 16) & 0xFF);
- ColourFill(&surf[surf_no], &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;
}
@@ -723,12 +585,12 @@
void PutText(int x, int y, const char *text, unsigned long color)
{
- DrawText(gFont, framebuffer.pixels, framebuffer.pitch, framebuffer.width, framebuffer.height, x * magnification, y * magnification, color, text, strlen(text));
+ Backend_DrawTextToScreen(gFont, x * magnification, y * magnification, text, color);
}
void PutText2(int x, int y, const char *text, unsigned long color, Surface_Ids surf_no)
{
- DrawText(gFont, surf[surf_no].pixels, surf[surf_no].pitch, surf[surf_no].width, surf[surf_no].height, x * magnification, y * magnification, color, text, strlen(text));
+ Backend_DrawText(surf[surf_no].backend, gFont, x * magnification, y * magnification, text, color);
//surf[surf_no].needs_updating = TRUE;
}