From fd855ee732a3a9d24264931272191e19447260a5 Mon Sep 17 00:00:00 2001 From: Clownacy Date: Mon, 2 Sep 2019 22:28:51 +0100 Subject: [PATCH] Restore the new renderers --- Makefile | 29 + src/ArmsItem.cpp | 2 +- src/Backends/Rendering.h | 32 ++ src/Backends/Rendering/OpenGL3.cpp | 797 ++++++++++++++++++++++++++ src/Backends/Rendering/SDLSurface.cpp | 239 ++++++++ src/Backends/Rendering/SDLTexture.cpp | 321 +++++++++++ src/Backends/Rendering/Software.cpp | 411 +++++++++++++ src/Draw.cpp | 525 ++++++----------- src/Draw.h | 10 +- src/Ending.cpp | 2 +- src/Escape.cpp | 2 +- src/Game.cpp | 10 +- src/Main.cpp | 21 +- src/MiniMap.cpp | 6 +- src/SelStage.cpp | 2 +- 15 files changed, 2029 insertions(+), 380 deletions(-) create mode 100644 src/Backends/Rendering.h create mode 100644 src/Backends/Rendering/OpenGL3.cpp create mode 100644 src/Backends/Rendering/SDLSurface.cpp create mode 100644 src/Backends/Rendering/SDLTexture.cpp create mode 100644 src/Backends/Rendering/Software.cpp diff --git a/Makefile b/Makefile index 67ee7b29..3fd8372d 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ WINDRES = windres BUILD_DIRECTORY = game ASSETS_DIRECTORY = assets +# Default options +RENDERER ?= Texture + ifeq ($(RELEASE), 1) CXXFLAGS = -O3 LDFLAGS = -s @@ -122,6 +125,32 @@ SOURCES = \ src/Triangle \ src/ValueView +ifeq ($(RENDERER), OpenGL3) + SOURCES += src/Backends/Rendering/OpenGL3 + CXXFLAGS += `pkg-config glew --cflags` + + ifeq ($(STATIC), 1) + CXXFLAGS += -DGLEW_STATIC + LIBS += `pkg-config glew --libs --static` + else + LIBS += `pkg-config glew --libs` + endif + +# ifeq ($(WINDOWS), 1) + LIBS += -lopengl32 +# else +# LIBS += -lGL +# endif +else ifeq ($(RENDERER), Texture) + SOURCES += src/Backends/Rendering/SDLTexture +else ifeq ($(RENDERER), Surface) + SOURCES += src/Backends/Rendering/SDLSurface +else ifeq ($(RENDERER), Software) + SOURCES += src/Backends/Rendering/Software +else + @echo Invalid RENDERER selected; this build will fail +endif + OBJECTS = $(addprefix obj/$(FILENAME)/, $(addsuffix .o, $(SOURCES))) DEPENDENCIES = $(addprefix obj/$(FILENAME)/, $(addsuffix .o.d, $(SOURCES))) diff --git a/src/ArmsItem.cpp b/src/ArmsItem.cpp index d4a8d710..18e7123e 100644 --- a/src/ArmsItem.cpp +++ b/src/ArmsItem.cpp @@ -436,7 +436,7 @@ int CampLoop() } } - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; } diff --git a/src/Backends/Rendering.h b/src/Backends/Rendering.h new file mode 100644 index 00000000..2764ce7e --- /dev/null +++ b/src/Backends/Rendering.h @@ -0,0 +1,32 @@ +#pragma once + +#include "SDL.h" + +#include "../WindowsWrapper.h" + +typedef enum FontPixelMode +{ + FONT_PIXEL_MODE_LCD, + FONT_PIXEL_MODE_GRAY, + FONT_PIXEL_MODE_MONO, +} FontPixelMode; + +typedef struct Backend_Surface Backend_Surface; +typedef struct Backend_Glyph Backend_Glyph; + +SDL_Window* Backend_CreateWindow(const char *title, int width, int height); +Backend_Surface* 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); +unsigned char* Backend_LockSurface(Backend_Surface *surface, unsigned int *pitch); +void Backend_UnlockSurface(Backend_Surface *surface); +void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, 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); +BOOL Backend_SupportsSubpixelGlyphs(void); +Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, FontPixelMode pixel_mode); +void Backend_UnloadGlyph(Backend_Glyph *glyph); +void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours); +void Backend_HandleDeviceLoss(void); +void Backend_HandleWindowResize(void); diff --git a/src/Backends/Rendering/OpenGL3.cpp b/src/Backends/Rendering/OpenGL3.cpp new file mode 100644 index 00000000..7f2220c3 --- /dev/null +++ b/src/Backends/Rendering/OpenGL3.cpp @@ -0,0 +1,797 @@ +#include "../Rendering.h" + +#include +#include +#include +#include + +#include +#include "SDL.h" + +#include "../../WindowsWrapper.h" + +typedef enum RenderMode +{ + MODE_BLANK, + MODE_DRAW_SURFACE, + MODE_DRAW_SURFACE_WITH_TRANSPARENCY, + MODE_COLOUR_FILL, + MODE_DRAW_GLYPH, + MODE_DRAW_GLYPH_LCD +} RenderMode; + +typedef struct Backend_Surface +{ + GLuint texture_id; + unsigned int width; + unsigned int height; + unsigned char *pixels; +} Backend_Surface; + +typedef struct Backend_Glyph +{ + GLuint texture_id; + unsigned int width; + unsigned int height; + unsigned char pixel_mode; +} Backend_Glyph; + +typedef struct Coordinate2D +{ + GLfloat x; + GLfloat y; +} Coordinate2D; + +typedef struct Vertex +{ + Coordinate2D vertex_coordinate; + Coordinate2D texture_coordinate; +} Vertex; + +typedef struct VertexBufferSlot +{ + Vertex vertices[2][3]; +} VertexBufferSlot; + +static SDL_Window *window; +static SDL_GLContext context; + +static GLuint program_texture; +static GLuint program_texture_colour_key; +static GLuint program_colour_fill; +static GLuint program_glyph_normal; +static GLuint program_glyph_subpixel_part1; +static GLuint program_glyph_subpixel_part2; + +static GLint program_colour_fill_uniform_colour; +static GLint program_glyph_normal_uniform_colour; +static GLint program_glyph_subpixel_part2_uniform_colour; + +static GLuint vertex_array_id; +static GLuint vertex_buffer_id; +static GLuint framebuffer_id; + +static VertexBufferSlot *vertex_buffer; +static unsigned long current_vertex_buffer_slot; + +static RenderMode last_render_mode; + +static Backend_Surface framebuffer; + +static const GLchar *vertex_shader_plain = " \ +#version 150 core\n \ +in vec2 input_vertex_coordinates; \ +void main() \ +{ \ + gl_Position = vec4(input_vertex_coordinates.x, input_vertex_coordinates.y, 0.0, 1.0); \ +} \ +"; + +static const GLchar *vertex_shader_texture = " \ +#version 150 core\n \ +in vec2 input_vertex_coordinates; \ +in vec2 input_texture_coordinates; \ +out vec2 texture_coordinates; \ +void main() \ +{ \ + texture_coordinates = input_texture_coordinates; \ + gl_Position = vec4(input_vertex_coordinates.x, input_vertex_coordinates.y, 0.0, 1.0); \ +} \ +"; + +static const GLchar *fragment_shader_texture = " \ +#version 150 core\n \ +uniform sampler2D tex; \ +in vec2 texture_coordinates; \ +out vec4 fragment; \ +void main() \ +{ \ + fragment = texture(tex, texture_coordinates); \ +} \ +"; + +static const GLchar *fragment_shader_texture_colour_key = " \ +#version 150 core\n \ +uniform sampler2D tex; \ +in vec2 texture_coordinates; \ +out vec4 fragment; \ +void main() \ +{ \ + vec4 colour = texture(tex, texture_coordinates); \ +\ + if (colour.xyz == vec3(0.0f, 0.0f, 0.0f)) \ + discard; \ +\ + fragment = colour; \ +} \ +"; + +static const GLchar *fragment_shader_colour_fill = " \ +#version 150 core\n \ +uniform vec4 colour; \ +out vec4 fragment; \ +void main() \ +{ \ + fragment = colour; \ +} \ +"; + +static const GLchar *fragment_shader_glyph_normal = " \ +#version 150 core\n \ +uniform sampler2D tex; \ +uniform vec4 colour; \ +in vec2 texture_coordinates; \ +out vec4 fragment; \ +void main() \ +{ \ + fragment = colour * vec4(1.0, 1.0, 1.0, texture(tex, texture_coordinates).r); \ +} \ +"; + +static const GLchar *fragment_shader_glyph_subpixel_part1 = " \ +#version 150 core\n \ +uniform sampler2D tex; \ +in vec2 texture_coordinates; \ +out vec4 fragment; \ +void main() \ +{ \ + fragment = texture(tex, texture_coordinates); \ +} \ +"; + +static const GLchar *fragment_shader_glyph_subpixel_part2 = " \ +#version 150 core\n \ +uniform sampler2D tex; \ +uniform vec4 colour; \ +in vec2 texture_coordinates; \ +out vec4 fragment; \ +void main() \ +{ \ + fragment = colour * texture(tex, texture_coordinates); \ +} \ +"; + +static void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void* userParam) +{ + (void)source; + (void)type; + (void)id; + (void)length; + (void)userParam; + + if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) + printf("OpenGL debug: %s\n", message); +} + +static GLuint CompileShader(const char *vertex_shader_source, const char *fragment_shader_source) +{ + GLint shader_status; + + GLuint program_id = glCreateProgram(); + + GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL); + glCompileShader(vertex_shader); + + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &shader_status); + if (shader_status != GL_TRUE) + return 0; + + glAttachShader(program_id, vertex_shader); + + GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL); + glCompileShader(fragment_shader); + + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &shader_status); + if (shader_status != GL_TRUE) + return 0; + + glAttachShader(program_id, fragment_shader); + + glBindAttribLocation(program_id, 1, "input_vertex_coordinates"); + glBindAttribLocation(program_id, 2, "input_texture_coordinates"); + + glLinkProgram(program_id); + + glGetProgramiv(program_id, GL_LINK_STATUS, &shader_status); + if (shader_status != GL_TRUE) + return 0; + + return program_id; +} + +static VertexBufferSlot* GetVertexBufferSlot(void) +{ + static unsigned long max_slots = 0; + + if (current_vertex_buffer_slot >= max_slots) + { + if (max_slots == 0) + max_slots = 1; + else + max_slots <<= 1; + + vertex_buffer = (VertexBufferSlot*)realloc(vertex_buffer, max_slots * sizeof(VertexBufferSlot)); + glBufferData(GL_ARRAY_BUFFER, max_slots * sizeof(VertexBufferSlot), NULL, GL_STREAM_DRAW); + } + + return &vertex_buffer[current_vertex_buffer_slot++]; +} + +static void FlushVertexBuffer(void) +{ + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(VertexBufferSlot) * current_vertex_buffer_slot, vertex_buffer); + + if (last_render_mode == MODE_DRAW_GLYPH_LCD) + { + // Here we're going to draw with per-component alpha. + // Since OpenGL doesn't really support this, we have to do it manually: + + // Step one: attenuate the destination pixels by the alpha + glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); + glUseProgram(program_glyph_subpixel_part1); + glDrawArrays(GL_TRIANGLES, 0, 6 * current_vertex_buffer_slot); + + // Step two: add the new pixels on top of them + glBlendFunc(GL_ONE, GL_ONE); + glUseProgram(program_glyph_subpixel_part2); + } + else if (last_render_mode == MODE_DRAW_GLYPH) + { + // Here, we just use a regular alpha channel + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glUseProgram(program_glyph_normal); + } + + glDrawArrays(GL_TRIANGLES, 0, 6 * current_vertex_buffer_slot); + + current_vertex_buffer_slot = 0; +} + +SDL_Window* Backend_CreateWindow(const char *title, int width, int height) +{ + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + + return SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL); +} + +Backend_Surface* Backend_Init(SDL_Window *p_window) +{ + window = p_window; + + int window_width, window_height; + SDL_GetWindowSize(window, &window_width, &window_height); + + context = SDL_GL_CreateContext(window); + + if (glewInit() != GLEW_OK) + return FALSE; + + // Check if the platform supports OpenGL 3.2 + if (!GLEW_VERSION_3_2) + return FALSE; + + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(MessageCallback, 0); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + + // Set up Vertex Array Object + glGenVertexArrays(1, &vertex_array_id); + glBindVertexArray(vertex_array_id); + + // Set up Vertex Buffer Object + glGenBuffers(1, &vertex_buffer_id); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id); + glBufferData(GL_ARRAY_BUFFER, 1 * sizeof(VertexBufferSlot), NULL, GL_STREAM_DRAW); + + // Set up the vertex attributes + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, vertex_coordinate)); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, texture_coordinate)); + + // Set up our shaders + program_texture = CompileShader(vertex_shader_texture, fragment_shader_texture); + program_texture_colour_key = CompileShader(vertex_shader_texture, fragment_shader_texture_colour_key); + program_colour_fill = CompileShader(vertex_shader_plain, fragment_shader_colour_fill); + program_glyph_normal = CompileShader(vertex_shader_texture, fragment_shader_glyph_normal); + program_glyph_subpixel_part1 = CompileShader(vertex_shader_texture, fragment_shader_glyph_subpixel_part1); + program_glyph_subpixel_part2 = CompileShader(vertex_shader_texture, fragment_shader_glyph_subpixel_part2); + + if (program_texture == 0 || program_texture_colour_key == 0 || program_colour_fill == 0 || program_glyph_normal == 0 || program_glyph_subpixel_part1 == 0 || program_glyph_subpixel_part2 == 0) + printf("Failed to compile shaders\n"); + + // Get shader uniforms + program_colour_fill_uniform_colour = glGetUniformLocation(program_colour_fill, "colour"); + program_glyph_normal_uniform_colour = glGetUniformLocation(program_glyph_normal, "colour"); + program_glyph_subpixel_part2_uniform_colour = glGetUniformLocation(program_glyph_subpixel_part2, "colour"); + + // Set up framebuffer (used for surface-to-surface blitting) + glGenFramebuffers(1, &framebuffer_id); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id); + + // Set up framebuffer screen texture (used for screen-to-surface blitting) + glGenTextures(1, &framebuffer.texture_id); + glBindTexture(GL_TEXTURE_2D, framebuffer.texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, window_width, window_height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + framebuffer.width = window_width; + framebuffer.height = window_height; + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, framebuffer.texture_id, 0); + glViewport(0, 0, framebuffer.width, framebuffer.height); + + + return &framebuffer; +} + +void Backend_Deinit(void) +{ + glDeleteTextures(1, &framebuffer.texture_id); + glDeleteFramebuffers(1, &framebuffer_id); + glDeleteProgram(program_glyph_subpixel_part2); + glDeleteProgram(program_glyph_subpixel_part1); + glDeleteProgram(program_glyph_normal); + glDeleteProgram(program_colour_fill); + glDeleteProgram(program_texture_colour_key); + glDeleteProgram(program_texture); + glDeleteBuffers(1, &vertex_buffer_id); + glDeleteVertexArrays(1, &vertex_array_id); + SDL_GL_DeleteContext(context); +} + +void Backend_DrawScreen(void) +{ + FlushVertexBuffer(); + last_render_mode = MODE_BLANK; + + glUseProgram(program_texture); + + glDisable(GL_BLEND); + + // Enable texture coordinates, since this uses textures + glEnableVertexAttribArray(2); + + // Target actual screen, and not our framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0, 0, framebuffer.width, framebuffer.height); + + // Draw framebuffer to screen + glBindTexture(GL_TEXTURE_2D, framebuffer.texture_id); + + VertexBufferSlot *vertex_buffer_slot = GetVertexBufferSlot(); + + vertex_buffer_slot->vertices[0][0].texture_coordinate.x = 0.0f; + vertex_buffer_slot->vertices[0][0].texture_coordinate.y = 1.0f; + vertex_buffer_slot->vertices[0][1].texture_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[0][1].texture_coordinate.y = 1.0f; + vertex_buffer_slot->vertices[0][2].texture_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[0][2].texture_coordinate.y = 0.0f; + + vertex_buffer_slot->vertices[1][0].texture_coordinate.x = 0.0f; + vertex_buffer_slot->vertices[1][0].texture_coordinate.y = 1.0f; + vertex_buffer_slot->vertices[1][1].texture_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[1][1].texture_coordinate.y = 0.0f; + vertex_buffer_slot->vertices[1][2].texture_coordinate.x = 0.0f; + vertex_buffer_slot->vertices[1][2].texture_coordinate.y = 0.0f; + + vertex_buffer_slot->vertices[0][0].vertex_coordinate.x = -1.0f; + vertex_buffer_slot->vertices[0][0].vertex_coordinate.y = -1.0f; + vertex_buffer_slot->vertices[0][1].vertex_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[0][1].vertex_coordinate.y = -1.0f; + vertex_buffer_slot->vertices[0][2].vertex_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[0][2].vertex_coordinate.y = 1.0f; + + vertex_buffer_slot->vertices[1][0].vertex_coordinate.x = -1.0f; + vertex_buffer_slot->vertices[1][0].vertex_coordinate.y = -1.0f; + vertex_buffer_slot->vertices[1][1].vertex_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[1][1].vertex_coordinate.y = 1.0f; + vertex_buffer_slot->vertices[1][2].vertex_coordinate.x = -1.0f; + vertex_buffer_slot->vertices[1][2].vertex_coordinate.y = 1.0f; + + FlushVertexBuffer(); + + SDL_GL_SwapWindow(window); + + // According to https://www.khronos.org/opengl/wiki/Common_Mistakes#Swap_Buffers + // the buffer should always be cleared, even if it seems unnecessary + glClear(GL_COLOR_BUFFER_BIT); + + // Switch back to our framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_id); +} + +Backend_Surface* Backend_CreateSurface(unsigned int width, unsigned int height) +{ + Backend_Surface *surface = (Backend_Surface*)malloc(sizeof(Backend_Surface)); + + if (surface == NULL) + return NULL; + + glGenTextures(1, &surface->texture_id); + glBindTexture(GL_TEXTURE_2D, surface->texture_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + surface->width = width; + surface->height = height; + + return surface; +} + +void Backend_FreeSurface(Backend_Surface *surface) +{ + if (surface == NULL) + return; + + glDeleteTextures(1, &surface->texture_id); + free(surface); +} + +unsigned char* Backend_LockSurface(Backend_Surface *surface, unsigned int *pitch) +{ + if (surface == NULL) + return NULL; + + surface->pixels = (unsigned char*)malloc(surface->width * surface->height * 3); + *pitch = surface->width * 3; + return surface->pixels; +} + +void Backend_UnlockSurface(Backend_Surface *surface) +{ + if (surface == NULL) + return; + + GLint previously_bound_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &previously_bound_texture); + + glBindTexture(GL_TEXTURE_2D, surface->texture_id); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surface->width, surface->height, GL_RGB, GL_UNSIGNED_BYTE, surface->pixels); + free(surface->pixels); + + glBindTexture(GL_TEXTURE_2D, previously_bound_texture); +} + +void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key) +{ + static Backend_Surface *last_source_surface; + static Backend_Surface *last_destination_surface; + + if (source_surface == NULL || destination_surface == NULL) + return; + + if (rect->right - rect->left < 0 || rect->bottom - rect->top < 0) + return; + + const RenderMode render_mode = (colour_key ? MODE_DRAW_SURFACE_WITH_TRANSPARENCY : MODE_DRAW_SURFACE); + + if (last_render_mode != render_mode || last_source_surface != source_surface || last_destination_surface != destination_surface) + { + FlushVertexBuffer(); + + last_render_mode = render_mode; + last_source_surface = source_surface; + last_destination_surface = destination_surface; + + // Point our framebuffer to the destination texture + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, destination_surface->texture_id, 0); + glViewport(0, 0, destination_surface->width, destination_surface->height); + + // Switch to colour-key shader if we have to + glUseProgram(colour_key ? program_texture_colour_key : program_texture); + + glDisable(GL_BLEND); + + // Enable texture coordinates, since this uses textures + glEnableVertexAttribArray(2); + + glBindTexture(GL_TEXTURE_2D, source_surface->texture_id); + } + + const GLfloat texture_left = (GLfloat)rect->left / (GLfloat)source_surface->width; + const GLfloat texture_right = (GLfloat)rect->right / (GLfloat)source_surface->width; + const GLfloat texture_top = (GLfloat)rect->top / (GLfloat)source_surface->height; + const GLfloat texture_bottom = (GLfloat)rect->bottom / (GLfloat)source_surface->height; + + const GLfloat vertex_left = (x * (2.0f / destination_surface->width)) - 1.0f; + const GLfloat vertex_right = ((x + (rect->right - rect->left)) * (2.0f / destination_surface->width)) - 1.0f; + const GLfloat vertex_top = (y * (2.0f / destination_surface->height)) - 1.0f; + const GLfloat vertex_bottom = ((y + (rect->bottom - rect->top)) * (2.0f / destination_surface->height)) - 1.0f; + + VertexBufferSlot *vertex_buffer_slot = GetVertexBufferSlot(); + + vertex_buffer_slot->vertices[0][0].texture_coordinate.x = texture_left; + vertex_buffer_slot->vertices[0][0].texture_coordinate.y = texture_top; + vertex_buffer_slot->vertices[0][1].texture_coordinate.x = texture_right; + vertex_buffer_slot->vertices[0][1].texture_coordinate.y = texture_top; + vertex_buffer_slot->vertices[0][2].texture_coordinate.x = texture_right; + vertex_buffer_slot->vertices[0][2].texture_coordinate.y = texture_bottom; + + vertex_buffer_slot->vertices[1][0].texture_coordinate.x = texture_left; + vertex_buffer_slot->vertices[1][0].texture_coordinate.y = texture_top; + vertex_buffer_slot->vertices[1][1].texture_coordinate.x = texture_right; + vertex_buffer_slot->vertices[1][1].texture_coordinate.y = texture_bottom; + vertex_buffer_slot->vertices[1][2].texture_coordinate.x = texture_left; + vertex_buffer_slot->vertices[1][2].texture_coordinate.y = texture_bottom; + + vertex_buffer_slot->vertices[0][0].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[0][0].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[0][1].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[0][1].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[0][2].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[0][2].vertex_coordinate.y = vertex_bottom; + + vertex_buffer_slot->vertices[1][0].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[1][0].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[1][1].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[1][1].vertex_coordinate.y = vertex_bottom; + vertex_buffer_slot->vertices[1][2].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[1][2].vertex_coordinate.y = vertex_bottom; +} + +void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue) +{ + static Backend_Surface *last_surface; + static unsigned char last_red; + static unsigned char last_green; + static unsigned char last_blue; + + if (surface == NULL) + return; + + if (rect->right - rect->left < 0 || rect->bottom - rect->top < 0) + return; + + if (last_render_mode != MODE_COLOUR_FILL || last_surface != surface || last_red != red || last_green != green || last_blue != blue) + { + FlushVertexBuffer(); + + last_render_mode = MODE_COLOUR_FILL; + last_surface = surface; + last_red = red; + last_green = green; + last_blue = blue; + + // Point our framebuffer to the destination texture + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, surface->texture_id, 0); + glViewport(0, 0, surface->width, surface->height); + + glUseProgram(program_colour_fill); + + glDisable(GL_BLEND); + + // Disable texture coordinate array, since this doesn't use textures + glDisableVertexAttribArray(2); + + glUniform4f(program_colour_fill_uniform_colour, red / 255.0f, green / 255.0f, blue / 255.0f, 1.0f); + + current_vertex_buffer_slot = 0; + } + + const GLfloat vertex_left = (rect->left * (2.0f / surface->width)) - 1.0f; + const GLfloat vertex_right = (rect->right * (2.0f / surface->width)) - 1.0f; + const GLfloat vertex_top = (rect->top * (2.0f / surface->height)) - 1.0f; + const GLfloat vertex_bottom = (rect->bottom * (2.0f / surface->height)) - 1.0f; + + VertexBufferSlot *vertex_buffer_slot = GetVertexBufferSlot(); + + vertex_buffer_slot->vertices[0][0].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[0][0].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[0][1].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[0][1].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[0][2].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[0][2].vertex_coordinate.y = vertex_bottom; + + vertex_buffer_slot->vertices[1][0].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[1][0].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[1][1].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[1][1].vertex_coordinate.y = vertex_bottom; + vertex_buffer_slot->vertices[1][2].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[1][2].vertex_coordinate.y = vertex_bottom; +} + +BOOL Backend_SupportsSubpixelGlyphs(void) +{ + return TRUE; +} + +Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, FontPixelMode pixel_mode) +{ + Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph)); + + if (glyph == NULL) + return NULL; + + const unsigned int destination_pitch = (width + 3) & ~3; // Round up to the nearest 4 (OpenGL needs this) + + unsigned char *buffer = (unsigned char*)malloc(destination_pitch * height); + + switch (pixel_mode) + { + case FONT_PIXEL_MODE_LCD: + case FONT_PIXEL_MODE_GRAY: + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + unsigned char *destination_pointer = buffer + y * destination_pitch; + memcpy(destination_pointer, source_pointer, width); + } + + break; + + case FONT_PIXEL_MODE_MONO: + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + unsigned char *destination_pointer = buffer + y * destination_pitch; + + for (unsigned int x = 0; x < width; ++x) + *destination_pointer++ = (*source_pointer++ ? 0xFF : 0); + } + + break; + } + + GLint previously_bound_texture; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &previously_bound_texture); + + glGenTextures(1, &glyph->texture_id); + glBindTexture(GL_TEXTURE_2D, glyph->texture_id); + if (pixel_mode == FONT_PIXEL_MODE_LCD) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width / 3, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, buffer); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + glyph->width = (pixel_mode == FONT_PIXEL_MODE_LCD ? width / 3 : width); + glyph->height = height; + glyph->pixel_mode = pixel_mode; + + free(buffer); + + glBindTexture(GL_TEXTURE_2D, previously_bound_texture); + + return glyph; +} + +void Backend_UnloadGlyph(Backend_Glyph *glyph) +{ + if (glyph == NULL) + return; + + glDeleteTextures(1, &glyph->texture_id); + free(glyph); +} + +void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours) +{ + static Backend_Surface *last_surface; + static Backend_Glyph *last_glyph; + static unsigned char last_red; + static unsigned char last_green; + static unsigned char last_blue; + + if (glyph == NULL || surface == NULL) + return; + + const RenderMode render_mode = (glyph->pixel_mode == FONT_PIXEL_MODE_LCD ? MODE_DRAW_GLYPH_LCD : MODE_DRAW_GLYPH); + + if (last_render_mode != render_mode || last_surface != surface || last_glyph != glyph || last_red != colours[0] || last_green != colours[1] || last_blue != colours[2]) + { + FlushVertexBuffer(); + + last_render_mode = render_mode; + last_surface = surface; + last_glyph = glyph; + last_red = colours[0]; + last_green = colours[1]; + last_blue = colours[2]; + + if (glyph->pixel_mode == FONT_PIXEL_MODE_LCD) + { + glUseProgram(program_glyph_subpixel_part2); + glUniform4f(program_glyph_subpixel_part2_uniform_colour, colours[0] / 255.0f, colours[1] / 255.0f, colours[2] / 255.0f, 1.0f); + } + else + { + glUseProgram(program_glyph_normal); + glUniform4f(program_glyph_normal_uniform_colour, colours[0] / 255.0f, colours[1] / 255.0f, colours[2] / 255.0f, 1.0f); + } + + // Point our framebuffer to the destination texture + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, surface->texture_id, 0); + glViewport(0, 0, surface->width, surface->height); + + glEnable(GL_BLEND); + + // Enable texture coordinates, since this uses textures + glEnableVertexAttribArray(2); + + glBindTexture(GL_TEXTURE_2D, glyph->texture_id); + } + + const GLfloat vertex_left = (x * (2.0f / surface->width)) - 1.0f; + const GLfloat vertex_right = ((x + glyph->width) * (2.0f / surface->width)) - 1.0f; + const GLfloat vertex_top = (y * (2.0f / surface->height)) - 1.0f; + const GLfloat vertex_bottom = ((y + glyph->height) * (2.0f / surface->height)) - 1.0f; + + VertexBufferSlot *vertex_buffer_slot = GetVertexBufferSlot(); + + vertex_buffer_slot->vertices[0][0].texture_coordinate.x = 0.0f; + vertex_buffer_slot->vertices[0][0].texture_coordinate.y = 0.0f; + vertex_buffer_slot->vertices[0][1].texture_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[0][1].texture_coordinate.y = 0.0f; + vertex_buffer_slot->vertices[0][2].texture_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[0][2].texture_coordinate.y = 1.0f; + + vertex_buffer_slot->vertices[1][0].texture_coordinate.x = 0.0f; + vertex_buffer_slot->vertices[1][0].texture_coordinate.y = 0.0f; + vertex_buffer_slot->vertices[1][1].texture_coordinate.x = 1.0f; + vertex_buffer_slot->vertices[1][1].texture_coordinate.y = 1.0f; + vertex_buffer_slot->vertices[1][2].texture_coordinate.x = 0.0f; + vertex_buffer_slot->vertices[1][2].texture_coordinate.y = 1.0f; + + vertex_buffer_slot->vertices[0][0].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[0][0].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[0][1].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[0][1].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[0][2].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[0][2].vertex_coordinate.y = vertex_bottom; + + vertex_buffer_slot->vertices[1][0].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[1][0].vertex_coordinate.y = vertex_top; + vertex_buffer_slot->vertices[1][1].vertex_coordinate.x = vertex_right; + vertex_buffer_slot->vertices[1][1].vertex_coordinate.y = vertex_bottom; + vertex_buffer_slot->vertices[1][2].vertex_coordinate.x = vertex_left; + vertex_buffer_slot->vertices[1][2].vertex_coordinate.y = vertex_bottom; +} + +void Backend_HandleDeviceLoss(void) +{ + // No problem for us +} + +void Backend_HandleWindowResize(void) +{ + // No problem for us +} diff --git a/src/Backends/Rendering/SDLSurface.cpp b/src/Backends/Rendering/SDLSurface.cpp new file mode 100644 index 00000000..1e976c3a --- /dev/null +++ b/src/Backends/Rendering/SDLSurface.cpp @@ -0,0 +1,239 @@ +#include "../Rendering.h" + +#include +#include + +#include "SDL.h" + +#include "../../WindowsWrapper.h" + +typedef struct Backend_Surface +{ + SDL_Surface *sdlsurface; +} Backend_Surface; + +typedef struct Backend_Glyph +{ + SDL_Surface *sdlsurface; +} Backend_Glyph; + +static SDL_Window *window; +static SDL_Surface *window_sdlsurface; + +static Backend_Surface framebuffer; + +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; +} + +SDL_Window* Backend_CreateWindow(const char *title, int width, int height) +{ + return SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0); +} + +Backend_Surface* Backend_Init(SDL_Window *p_window) +{ + window = p_window; + + window_sdlsurface = SDL_GetWindowSurface(window); + + framebuffer.sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, window_sdlsurface->w, window_sdlsurface->h, 0, SDL_PIXELFORMAT_RGB24); + + if (framebuffer.sdlsurface == NULL) + return NULL; + + return &framebuffer; +} + +void Backend_Deinit(void) +{ + SDL_FreeSurface(framebuffer.sdlsurface); +} + +void Backend_DrawScreen(void) +{ + SDL_BlitSurface(framebuffer.sdlsurface, NULL, window_sdlsurface, 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->sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, SDL_PIXELFORMAT_RGB24); + + if (surface->sdlsurface == NULL) + { + free(surface); + return NULL; + } + + return surface; +} + +void Backend_FreeSurface(Backend_Surface *surface) +{ + if (surface == NULL) + return; + + SDL_FreeSurface(surface->sdlsurface); + free(surface); +} + +unsigned char* Backend_LockSurface(Backend_Surface *surface, unsigned int *pitch) +{ + if (surface == NULL) + return NULL; + + *pitch = surface->sdlsurface->pitch; + return (unsigned char*)surface->sdlsurface->pixels; +} + +void Backend_UnlockSurface(Backend_Surface *surface) +{ + (void)surface; +} + +void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key) +{ + if (source_surface == NULL || destination_surface == NULL) + return; + + SDL_Rect source_rect; + RectToSDLRect(rect, &source_rect); + + SDL_Rect destination_rect; + destination_rect.x = x; + destination_rect.y = y; + destination_rect.w = source_rect.w; + destination_rect.h = source_rect.h; + + SDL_SetColorKey(source_surface->sdlsurface, colour_key ? SDL_TRUE : SDL_FALSE, SDL_MapRGB(source_surface->sdlsurface->format, 0, 0, 0)); // Assumes the colour key will always be #000000 (black) + + SDL_BlitSurface(source_surface->sdlsurface, &source_rect, destination_surface->sdlsurface, &destination_rect); +} + +void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue) +{ + if (surface == NULL) + return; + + SDL_Rect destination_rect; + RectToSDLRect(rect, &destination_rect); + + SDL_FillRect(surface->sdlsurface, &destination_rect, SDL_MapRGB(surface->sdlsurface->format, red, green, blue)); +} + +BOOL Backend_SupportsSubpixelGlyphs(void) +{ + return FALSE; // SDL_Surfaces don't have per-component alpha +} + +Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, FontPixelMode pixel_mode) +{ + Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph)); + + if (glyph == NULL) + return NULL; + + glyph->sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 0, SDL_PIXELFORMAT_RGBA32); + + if (glyph->sdlsurface == NULL) + { + free(glyph); + return NULL; + } + + switch (pixel_mode) + { + case FONT_PIXEL_MODE_LCD: + // Unsupported + break; + + case FONT_PIXEL_MODE_GRAY: + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + unsigned char *destination_pointer = (unsigned char*)glyph->sdlsurface->pixels + y * glyph->sdlsurface->pitch; + + for (unsigned int x = 0; x < width; ++x) + { + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = *source_pointer++; + } + } + + break; + + case FONT_PIXEL_MODE_MONO: + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + unsigned char *destination_pointer = (unsigned char*)glyph->sdlsurface->pixels + y * glyph->sdlsurface->pitch; + + for (unsigned int x = 0; x < width; ++x) + { + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = *source_pointer++ ? 0xFF : 0; + } + } + + break; + } + + return glyph; +} + +void Backend_UnloadGlyph(Backend_Glyph *glyph) +{ + if (glyph == NULL) + return; + + SDL_FreeSurface(glyph->sdlsurface); + free(glyph); +} + +void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours) +{ + if (glyph == NULL || surface == NULL) + return; + + SDL_Rect rect; + rect.x = x; + rect.y = y; + rect.w = glyph->sdlsurface->w; + rect.h = glyph->sdlsurface->h; + + SDL_SetSurfaceColorMod(glyph->sdlsurface, colours[0], colours[1], colours[2]); + + SDL_BlitSurface(glyph->sdlsurface, NULL, surface->sdlsurface, &rect); +} + +void Backend_HandleDeviceLoss(void) +{ + // No problem for us +} + +void Backend_HandleWindowResize(void) +{ + // https://wiki.libsdl.org/SDL_GetWindowSurface + // We need to fetch a new surface pointer + window_sdlsurface = SDL_GetWindowSurface(window); +} diff --git a/src/Backends/Rendering/SDLTexture.cpp b/src/Backends/Rendering/SDLTexture.cpp new file mode 100644 index 00000000..a9f3307f --- /dev/null +++ b/src/Backends/Rendering/SDLTexture.cpp @@ -0,0 +1,321 @@ +#include "../Rendering.h" + +#include +#include + +#include "SDL.h" + +#include "../../WindowsWrapper.h" + +#include "../../Draw.h" +#include "../../Ending.h" +#include "../../MapName.h" +#include "../../TextScr.h" + +typedef struct Backend_Surface +{ + SDL_Texture *texture; + unsigned char *pixels; + unsigned int width; + unsigned int height; +} Backend_Surface; + +typedef struct Backend_Glyph +{ + SDL_Texture *texture; + unsigned int width; + unsigned int height; +} Backend_Glyph; + +static SDL_Renderer *renderer; + +static Backend_Surface framebuffer; + +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; +} + +SDL_Window* Backend_CreateWindow(const char *title, int width, int height) +{ + return SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0); +} + +Backend_Surface* Backend_Init(SDL_Window *window) +{ + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); + + if (renderer == NULL) + return NULL; + + int width, height; + SDL_GetRendererOutputSize(renderer, &width, &height); + framebuffer.texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, width, height); + + if (framebuffer.texture == NULL) + { + SDL_DestroyRenderer(renderer); + return NULL; + } + + framebuffer.width = width; + framebuffer.height = height; + + return &framebuffer; +} + +void Backend_Deinit(void) +{ + SDL_DestroyTexture(framebuffer.texture); + SDL_DestroyRenderer(renderer); +} + +void Backend_DrawScreen(void) +{ + SDL_SetRenderTarget(renderer, NULL); + SDL_RenderCopy(renderer, framebuffer.texture, NULL, NULL); + 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->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_TARGET, width, height); + + if (surface->texture == NULL) + { + free(surface); + return NULL; + } + + surface->width = width; + surface->height = height; + + return surface; +} + +void Backend_FreeSurface(Backend_Surface *surface) +{ + if (surface == NULL) + return; + + SDL_DestroyTexture(surface->texture); + free(surface); +} + +unsigned char* Backend_LockSurface(Backend_Surface *surface, unsigned int *pitch) +{ + if (surface == NULL) + return NULL; + + *pitch = surface->width * 3; + + surface->pixels = (unsigned char*)malloc(surface->width * surface->height * 3); + + return surface->pixels; +} + +void Backend_UnlockSurface(Backend_Surface *surface) +{ + if (surface == NULL) + return; + + unsigned char *buffer = (unsigned char*)malloc(surface->width * surface->height * 4); + unsigned char *buffer_pointer = buffer; + const unsigned char *src_pixel = surface->pixels; + + // Convert the SDL_Surface's colour-keyed pixels to RGBA32 + for (unsigned int y = 0; y < surface->height; ++y) + { + + for (unsigned int x = 0; x < surface->width; ++x) + { + *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 #000000 (black) + *buffer_pointer++ = 0; + else + *buffer_pointer++ = 0xFF; + + src_pixel += 3; + } + } + + free(surface->pixels); + + SDL_UpdateTexture(surface->texture, NULL, buffer, surface->width * 4); + + free(buffer); +} + +void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key) +{ + if (source_surface == NULL || destination_surface == NULL) + return; + + SDL_Rect source_rect; + RectToSDLRect(rect, &source_rect); + + SDL_Rect destination_rect = {(int)x, (int)y, source_rect.w, source_rect.h}; + + // 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); +} + +void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue) +{ + if (surface == NULL) + return; + + SDL_Rect sdl_rect; + RectToSDLRect(rect, &sdl_rect); + + // Check colour-key + if (red == 0 && green == 0 && blue == 0) + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + else + SDL_SetRenderDrawColor(renderer, red, green, blue, SDL_ALPHA_OPAQUE); + + // Draw colour + SDL_SetRenderTarget(renderer, surface->texture); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); + SDL_RenderFillRect(renderer, &sdl_rect); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); +} + +BOOL Backend_SupportsSubpixelGlyphs(void) +{ + return FALSE; // SDL_Textures don't have per-component alpha +} + +Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, FontPixelMode pixel_mode) +{ + Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph)); + + if (glyph == NULL) + return NULL; + + glyph->texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height); + + if (glyph->texture == NULL) + { + free(glyph); + return NULL; + } + + unsigned char *buffer = (unsigned char*)malloc(width * height * 4); + + if (buffer == NULL) + { + SDL_DestroyTexture(glyph->texture); + free(glyph); + return NULL; + } + + unsigned char *destination_pointer = buffer; + + switch (pixel_mode) + { + case FONT_PIXEL_MODE_LCD: + // Unsupported + break; + + case FONT_PIXEL_MODE_GRAY: + + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + + for (unsigned int x = 0; x < width; ++x) + { + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = *source_pointer++; + } + } + + break; + + case FONT_PIXEL_MODE_MONO: + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + + for (unsigned int x = 0; x < width; ++x) + { + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = 0xFF; + *destination_pointer++ = *source_pointer++ ? 0xFF : 0; + } + } + + break; + } + + SDL_UpdateTexture(glyph->texture, NULL, buffer, width * 4); + + glyph->width = width; + glyph->height = height; + + return glyph; +} + +void Backend_UnloadGlyph(Backend_Glyph *glyph) +{ + if (glyph == NULL) + return; + + SDL_DestroyTexture(glyph->texture); + free(glyph); +} + +void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours) +{ + // The SDL_Texture side of things uses alpha, not a colour-key, so the bug where the font is blended + // with the colour key doesn't occur. + + if (glyph == NULL || surface == NULL) + return; + + SDL_Rect destination_rect = {(int)x, (int)y, (int)glyph->width, (int)glyph->height}; + + // Blit the texture + SDL_SetTextureColorMod(glyph->texture, colours[0], colours[1], colours[2]); + SDL_SetTextureBlendMode(glyph->texture, SDL_BLENDMODE_BLEND); + SDL_SetRenderTarget(renderer, surface->texture); + SDL_RenderCopy(renderer, glyph->texture, NULL, &destination_rect); +} + +void Backend_HandleDeviceLoss(void) +{ + // TODO - RestoreSurfaces + // All of our target-textures have been lost, so regenerate them +// RestoreSurfaces(); +// RestoreStripper(); +// RestoreMapName(); +// RestoreTextScript(); +} + +void Backend_HandleWindowResize(void) +{ + // No problem for us +} diff --git a/src/Backends/Rendering/Software.cpp b/src/Backends/Rendering/Software.cpp new file mode 100644 index 00000000..937b18f7 --- /dev/null +++ b/src/Backends/Rendering/Software.cpp @@ -0,0 +1,411 @@ +#include "../Rendering.h" + +#include +#include +#include + +#include "SDL.h" + +#include "../../WindowsWrapper.h" + +#undef MIN +#undef MAX +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +typedef struct Backend_Surface +{ + unsigned char *pixels; + unsigned int width; + unsigned int height; + unsigned int pitch; +} Backend_Surface; + +typedef struct Backend_Glyph +{ + void *pixels; + unsigned int width; + unsigned int height; + FontPixelMode pixel_mode; +} Backend_Glyph; + +static SDL_Window *window; +static SDL_Surface *window_sdlsurface; +static SDL_Surface *framebuffer_sdlsurface; +static Backend_Surface framebuffer; + +SDL_Window* Backend_CreateWindow(const char *title, int width, int height) +{ + return SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, 0); +} + +Backend_Surface* Backend_Init(SDL_Window *p_window) +{ + window = p_window; + + window_sdlsurface = SDL_GetWindowSurface(window); + + framebuffer_sdlsurface = SDL_CreateRGBSurfaceWithFormat(0, window_sdlsurface->w, window_sdlsurface->h, 0, SDL_PIXELFORMAT_RGB24); + + if (framebuffer_sdlsurface == NULL) + return NULL; + + framebuffer.pixels = (unsigned char*)framebuffer_sdlsurface->pixels; + framebuffer.width = framebuffer_sdlsurface->w; + framebuffer.height = framebuffer_sdlsurface->h; + framebuffer.pitch = framebuffer_sdlsurface->pitch; + + return &framebuffer; +} + +void Backend_Deinit(void) +{ + SDL_FreeSurface(framebuffer_sdlsurface); +} + +void Backend_DrawScreen(void) +{ + SDL_BlitSurface(framebuffer_sdlsurface, NULL, window_sdlsurface, 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) +{ + if (surface == NULL) + return; + + free(surface->pixels); + free(surface); +} + +unsigned char* Backend_LockSurface(Backend_Surface *surface, unsigned int *pitch) +{ + if (surface == NULL) + return NULL; + + *pitch = surface->pitch; + return surface->pixels; +} + +void Backend_UnlockSurface(Backend_Surface *surface) +{ + (void)surface; +} + +void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key) +{ + if (source_surface == NULL || destination_surface == NULL) + return; + + 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; + } + + if (rect_clamped.bottom - rect_clamped.top <= 0) + return; + + if (rect_clamped.right - rect_clamped.left <= 0) + return; + + // 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 #000000 (black) + { + source_pointer += 3; + destination_pointer += 3; + } + else + { + *destination_pointer++ = *source_pointer++; + *destination_pointer++ = *source_pointer++; + *destination_pointer++ = *source_pointer++; + } + } + } + } + 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_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue) +{ + if (surface == NULL) + return; + + 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; + } + + if (rect_clamped.bottom - rect_clamped.top <= 0) + return; + + if (rect_clamped.right - rect_clamped.left <= 0) + return; + + for (long j = 0; j < rect_clamped.bottom - rect_clamped.top; ++j) + { + unsigned char *destination_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) + { + *destination_pointer++ = red; + *destination_pointer++ = green; + *destination_pointer++ = blue; + } + } +} + +BOOL Backend_SupportsSubpixelGlyphs(void) +{ + return TRUE; // It's a software renderer, baby +} + +Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, FontPixelMode pixel_mode) +{ + Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph)); + + if (glyph == NULL) + return NULL; + + switch (pixel_mode) + { + case FONT_PIXEL_MODE_LCD: + case FONT_PIXEL_MODE_GRAY: + { + glyph->pixels = malloc(width * height * sizeof(float)); + + if (glyph->pixels == NULL) + { + free(glyph); + return NULL; + } + + float *destination_pointer = (float*)glyph->pixels; + + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + + for (unsigned int x = 0; x < width; ++x) + *destination_pointer++ = *source_pointer++ / 255.0f; + } + + break; + } + + case FONT_PIXEL_MODE_MONO: + { + glyph->pixels = malloc(width * height); + + if (glyph->pixels == NULL) + { + free(glyph); + return NULL; + } + + for (unsigned int y = 0; y < height; ++y) + { + const unsigned char *source_pointer = pixels + y * pitch; + unsigned char *destination_pointer = (unsigned char*)glyph->pixels + y * width; + + memcpy(destination_pointer, source_pointer, width); + } + + break; + } + } + + glyph->width = (pixel_mode == FONT_PIXEL_MODE_LCD ? width / 3 : width); + glyph->height = height; + glyph->pixel_mode = pixel_mode; + + return glyph; +} + +void Backend_UnloadGlyph(Backend_Glyph *glyph) +{ + if (glyph == NULL) + return; + + free(glyph->pixels); + free(glyph); +} + +void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours) +{ + if (glyph == NULL || surface == NULL) + return; + + switch (glyph->pixel_mode) + { + case FONT_PIXEL_MODE_LCD: + for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy) + { + for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, surface->width); ++ix) + { + const float *font_pixel = (float*)glyph->pixels + (iy * glyph->width + ix) * 3; + + if (font_pixel[0] || font_pixel[1] || font_pixel[2]) + { + unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3; + + for (unsigned int j = 0; j < 3; ++j) + { + const float alpha = font_pixel[j]; + bitmap_pixel[j] = (unsigned char)((colours[j] * alpha) + (bitmap_pixel[j] * (1.0f - alpha))); // Alpha blending + } + } + } + } + + break; + + case FONT_PIXEL_MODE_GRAY: + for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy) + { + for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, surface->width); ++ix) + { + const float alpha = ((float*)glyph->pixels)[iy * glyph->width + ix]; + + if (alpha) + { + unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3; + + for (unsigned int j = 0; j < 3; ++j) + bitmap_pixel[j] = (unsigned char)((colours[j] * alpha) + (bitmap_pixel[j] * (1.0f - alpha))); // Alpha blending + } + } + } + + break; + + case FONT_PIXEL_MODE_MONO: + for (unsigned int iy = MAX(-y, 0); y + iy < MIN(y + glyph->height, surface->height); ++iy) + { + for (unsigned int ix = MAX(-x, 0); x + ix < MIN(x + glyph->width, surface->width); ++ix) + { + if (((unsigned char*)glyph->pixels)[iy * glyph->width + ix]) + { + unsigned char *bitmap_pixel = surface->pixels + (y + iy) * surface->pitch + (x + ix) * 3; + + for (unsigned int j = 0; j < 3; ++j) + bitmap_pixel[j] = colours[j]; + } + } + } + + break; + } +} + +void Backend_HandleDeviceLoss(void) +{ + // No problem for us +} + +void Backend_HandleWindowResize(void) +{ + // https://wiki.libsdl.org/SDL_GetWindowSurface + // We need to fetch a new surface pointer + window_sdlsurface = SDL_GetWindowSurface(window); +} diff --git a/src/Draw.cpp b/src/Draw.cpp index 4add7b70..ecd7b52c 100644 --- a/src/Draw.cpp +++ b/src/Draw.cpp @@ -4,10 +4,11 @@ #include #include -#include +#include "SDL.h" #include "WindowsWrapper.h" +#include "Backends/Rendering.h" #include "CommonDefines.h" #include "Ending.h" #include "Generic.h" @@ -28,20 +29,11 @@ RECT grcFull = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; int magnification; BOOL fullscreen; -static LPDIRECTDRAW lpDD; -static LPDIRECTDRAWSURFACE frontbuffer; -static LPDIRECTDRAWSURFACE backbuffer; +static Backend_Surface *framebuffer; -static LPDIRECTDRAWCLIPPER clipper; +static Backend_Surface *surf[SURFACE_ID_MAX]; -static LPDIRECTDRAWSURFACE surf[SURFACE_ID_MAX]; - -static RECT backbuffer_rect; - -static int scaled_window_width; -static int scaled_window_height; - -static HFONT font; +static SDL_PixelFormat *rgb24_pixel_format; // Needed because SDL2 is stupid // This doesn't exist in the Linux port, so none of these symbol names are accurate static struct @@ -53,20 +45,9 @@ static struct BOOL bSystem; // Basically a 'do not regenerate' flag } surface_metadata[SURFACE_ID_MAX]; -// The original names for these variables are unknown -static int x_offset; -static int y_offset; - #define FRAMERATE 20 -// The original name for this function is unknown -void SetWindowPadding(int width, int height) -{ - x_offset = width; - y_offset = height; -} - -BOOL Flip_SystemTask(HWND hWnd) +BOOL Flip_SystemTask(void) { static DWORD timePrev; static DWORD timeNow; @@ -90,32 +71,18 @@ BOOL Flip_SystemTask(HWND hWnd) else timePrev += FRAMERATE; - static RECT dst_rect; - GetWindowRect(hWnd, &dst_rect); - dst_rect.left += x_offset; - dst_rect.top += y_offset; - dst_rect.right = dst_rect.left + scaled_window_width; - dst_rect.bottom = dst_rect.top + scaled_window_height; - - frontbuffer->Blt(&dst_rect, backbuffer, &backbuffer_rect, DDBLT_WAIT, NULL); - - if (RestoreSurfaces()) - { - RestoreStripper(); - RestoreMapName(); - RestoreTextScript(); - } + Backend_DrawScreen(); return TRUE; } -BOOL StartDirectDraw(HWND hWnd, int lMagnification, int lColourDepth) +SDL_Window* CreateWindow(const char *title, int width, int height) { - DDSURFACEDESC ddsd; - - if (DirectDrawCreate(NULL, &lpDD, NULL) != DD_OK) - return FALSE; + return Backend_CreateWindow(title, width, height); +} +BOOL StartDirectDraw(SDL_Window *window, int lMagnification) +{ memset(surface_metadata, 0, sizeof(surface_metadata)); switch (lMagnification) @@ -123,84 +90,44 @@ BOOL StartDirectDraw(HWND hWnd, int lMagnification, int lColourDepth) case 0: magnification = 1; fullscreen = FALSE; - lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); break; case 1: magnification = 2; fullscreen = FALSE; - lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); break; case 2: magnification = 2; fullscreen = TRUE; - lpDD->SetCooperativeLevel(hWnd, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE); - lpDD->SetDisplayMode(WINDOW_WIDTH * magnification, WINDOW_HEIGHT * magnification, lColourDepth); + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN); break; } - backbuffer_rect.left = 0; - backbuffer_rect.top = 0; - backbuffer_rect.right = WINDOW_WIDTH * magnification; - backbuffer_rect.bottom = WINDOW_HEIGHT * magnification; + framebuffer = Backend_Init(window); - scaled_window_width = WINDOW_WIDTH * magnification; - scaled_window_height = WINDOW_HEIGHT * magnification; - - memset(&ddsd, 0, sizeof(DDSURFACEDESC)); - ddsd.dwSize = sizeof(DDSURFACEDESC); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - ddsd.dwBackBufferCount = 0; - - if (lpDD->CreateSurface(&ddsd, &frontbuffer, NULL) != DD_OK) - return FALSE; - - memset(&ddsd, 0, sizeof(DDSURFACEDESC)); - ddsd.dwSize = sizeof(DDSURFACEDESC); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - ddsd.dwWidth = WINDOW_WIDTH * magnification; - ddsd.dwHeight = WINDOW_HEIGHT * magnification; - - if (lpDD->CreateSurface(&ddsd, &backbuffer, NULL) != DD_OK) - return FALSE; - - lpDD->CreateClipper(0, &clipper, NULL); - clipper->SetHWnd(0, hWnd); - frontbuffer->SetClipper(clipper); + rgb24_pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_RGB24); return TRUE; } -void EndDirectDraw(HWND hWnd) +void EndDirectDraw(void) { // Release all surfaces for (int i = 0; i < SURFACE_ID_MAX; ++i) { if (surf[i] != NULL) { - surf[i]->Release(); + Backend_FreeSurface(surf[i]); surf[i] = NULL; } } - if (frontbuffer != NULL) - { - frontbuffer->Release(); - frontbuffer = NULL; - backbuffer = NULL; - } + framebuffer = NULL; - if (fullscreen) - lpDD->SetCooperativeLevel(hWnd, DDSCL_NORMAL); + SDL_FreeFormat(rgb24_pixel_format); - if (lpDD != NULL) - { - lpDD->Release(); - lpDD = NULL; - } + Backend_Deinit(); memset(surface_metadata, 0, sizeof(surface_metadata)); } @@ -210,13 +137,71 @@ void ReleaseSurface(SurfaceID s) // Release the surface we want to release if (surf[s] != NULL) { - surf[s]->Release(); + Backend_FreeSurface(surf[s]); surf[s] = NULL; } memset(&surface_metadata[s], 0, sizeof(surface_metadata[0])); } +static BOOL ScaleAndUploadSurface(SDL_Surface *surface, SurfaceID surf_no) +{ + SDL_Surface *converted_surface = SDL_ConvertSurface(surface, rgb24_pixel_format, 0); + + SDL_FreeSurface(surface); + + if (converted_surface == NULL) + return FALSE; + + // IF YOU WANT TO ADD HD SPRITES, THIS IS THE CODE YOU SHOULD EDIT + unsigned int pitch; + unsigned char *pixels = Backend_LockSurface(surf[surf_no], &pitch); + + if (magnification == 1) + { + // Just copy the pixels the way they are + for (int y = 0; y < converted_surface->h; ++y) + { + const unsigned char *src_row = (unsigned char*)converted_surface->pixels + y * converted_surface->pitch; + unsigned char *dst_row = &pixels[y * pitch]; + + memcpy(dst_row, src_row, converted_surface->w * 3); + } + } + else + { + // Upscale the bitmap to the game's internal resolution + for (int y = 0; y < converted_surface->h; ++y) + { + const unsigned char *src_row = (unsigned char*)converted_surface->pixels + y * converted_surface->pitch; + unsigned char *dst_row = &pixels[y * pitch * magnification]; + + const unsigned char *src_ptr = src_row; + unsigned char *dst_ptr = dst_row; + + for (int x = 0; x < converted_surface->w; ++x) + { + for (int i = 0; i < magnification; ++i) + { + *dst_ptr++ = src_ptr[0]; + *dst_ptr++ = src_ptr[1]; + *dst_ptr++ = src_ptr[2]; + } + + src_ptr += 3; + } + + for (int i = 1; i < magnification; ++i) + memcpy(dst_row + i * pitch, dst_row, converted_surface->w * magnification * 3); + } + } + + Backend_UnlockSurface(surf[surf_no]); + SDL_FreeSurface(converted_surface); + + return TRUE; +} + // TODO - Inaccurate stack frame BOOL MakeSurface_Resource(const char *name, SurfaceID surf_no) { @@ -226,59 +211,45 @@ BOOL MakeSurface_Resource(const char *name, SurfaceID surf_no) if (surf[surf_no] != NULL) return FALSE; - HANDLE handle = LoadImageA(GetModuleHandleA(NULL), name, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); - if (handle == NULL) + HRSRC hrscr = FindResourceA(NULL, name, RT_BITMAP); + + if (hrscr == NULL) return FALSE; - BITMAP bitmap; - GetObjectA(handle, sizeof(BITMAP), &bitmap); + size_t size = SizeofResource(NULL, hrscr); + const unsigned char *data = (unsigned char*)LockResource(LoadResource(NULL, hrscr)); - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(DDSURFACEDESC)); - ddsd.dwSize = sizeof(DDSURFACEDESC); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - ddsd.dwWidth = bitmap.bmWidth * magnification; - ddsd.dwHeight = bitmap.bmHeight * magnification; + // The bitmap we get from LockResource is incomplete, so we need to restore its missing header here + unsigned char *bmp_buffer = (unsigned char*)malloc(size + 0xE); - if (lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL) != DD_OK) + if (bmp_buffer == NULL) return FALSE; - int src_x = 0; - int src_y = 0; - int src_w = bitmap.bmWidth; - int src_h = bitmap.bmHeight; + const unsigned char bmp_header[0xE] = {0x42, 0x4D, 0x76, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00}; - int dst_x = 0; - int dst_y = 0; - int dst_w = bitmap.bmWidth * magnification; - int dst_h = bitmap.bmHeight * magnification; + memcpy(bmp_buffer, bmp_header, 0xE); + memcpy(bmp_buffer + 0xE, data, size); - HDC hdc = CreateCompatibleDC(NULL); - HGDIOBJ hgdiobj = SelectObject(hdc, handle); + SDL_RWops *fp = SDL_RWFromConstMem(bmp_buffer, size + 0xE); + SDL_Surface *surface = SDL_LoadBMP_RW(fp, 1); - HDC hdc2; - surf[surf_no]->GetDC(&hdc2); - StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); - surf[surf_no]->ReleaseDC(hdc2); + surf[surf_no] = Backend_CreateSurface(surface->w * magnification, surface->h * magnification); - SelectObject(hdc, hgdiobj); - DeleteDC(hdc); + if (surf[surf_no] == NULL) + { + SDL_FreeSurface(surface); + return FALSE; + } - DDCOLORKEY ddcolorkey; - ddcolorkey.dwColorSpaceLowValue = 0; - ddcolorkey.dwColorSpaceHighValue = 0; - - surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); - surf[surf_no]->SetClipper(clipper); - -#ifdef FIX_BUGS - DeleteObject(handle); -#endif + if (!ScaleAndUploadSurface(surface, surf_no)) + { + Backend_FreeSurface(surf[surf_no]); + return FALSE; + } surface_metadata[surf_no].type = SURFACE_SOURCE_RESOURCE; - surface_metadata[surf_no].width = bitmap.bmWidth; - surface_metadata[surf_no].height = bitmap.bmHeight; + surface_metadata[surf_no].width = surface->w; + surface_metadata[surf_no].height = surface->h; surface_metadata[surf_no].bSystem = FALSE; strcpy(surface_metadata[surf_no].name, name); @@ -313,59 +284,31 @@ BOOL MakeSurface_File(const char *name, SurfaceID surf_no) return FALSE; } - HANDLE handle = LoadImageA(GetModuleHandleA(NULL), path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); - if (handle == NULL) + SDL_Surface *surface = SDL_LoadBMP(path); + + if (surface == NULL) { PrintBitmapError(path, 1); return FALSE; } - BITMAP bitmap; - GetObjectA(handle, sizeof(BITMAP), &bitmap); + surf[surf_no] = Backend_CreateSurface(surface->w * magnification, surface->h * magnification); - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(DDSURFACEDESC)); - ddsd.dwSize = sizeof(DDSURFACEDESC); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - ddsd.dwWidth = bitmap.bmWidth * magnification; - ddsd.dwHeight = bitmap.bmHeight * magnification; + if (surf[surf_no] == NULL) + { + SDL_FreeSurface(surface); + return FALSE; + } - lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL); - - int src_x = 0; - int src_y = 0; - int src_w = bitmap.bmWidth; - int src_h = bitmap.bmHeight; - - int dst_x = 0; - int dst_y = 0; - int dst_w = bitmap.bmWidth * magnification; - int dst_h = bitmap.bmHeight * magnification; - - HDC hdc = CreateCompatibleDC(NULL); - HGDIOBJ hgdiobj = SelectObject(hdc, handle); - - HDC hdc2; - surf[surf_no]->GetDC(&hdc2); - StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); - surf[surf_no]->ReleaseDC(hdc2); - - SelectObject(hdc, hgdiobj); - DeleteDC(hdc); - - DDCOLORKEY ddcolorkey; - ddcolorkey.dwColorSpaceLowValue = 0; - ddcolorkey.dwColorSpaceHighValue = 0; - - surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); - surf[surf_no]->SetClipper(clipper); - - DeleteObject(handle); + if (!ScaleAndUploadSurface(surface, surf_no)) + { + Backend_FreeSurface(surf[surf_no]); + return FALSE; + } surface_metadata[surf_no].type = SURFACE_SOURCE_FILE; - surface_metadata[surf_no].width = bitmap.bmWidth; - surface_metadata[surf_no].height = bitmap.bmHeight; + surface_metadata[surf_no].width = surface->w; + surface_metadata[surf_no].height = surface->h; surface_metadata[surf_no].bSystem = FALSE; strcpy(surface_metadata[surf_no].name, name); @@ -378,44 +321,30 @@ BOOL ReloadBitmap_Resource(const char *name, SurfaceID surf_no) if (surf_no >= SURFACE_ID_MAX) return FALSE; - HANDLE handle = LoadImageA(GetModuleHandleA(NULL), name, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); - if (handle == NULL) + HRSRC hrscr = FindResourceA(NULL, name, RT_BITMAP); + + if (hrscr == NULL) return FALSE; - BITMAP bitmap; - GetObjectA(handle, sizeof(BITMAP), &bitmap); + size_t size = SizeofResource(NULL, hrscr); + const unsigned char *data = (unsigned char*)LockResource(LoadResource(NULL, hrscr)); - int src_x = 0; - int src_y = 0; - int src_w = bitmap.bmWidth; - int src_h = bitmap.bmHeight; + // The bitmap we get from LockResource is incomplete, so we need to restore its missing header here + unsigned char *bmp_buffer = (unsigned char*)malloc(size + 0xE); - int dst_x = 0; - int dst_y = 0; - int dst_w = bitmap.bmWidth * magnification; - int dst_h = bitmap.bmHeight * magnification; + if (bmp_buffer == NULL) + return FALSE; - HDC hdc = CreateCompatibleDC(NULL); - HGDIOBJ hgdiobj = SelectObject(hdc, handle); + const unsigned char bmp_header[0xE] = {0x42, 0x4D, 0x76, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00}; - HDC hdc2; - surf[surf_no]->GetDC(&hdc2); - StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); - surf[surf_no]->ReleaseDC(hdc2); + memcpy(bmp_buffer, bmp_header, 0xE); + memcpy(bmp_buffer + 0xE, data, size); - SelectObject(hdc, hgdiobj); - DeleteDC(hdc); + SDL_RWops *fp = SDL_RWFromConstMem(bmp_buffer, size + 0xE); + SDL_Surface *surface = SDL_LoadBMP_RW(fp, 1); - DDCOLORKEY ddcolorkey; - ddcolorkey.dwColorSpaceLowValue = 0; - ddcolorkey.dwColorSpaceHighValue = 0; - - surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); - surf[surf_no]->SetClipper(clipper); - -#ifdef FIX_BUGS - DeleteObject(handle); -#endif + if (!ScaleAndUploadSurface(surface, surf_no)) + return FALSE; surface_metadata[surf_no].type = SURFACE_SOURCE_RESOURCE; strcpy(surface_metadata[surf_no].name, name); @@ -445,40 +374,16 @@ BOOL ReloadBitmap_File(const char *name, SurfaceID surf_no) return FALSE; } - HANDLE handle = LoadImageA(GetModuleHandleA(NULL), path, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); - if (handle == NULL) + SDL_Surface *surface = SDL_LoadBMP(path); + + if (surface == NULL) { PrintBitmapError(path, 1); return FALSE; } - BITMAP bitmap; - GetObjectA(handle, sizeof(BITMAP), &bitmap); - - int src_x = 0; - int src_y = 0; - int src_w = bitmap.bmWidth; - int src_h = bitmap.bmHeight; - - int dst_x = 0; - int dst_y = 0; - int dst_w = bitmap.bmWidth * magnification; - int dst_h = bitmap.bmHeight * magnification; - - HDC hdc = CreateCompatibleDC(NULL); - HGDIOBJ hgdiobj = SelectObject(hdc, handle); - - HDC hdc2; - surf[surf_no]->GetDC(&hdc2); - StretchBlt(hdc2, dst_x, dst_y, dst_w, dst_h, hdc, src_x, src_y, src_w, src_h, SRCCOPY); - surf[surf_no]->ReleaseDC(hdc2); - - SelectObject(hdc, hgdiobj); - DeleteDC(hdc); - - // No colour-keying - - DeleteObject(handle); + if (!ScaleAndUploadSurface(surface, surf_no)) + return FALSE; surface_metadata[surf_no].type = SURFACE_SOURCE_FILE; strcpy(surface_metadata[surf_no].name, name); @@ -499,30 +404,14 @@ BOOL MakeSurface_Generic(int bxsize, int bysize, SurfaceID surf_no, BOOL bSystem if (surf[surf_no] != NULL) return FALSE; - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(DDSURFACEDESC)); - ddsd.dwSize = sizeof(DDSURFACEDESC); - ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + surf[surf_no] = Backend_CreateSurface(bxsize * magnification, bysize * magnification); - if (bSystem) - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; - else - ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - - ddsd.dwWidth = bxsize * magnification; - ddsd.dwHeight = bysize * magnification; - - lpDD->CreateSurface(&ddsd, &surf[surf_no], NULL); - - DDCOLORKEY ddcolorkey; - ddcolorkey.dwColorSpaceLowValue = 0; - ddcolorkey.dwColorSpaceHighValue = 0; - - surf[surf_no]->SetColorKey(DDCKEY_SRCBLT, &ddcolorkey); + if (surf[surf_no] == NULL) + return FALSE; surface_metadata[surf_no].type = SURFACE_SOURCE_NONE; - surface_metadata[surf_no].width = ddsd.dwWidth / magnification; - surface_metadata[surf_no].height = ddsd.dwHeight / magnification; + surface_metadata[surf_no].width = bxsize; + surface_metadata[surf_no].height = bysize; if (bSystem) surface_metadata[surf_no].bSystem = TRUE; @@ -536,24 +425,18 @@ BOOL MakeSurface_Generic(int bxsize, int bysize, SurfaceID surf_no, BOOL bSystem void BackupSurface(SurfaceID surf_no, const RECT *rect) { - static DDBLTFX ddbltfx; - - memset(&ddbltfx, 0, sizeof(DDBLTFX)); - ddbltfx.dwSize = sizeof(DDBLTFX); - static RECT scaled_rect; scaled_rect.left = rect->left * magnification; scaled_rect.top = rect->top * magnification; scaled_rect.right = rect->right * magnification; scaled_rect.bottom = rect->bottom * magnification; - surf[surf_no]->Blt(&scaled_rect, backbuffer, &scaled_rect, DDBLT_WAIT, &ddbltfx); + Backend_Blit(framebuffer, &scaled_rect, surf[surf_no], scaled_rect.left, scaled_rect.top, FALSE); } void PutBitmap3(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID surf_no) // Transparency { static RECT src_rect; - static RECT dst_rect; src_rect = *rect; @@ -575,28 +458,17 @@ void PutBitmap3(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID su y = rcView->top; } - dst_rect.left = x; - dst_rect.top = y; - dst_rect.right = x + src_rect.right - src_rect.left; - dst_rect.bottom = y + src_rect.bottom - src_rect.top; - src_rect.left *= magnification; src_rect.top *= magnification; src_rect.right *= magnification; src_rect.bottom *= magnification; - dst_rect.left *= magnification; - dst_rect.top *= magnification; - dst_rect.right *= magnification; - dst_rect.bottom *= magnification; - - backbuffer->Blt(&dst_rect, surf[surf_no], &src_rect, DDBLT_KEYSRC | DDBLT_WAIT, NULL); + Backend_Blit(surf[surf_no], &src_rect, framebuffer, x * magnification, y * magnification, TRUE); } void PutBitmap4(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID surf_no) // No Transparency { static RECT src_rect; - static RECT dst_rect; src_rect = *rect; @@ -618,106 +490,49 @@ void PutBitmap4(const RECT *rcView, int x, int y, const RECT *rect, SurfaceID su y = rcView->top; } - dst_rect.left = x; - dst_rect.top = y; - dst_rect.right = x + src_rect.right - src_rect.left; - dst_rect.bottom = y + src_rect.bottom - src_rect.top; - src_rect.left *= magnification; src_rect.top *= magnification; src_rect.right *= magnification; src_rect.bottom *= magnification; - dst_rect.left *= magnification; - dst_rect.top *= magnification; - dst_rect.right *= magnification; - dst_rect.bottom *= magnification; - - backbuffer->Blt(&dst_rect, surf[surf_no], &src_rect, DDBLT_WAIT, NULL); + Backend_Blit(surf[surf_no], &src_rect, framebuffer, x * magnification, y * magnification, FALSE); } void Surface2Surface(int x, int y, const RECT *rect, int to, int from) { static RECT src_rect; - static RECT dst_rect; src_rect.left = rect->left * magnification; src_rect.top = rect->top * magnification; src_rect.right = rect->right * magnification; src_rect.bottom = rect->bottom * magnification; - dst_rect.left = x; - dst_rect.top = y; - dst_rect.right = x + rect->right - rect->left; - dst_rect.bottom = y + rect->bottom - rect->top; - - dst_rect.left *= magnification; - dst_rect.top *= magnification; - dst_rect.right *= magnification; - dst_rect.bottom *= magnification; - - surf[to]->Blt(&dst_rect, surf[from], &src_rect, DDBLT_KEYSRC | DDBLT_WAIT, NULL); + Backend_Blit(surf[from], &src_rect, surf[to], x * magnification, y * magnification, TRUE); } -// This converts a colour to the 'native' format by writing it -// straight to the framebuffer, and then reading it back unsigned long GetCortBoxColor(COLORREF col) { - HDC hdc; - - if (backbuffer->GetDC(&hdc) != DD_OK) - return 0xFFFFFFFF; - - COLORREF original_colour = GetPixel(hdc, 0, 0); - SetPixel(hdc, 0, 0, col); - backbuffer->ReleaseDC(hdc); - - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(DDSURFACEDESC)); - ddsd.dwSize = sizeof(DDSURFACEDESC); - - if (backbuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) - return 0xFFFFFFFF; - - DWORD native_colour = *(DWORD*)ddsd.lpSurface; - - if (ddsd.ddpfPixelFormat.dwRGBBitCount < 32) - native_colour &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount) - 1; - - backbuffer->Unlock(0); - - if (backbuffer->GetDC(&hdc) != DD_OK) - return 0xFFFFFFFF; - - SetPixel(hdc, 0, 0, original_colour); - backbuffer->ReleaseDC(hdc); - - return native_colour; + // Comes in 00BBGGRR, goes out 00BBGGRR + return col; } void CortBox(const RECT *rect, unsigned long col) { - static DDBLTFX ddbltfx; - memset(&ddbltfx, 0, sizeof(DDBLTFX)); - ddbltfx.dwSize = sizeof(DDBLTFX); - ddbltfx.dwFillColor = col; - static RECT dst_rect; dst_rect.left = rect->left * magnification; dst_rect.top = rect->top * magnification; dst_rect.right = rect->right * magnification; dst_rect.bottom = rect->bottom * magnification; - backbuffer->Blt(&dst_rect, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); + const unsigned char red = col & 0xFF; + const unsigned char green = (col >> 8) & 0xFF; + const unsigned char blue = (col >> 16) & 0xFF; + + Backend_ColourFill(framebuffer, &dst_rect, red, green, blue); } void CortBox2(const RECT *rect, unsigned long col, SurfaceID surf_no) { - static DDBLTFX ddbltfx; - memset(&ddbltfx, 0, sizeof(DDBLTFX)); - ddbltfx.dwSize = sizeof(DDBLTFX); - ddbltfx.dwFillColor = col; - static RECT dst_rect; dst_rect.left = rect->left * magnification; dst_rect.top = rect->top * magnification; @@ -726,9 +541,13 @@ void CortBox2(const RECT *rect, unsigned long col, SurfaceID surf_no) surface_metadata[surf_no].type = SURFACE_SOURCE_NONE; - surf[surf_no]->Blt(&dst_rect, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); -} + const unsigned char red = col & 0xFF; + const unsigned char green = (col >> 8) & 0xFF; + const unsigned char blue = (col >> 16) & 0xFF; + Backend_ColourFill(surf[surf_no], &dst_rect, red, green, blue); +} +/* BOOL DummiedOutLogFunction(int unknown) { char unknown2[0x100]; @@ -807,10 +626,10 @@ int RestoreSurfaces(void) // Guessed function name - this doesn't exist in the L return surfaces_regenerated; } - +*/ // TODO - Inaccurate stack frame void InitTextObject(const char *name) -{ +{/* // Get font size unsigned int width, height; @@ -849,10 +668,10 @@ void InitTextObject(const char *name) if (font == NULL) font = CreateFontA(height, width, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, QUALITY, FIXED_PITCH | FF_DONTCARE, NULL); -} +*/} void PutText(int x, int y, const char *text, unsigned long color) -{ +{/* HDC hdc; backbuffer->GetDC(&hdc); HGDIOBJ hgdiobj = SelectObject(hdc, font); @@ -861,10 +680,10 @@ void PutText(int x, int y, const char *text, unsigned long color) TextOutA(hdc, x * magnification, y * magnification, text, (int)strlen(text)); SelectObject(hdc, hgdiobj); backbuffer->ReleaseDC(hdc); -} +*/} void PutText2(int x, int y, const char *text, unsigned long color, SurfaceID surf_no) -{ +{/* HDC hdc; surf[surf_no]->GetDC(&hdc); HGDIOBJ hgdiobj = SelectObject(hdc, font); @@ -873,9 +692,9 @@ void PutText2(int x, int y, const char *text, unsigned long color, SurfaceID sur TextOutA(hdc, x * magnification, y * magnification, text, (int)strlen(text)); SelectObject(hdc, hgdiobj); surf[surf_no]->ReleaseDC(hdc); -} +*/} void EndTextObject(void) { - DeleteObject(font); +// DeleteObject(font); } diff --git a/src/Draw.h b/src/Draw.h index 8c4b625d..99e707ee 100644 --- a/src/Draw.h +++ b/src/Draw.h @@ -1,5 +1,7 @@ #pragma once +#include "SDL.h" + #include "WindowsWrapper.h" #ifndef RGB @@ -48,10 +50,10 @@ typedef enum SurfaceID SURFACE_ID_MAX = 40 } SurfaceID; -void SetWindowPadding(int width, int height); -BOOL Flip_SystemTask(HWND hWnd); -BOOL StartDirectDraw(HWND hWnd, int lMagnification, int lColourDepth); -void EndDirectDraw(HWND hWnd); +BOOL Flip_SystemTask(void); +SDL_Window* CreateWindow(const char *title, int width, int height); +BOOL StartDirectDraw(SDL_Window *window, int lMagnification); +void EndDirectDraw(void); void ReleaseSurface(SurfaceID s); BOOL MakeSurface_Resource(const char *name, SurfaceID surf_no); BOOL MakeSurface_File(const char *name, SurfaceID surf_no); diff --git a/src/Ending.cpp b/src/Ending.cpp index a1eaf3d7..3ce6b38c 100644 --- a/src/Ending.cpp +++ b/src/Ending.cpp @@ -507,7 +507,7 @@ int Scene_DownIsland(HWND hWnd, int mode) // Draw window PutFramePerSecound(); - if (!Flip_SystemTask(hWnd)) + if (!Flip_SystemTask()) return 0; } diff --git a/src/Escape.cpp b/src/Escape.cpp index fb8cba56..11ed3d1e 100644 --- a/src/Escape.cpp +++ b/src/Escape.cpp @@ -37,7 +37,7 @@ int Call_Escape(HWND hWnd) PutBitmap3(&grcFull, (WINDOW_WIDTH - 208) / 2, (WINDOW_HEIGHT - 16) / 2, &rc, SURFACE_ID_TEXT_BOX); PutFramePerSecound(); - if (!Flip_SystemTask(hWnd)) + if (!Flip_SystemTask()) { // Quit if window is closed gKeyTrg = 0; diff --git a/src/Game.cpp b/src/Game.cpp index 82144322..1bb2e170 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -205,7 +205,7 @@ int ModeOpening(HWND hWnd) PutTextScript(); PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; ++gCounter; @@ -216,7 +216,7 @@ int ModeOpening(HWND hWnd) { CortBox(&grcGame, 0x000000); PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; } return 2; @@ -449,7 +449,7 @@ int ModeTitle(HWND hWnd) PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; } @@ -461,7 +461,7 @@ int ModeTitle(HWND hWnd) { CortBox(&grcGame, 0); PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; } @@ -667,7 +667,7 @@ int ModeAction(HWND hWnd) PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; ++gCounter; diff --git a/src/Main.cpp b/src/Main.cpp index 5ec60a87..cf072a31 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -225,9 +225,7 @@ int main(int argc, char *argv[]) windowHeight = WINDOW_HEIGHT * 2; } - SetWindowPadding(GetSystemMetrics(SM_CXFIXEDFRAME) + 1, GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION) + 1); - - window = SDL_CreateWindow(lpWindowName, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowWidth, windowHeight, 0); + window = CreateWindow(lpWindowName, windowWidth, windowHeight); if (window == NULL) { @@ -242,9 +240,9 @@ int main(int argc, char *argv[]) ghWnd = hWnd; if (conf.display_mode == 1) - StartDirectDraw(hWnd, 0, 0); + StartDirectDraw(window, 0); else - StartDirectDraw(hWnd, 1, 0); + StartDirectDraw(window, 1); break; @@ -255,9 +253,7 @@ int main(int argc, char *argv[]) windowWidth = WINDOW_WIDTH * 2; windowHeight = WINDOW_HEIGHT * 2; - SetWindowPadding(0, 0); - - window = SDL_CreateWindow(lpWindowName, 0, 0, windowWidth, windowHeight, SDL_WINDOW_FULLSCREEN); + window = CreateWindow(lpWindowName, windowWidth, windowHeight); if (window == NULL) { @@ -273,6 +269,7 @@ int main(int argc, char *argv[]) if (hWnd == NULL) { + SDL_DestroyWindow(window); ReleaseMutex(hMutex); return 0; } @@ -293,7 +290,7 @@ int main(int argc, char *argv[]) break; } - StartDirectDraw(ghWnd, 2, depth); + StartDirectDraw(window, 2); bFullscreen = TRUE; break; @@ -317,8 +314,9 @@ int main(int argc, char *argv[]) PutBitmap3(&rcFull, (WINDOW_WIDTH - 64) / 2, (WINDOW_HEIGHT - 8) / 2, &rcLoading, SURFACE_ID_LOADING); // Draw to screen - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) { + SDL_DestroyWindow(window); ReleaseMutex(hMutex); return 1; } @@ -344,8 +342,9 @@ int main(int argc, char *argv[]) // End stuff EndDirectSound(); EndTextObject(); - EndDirectDraw(hWnd); + EndDirectDraw(); + SDL_DestroyWindow(window); ReleaseMutex(hMutex); } diff --git a/src/MiniMap.cpp b/src/MiniMap.cpp index 650bcd68..168b29d8 100644 --- a/src/MiniMap.cpp +++ b/src/MiniMap.cpp @@ -114,7 +114,7 @@ int MiniMapLoop() CortBox(&rcView, 0); PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; } @@ -169,7 +169,7 @@ int MiniMapLoop() PutBitmap3(&grcGame, my_x + rcView.left + 1, my_y + rcView.top + 1, &my_rect, SURFACE_ID_TEXT_BOX); PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; } @@ -199,7 +199,7 @@ int MiniMapLoop() CortBox(&rcView, 0); PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; } diff --git a/src/SelStage.cpp b/src/SelStage.cpp index aa4d3a02..34cbb721 100644 --- a/src/SelStage.cpp +++ b/src/SelStage.cpp @@ -212,7 +212,7 @@ int StageSelectLoop(int *p_event) PutFramePerSecound(); - if (!Flip_SystemTask(ghWnd)) + if (!Flip_SystemTask()) return 0; }