Fixed an issue with clipping the render rectangle
This commit is contained in:
1 parent
2eb8d83dc0
commit
c1659dcf88
5 files changed
+99
-39
No files matched your search
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include "AssetManager.h"
|
#include "AssetManager.h"
|
||||||
#include "ObjectStore.h"
|
#include "ObjectStore.h"
|
||||||
|
#include "Renderer.h"
|
||||||
#include "SDL_pixels.h"
|
#include "SDL_pixels.h"
|
||||||
#include "SDL_rect.h"
|
|
||||||
#include "Window.h"
|
#include "Window.h"
|
||||||
#include "reusable_ids.h"
|
#include "reusable_ids.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -61,15 +61,16 @@ WindowSize get_window_real_size();
|
|||||||
*/
|
*/
|
||||||
WindowDrawingArea get_window_drawing_area();
|
WindowDrawingArea get_window_drawing_area();
|
||||||
|
|
||||||
void fill_rectangle(float x, float y, float w, float h, SDL_Color color);
|
void fill_rectangle(RenderRect rect, SDL_Color color);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensures that a rendered rectangle is clipped to the drawing area when it is
|
* Ensures that a rendered rectangle is clipped to the drawing area when it is
|
||||||
* smaller than the actual size of the window.
|
* smaller than the actual size of the window.
|
||||||
*/
|
*/
|
||||||
void clip_render_rect_to_drawing_area(SDL_FRect *rect);
|
void clip_source_rect_to_drawing_area(RenderRect *src, RenderRect *dest);
|
||||||
|
|
||||||
void render_texture_asset(AssetID id, float x, float y, float w, float h);
|
RenderRect get_texture_asset_rect(AssetID id);
|
||||||
|
void render_texture_asset(AssetID id, RenderRect *src, RenderRect *dest);
|
||||||
void render_text_with_font_asset(AssetID id, const char *text, float x,
|
void render_text_with_font_asset(AssetID id, const char *text, float x,
|
||||||
float y);
|
float y);
|
||||||
void set_font_asset_size(AssetID id, uint32_t size);
|
void set_font_asset_size(AssetID id, uint32_t size);
|
||||||
|
|||||||
+11
-4
@@ -14,6 +14,13 @@ extern "C" {
|
|||||||
|
|
||||||
typedef struct renderer Renderer;
|
typedef struct renderer Renderer;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float width;
|
||||||
|
float height;
|
||||||
|
} RenderRect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to allocate a Renderer object on the heap.
|
* Attempts to allocate a Renderer object on the heap.
|
||||||
*
|
*
|
||||||
@@ -32,10 +39,10 @@ void get_render_output_size(Renderer *renderer, int32_t *w, int32_t *h);
|
|||||||
void render_clear(const Renderer *renderer, SDL_Color color);
|
void render_clear(const Renderer *renderer, SDL_Color color);
|
||||||
void fill_rect(const Renderer *renderer, SDL_Color color, float x, float y,
|
void fill_rect(const Renderer *renderer, SDL_Color color, float x, float y,
|
||||||
float w, float h);
|
float w, float h);
|
||||||
void render_surface(const Renderer *renderer, SDL_Surface *surface, float x,
|
void render_surface(const Renderer *renderer, SDL_Surface *surface,
|
||||||
float y, float w, float h);
|
const RenderRect *dest);
|
||||||
void render_texture(const Renderer *renderer, SDL_Texture *texture, float x,
|
void render_texture(const Renderer *renderer, SDL_Texture *texture,
|
||||||
float y, float w, float h);
|
const RenderRect *src, const RenderRect *dest);
|
||||||
void swap_buffers(const Renderer *renderer);
|
void swap_buffers(const Renderer *renderer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+61
-24
@@ -213,47 +213,82 @@ WindowDrawingArea get_window_drawing_area() {
|
|||||||
return GameEngine.window.drawing_area;
|
return GameEngine.window.drawing_area;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_rectangle(float x, float y, float w, float h, SDL_Color color) {
|
void fill_rectangle(RenderRect rect, SDL_Color color) {
|
||||||
fill_rect(GameEngine.window.renderer, color, x, y, w, h);
|
fill_rect(GameEngine.window.renderer, color, rect.x, rect.y, rect.width,
|
||||||
|
rect.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clip_render_rect_to_drawing_area(SDL_FRect *rect) {
|
void clip_source_rect_to_drawing_area(RenderRect *src, RenderRect *dest) {
|
||||||
WindowDrawingArea area = get_window_drawing_area();
|
WindowDrawingArea area = get_window_drawing_area();
|
||||||
|
|
||||||
// If the rectangle is completely out of bounds, set its width and height to 0
|
// If the rectangle is completely out of bounds, set its width and height to 0
|
||||||
if (rect->x > area.x + area.width || rect->x + rect->w < area.x ||
|
if (dest->x > area.x + area.width || dest->x + dest->width < area.x ||
|
||||||
rect->y > area.y + area.height || rect->y + rect->h < area.y) {
|
dest->y > area.y + area.height || dest->y + dest->height < area.y) {
|
||||||
rect->w = 0.0f;
|
src->width = 0.0f;
|
||||||
rect->h = 0.0f;
|
src->height = 0.0f;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float x_diff = 0.0f;
|
float x_offset = 0.0f;
|
||||||
float y_diff = 0.0f;
|
float y_offset = 0.0f;
|
||||||
|
float x_clip = 0.0f;
|
||||||
|
float y_clip = 0.0f;
|
||||||
|
|
||||||
// If the rectangle is partially out of the horizontal bounds of the drawing
|
// If the rectangle is partially out of the horizontal bounds of the drawing
|
||||||
// area, calculate how much of its width will be clipped
|
// area, calculate how much of its width will be clipped
|
||||||
if (rect->x < area.x) {
|
if (dest->x < area.x) {
|
||||||
x_diff = area.x - rect->x;
|
// When an object goes out of the left border of the screen, we need to both
|
||||||
rect->x += x_diff;
|
// clip and offset the source and destination rectangles to ensure that the
|
||||||
} else if (rect->x + rect->w > area.x + area.width) {
|
// object is rendered properly
|
||||||
x_diff = (rect->x + rect->w) - (area.x + area.width);
|
x_clip = x_offset = area.x - dest->x;
|
||||||
|
} else if (dest->x + dest->width > area.x + area.width) {
|
||||||
|
x_clip = (dest->x + dest->width) - (area.x + area.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the rectangle is partially out of the vertical bounds of the drawing
|
// If the rectangle is partially out of the vertical bounds of the drawing
|
||||||
// area, calculate how much of its height will be clipped
|
// area, calculate how much of its height will be clipped
|
||||||
if (rect->y < area.y) {
|
if (dest->y < area.y) {
|
||||||
y_diff = area.y - rect->y;
|
// When an object goes out of the top border of the screen, we need to both
|
||||||
rect->y += y_diff;
|
// clip and offset the source and destination rectangles to ensure that the
|
||||||
} else if (rect->y + rect->h > area.y + area.height) {
|
// object is rendered properly
|
||||||
y_diff = (rect->y + rect->h) - (area.y + area.height);
|
y_clip = y_offset = area.y - dest->y;
|
||||||
|
} else if (dest->y + dest->height > area.y + area.height) {
|
||||||
|
y_clip = (dest->y + dest->height) - (area.y + area.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
rect->w -= x_diff;
|
// Offset and clipping of source rectangle needs to be calculated based on the
|
||||||
rect->h -= y_diff;
|
// ratio of the x_clip and y_clip variables to the width and height of the
|
||||||
|
// destination rectangle respectively. This is because the source rectangle's
|
||||||
|
// width and height might be different from the destination's
|
||||||
|
src->x += ((x_offset / dest->width) * src->width);
|
||||||
|
src->y += ((y_offset / dest->height) * src->height);
|
||||||
|
src->width *= 1 - (x_clip / dest->width);
|
||||||
|
src->height *= 1 - (y_clip / dest->height);
|
||||||
|
|
||||||
|
dest->x += x_offset;
|
||||||
|
dest->y += y_offset;
|
||||||
|
dest->width -= x_clip;
|
||||||
|
dest->height -= y_clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_texture_asset(AssetID id, float x, float y, float w, float h) {
|
RenderRect get_texture_asset_rect(AssetID id) {
|
||||||
|
RenderRect rect = {0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
|
|
||||||
|
SDL_Texture *texture = get_texture(GameEngine.asset_manager, id);
|
||||||
|
|
||||||
|
if (texture) {
|
||||||
|
int32_t w = 0;
|
||||||
|
int32_t h = 0;
|
||||||
|
if (SDL_QueryTexture(texture, NULL, NULL, &w, &h) == 0) {
|
||||||
|
rect.width = w;
|
||||||
|
rect.height = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_texture_asset(AssetID id, RenderRect *src, RenderRect *dest) {
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -264,7 +299,7 @@ void render_texture_asset(AssetID id, float x, float y, float w, float h) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
render_texture(GameEngine.window.renderer, texture, x, y, w, h);
|
render_texture(GameEngine.window.renderer, texture, src, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_text_with_font_asset(AssetID id, const char *text, float x,
|
void render_text_with_font_asset(AssetID id, const char *text, float x,
|
||||||
@@ -286,7 +321,9 @@ void render_text_with_font_asset(AssetID id, const char *text, float x,
|
|||||||
int32_t h = 0;
|
int32_t h = 0;
|
||||||
TTF_SizeText(font, text, &w, &h);
|
TTF_SizeText(font, text, &w, &h);
|
||||||
|
|
||||||
render_surface(GameEngine.window.renderer, surface, x, y, w, h);
|
RenderRect rect = {x, y, w, h};
|
||||||
|
|
||||||
|
render_surface(GameEngine.window.renderer, surface, &rect);
|
||||||
|
|
||||||
SDL_FreeSurface(surface);
|
SDL_FreeSurface(surface);
|
||||||
surface = NULL;
|
surface = NULL;
|
||||||
|
|||||||
+16
-7
@@ -58,8 +58,8 @@ void fill_rect(const Renderer *renderer, SDL_Color color, float x, float y,
|
|||||||
SDL_RenderFillRectF(renderer->SDL_base_renderer, &dest);
|
SDL_RenderFillRectF(renderer->SDL_base_renderer, &dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_surface(const Renderer *renderer, SDL_Surface *surface, float x,
|
void render_surface(const Renderer *renderer, SDL_Surface *surface,
|
||||||
float y, float w, float h) {
|
const RenderRect *dest) {
|
||||||
SDL_Texture *texture =
|
SDL_Texture *texture =
|
||||||
SDL_CreateTextureFromSurface(renderer->SDL_base_renderer, surface);
|
SDL_CreateTextureFromSurface(renderer->SDL_base_renderer, surface);
|
||||||
|
|
||||||
@@ -67,23 +67,32 @@ void render_surface(const Renderer *renderer, SDL_Surface *surface, float x,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
render_texture(renderer, texture, x, y, w, h);
|
render_texture(renderer, texture, NULL, dest);
|
||||||
|
|
||||||
SDL_DestroyTexture(texture);
|
SDL_DestroyTexture(texture);
|
||||||
texture = NULL;
|
texture = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void render_texture(const Renderer *renderer, SDL_Texture *texture, float x,
|
void render_texture(const Renderer *renderer, SDL_Texture *texture,
|
||||||
float y, float w, float h) {
|
const RenderRect *src, const RenderRect *dest) {
|
||||||
if (!renderer || !texture) {
|
if (!renderer || !texture) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_FRect dest = {x, y, w, h};
|
SDL_Rect src_frect;
|
||||||
|
if (src) {
|
||||||
|
src_frect.x = src->x;
|
||||||
|
src_frect.y = src->y;
|
||||||
|
src_frect.w = src->width;
|
||||||
|
src_frect.h = src->height;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_FRect dest_frect = {dest->x, dest->y, dest->width, dest->height};
|
||||||
|
|
||||||
// TODO (Abdelrahman): Look into using the SDL_RenderCopyExF instead to
|
// TODO (Abdelrahman): Look into using the SDL_RenderCopyExF instead to
|
||||||
// support rotating the texture
|
// support rotating the texture
|
||||||
SDL_RenderCopyF(renderer->SDL_base_renderer, texture, NULL, &dest);
|
SDL_RenderCopyF(renderer->SDL_base_renderer, texture, &src_frect,
|
||||||
|
&dest_frect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap_buffers(const Renderer *renderer) {
|
void swap_buffers(const Renderer *renderer) {
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ bool init_window(Window *wnd, const char *title, WindowSize size,
|
|||||||
|
|
||||||
if (strcmp(current_platform, "Android") == 0 ||
|
if (strcmp(current_platform, "Android") == 0 ||
|
||||||
strcmp(current_platform, "iOS") == 0) {
|
strcmp(current_platform, "iOS") == 0) {
|
||||||
|
// Mobile platforms should always be full screen
|
||||||
|
//
|
||||||
|
// TODO (Abdelrahman): Test to see how to make this work when in landscape
|
||||||
|
// orientation, as it didn't seem to work when tested on Android
|
||||||
|
window_flags |= SDL_WINDOW_FULLSCREEN;
|
||||||
|
|
||||||
// Calculate the mobile orientation based on the user-defined width and
|
// Calculate the mobile orientation based on the user-defined width and
|
||||||
// height
|
// height
|
||||||
MobileOrientation orientation;
|
MobileOrientation orientation;
|
||||||
|
|||||||
Reference in new issue
Block a user