diff --git a/include/GameEngine.h b/include/GameEngine.h index 32f738d..19da54e 100644 --- a/include/GameEngine.h +++ b/include/GameEngine.h @@ -3,8 +3,8 @@ #include "AssetManager.h" #include "ObjectStore.h" +#include "Renderer.h" #include "SDL_pixels.h" -#include "SDL_rect.h" #include "Window.h" #include "reusable_ids.h" #include @@ -61,15 +61,16 @@ WindowSize get_window_real_size(); */ 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 * 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, float y); void set_font_asset_size(AssetID id, uint32_t size); diff --git a/include/Renderer.h b/include/Renderer.h index 073a9a0..75631eb 100644 --- a/include/Renderer.h +++ b/include/Renderer.h @@ -14,6 +14,13 @@ extern "C" { typedef struct renderer Renderer; +typedef struct { + float x; + float y; + float width; + float height; +} RenderRect; + /** * 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 fill_rect(const Renderer *renderer, SDL_Color color, float x, float y, float w, float h); -void render_surface(const Renderer *renderer, SDL_Surface *surface, float x, - float y, float w, float h); -void render_texture(const Renderer *renderer, SDL_Texture *texture, float x, - float y, float w, float h); +void render_surface(const Renderer *renderer, SDL_Surface *surface, + const RenderRect *dest); +void render_texture(const Renderer *renderer, SDL_Texture *texture, + const RenderRect *src, const RenderRect *dest); void swap_buffers(const Renderer *renderer); /** diff --git a/src/GameEngine.c b/src/GameEngine.c index 75ecd77..48c911e 100644 --- a/src/GameEngine.c +++ b/src/GameEngine.c @@ -213,47 +213,82 @@ WindowDrawingArea get_window_drawing_area() { return GameEngine.window.drawing_area; } -void fill_rectangle(float x, float y, float w, float h, SDL_Color color) { - fill_rect(GameEngine.window.renderer, color, x, y, w, h); +void fill_rectangle(RenderRect rect, SDL_Color color) { + 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(); // 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 || - rect->y > area.y + area.height || rect->y + rect->h < area.y) { - rect->w = 0.0f; - rect->h = 0.0f; + if (dest->x > area.x + area.width || dest->x + dest->width < area.x || + dest->y > area.y + area.height || dest->y + dest->height < area.y) { + src->width = 0.0f; + src->height = 0.0f; return; } - float x_diff = 0.0f; - float y_diff = 0.0f; + float x_offset = 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 // area, calculate how much of its width will be clipped - if (rect->x < area.x) { - x_diff = area.x - rect->x; - rect->x += x_diff; - } else if (rect->x + rect->w > area.x + area.width) { - x_diff = (rect->x + rect->w) - (area.x + area.width); + if (dest->x < area.x) { + // When an object goes out of the left border of the screen, we need to both + // clip and offset the source and destination rectangles to ensure that the + // object is rendered properly + 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 // area, calculate how much of its height will be clipped - if (rect->y < area.y) { - y_diff = area.y - rect->y; - rect->y += y_diff; - } else if (rect->y + rect->h > area.y + area.height) { - y_diff = (rect->y + rect->h) - (area.y + area.height); + if (dest->y < area.y) { + // When an object goes out of the top border of the screen, we need to both + // clip and offset the source and destination rectangles to ensure that the + // object is rendered properly + 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; - rect->h -= y_diff; + // Offset and clipping of source rectangle needs to be calculated based on the + // 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) { return; } @@ -264,7 +299,7 @@ void render_texture_asset(AssetID id, float x, float y, float w, float h) { 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, @@ -286,7 +321,9 @@ void render_text_with_font_asset(AssetID id, const char *text, float x, int32_t h = 0; 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); surface = NULL; diff --git a/src/Renderer.c b/src/Renderer.c index da830bc..eda2016 100644 --- a/src/Renderer.c +++ b/src/Renderer.c @@ -58,8 +58,8 @@ void fill_rect(const Renderer *renderer, SDL_Color color, float x, float y, SDL_RenderFillRectF(renderer->SDL_base_renderer, &dest); } -void render_surface(const Renderer *renderer, SDL_Surface *surface, float x, - float y, float w, float h) { +void render_surface(const Renderer *renderer, SDL_Surface *surface, + const RenderRect *dest) { SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer->SDL_base_renderer, surface); @@ -67,23 +67,32 @@ void render_surface(const Renderer *renderer, SDL_Surface *surface, float x, return; } - render_texture(renderer, texture, x, y, w, h); + render_texture(renderer, texture, NULL, dest); SDL_DestroyTexture(texture); texture = NULL; } -void render_texture(const Renderer *renderer, SDL_Texture *texture, float x, - float y, float w, float h) { +void render_texture(const Renderer *renderer, SDL_Texture *texture, + const RenderRect *src, const RenderRect *dest) { if (!renderer || !texture) { 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 // 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) { diff --git a/src/Window.c b/src/Window.c index 4cd41a8..585eae1 100644 --- a/src/Window.c +++ b/src/Window.c @@ -29,6 +29,12 @@ bool init_window(Window *wnd, const char *title, WindowSize size, if (strcmp(current_platform, "Android") == 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 // height MobileOrientation orientation;