Added support for desktop full screen with pillarboxing and letterboxing
and started adding some comments to the code
This commit is contained in:
1 parent
ffaa6e5ae7
commit
e110b1f2fd
10 files changed
+351
-77
No files matched your search
@@ -22,14 +22,38 @@ typedef enum {
|
|||||||
} AssetType;
|
} AssetType;
|
||||||
typedef struct asset_manager AssetManager;
|
typedef struct asset_manager AssetManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to allocate an AssetManager object on the heap.
|
||||||
|
*
|
||||||
|
* Returns the pointer to the object when it succeeds, or NULL if it fails.
|
||||||
|
*/
|
||||||
AssetManager *create_asset_manager();
|
AssetManager *create_asset_manager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to load an asset to the manager from a file path.
|
||||||
|
*
|
||||||
|
* Returns the AssetID on success or an INVALID_ID in the case of failure.
|
||||||
|
*/
|
||||||
AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
||||||
AssetType type, Renderer *renderer);
|
AssetType type, Renderer *renderer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an asset from the manager using its ID.
|
||||||
|
*
|
||||||
|
* Does nothing if the ID is not valid.
|
||||||
|
*/
|
||||||
void remove_asset_from_manager(AssetManager *am, AssetID *id_ptr);
|
void remove_asset_from_manager(AssetManager *am, AssetID *id_ptr);
|
||||||
|
|
||||||
SDL_Texture *get_texture(AssetManager *am, AssetID id);
|
SDL_Texture *get_texture(AssetManager *am, AssetID id);
|
||||||
TTF_Font *get_font(AssetManager *am, AssetID id);
|
TTF_Font *get_font(AssetManager *am, AssetID id);
|
||||||
Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id);
|
Mix_Chunk *get_audio_chunk(AssetManager *am, AssetID id);
|
||||||
Mix_Music *get_music(AssetManager *am, AssetID id);
|
Mix_Music *get_music(AssetManager *am, AssetID id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the memory allocated to the AssetManager object and performs the
|
||||||
|
* necessary cleanup to free all memory that were allocated to the loaded
|
||||||
|
* assets.
|
||||||
|
*/
|
||||||
void destroy_asset_manager(AssetManager **am);
|
void destroy_asset_manager(AssetManager **am);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
+55
-4
@@ -4,6 +4,7 @@
|
|||||||
#include "AssetManager.h"
|
#include "AssetManager.h"
|
||||||
#include "ObjectStore.h"
|
#include "ObjectStore.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>
|
||||||
@@ -13,20 +14,68 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif // !__cplusplus
|
#endif // !__cplusplus
|
||||||
|
|
||||||
|
// GENERAL ENGINE API
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialises the game engine. Returns true on success and false on failure.
|
||||||
|
*
|
||||||
|
* The audio_tracks parameter determines how many audio tracks to be allocated.
|
||||||
|
* Pass 0 if you want to allocate the default number.
|
||||||
|
*/
|
||||||
bool init_engine(const char *game_name, WindowSize window_size,
|
bool init_engine(const char *game_name, WindowSize window_size,
|
||||||
SDL_Color window_background_color, bool full_screen,
|
SDL_Color window_background_color, bool full_screen,
|
||||||
uint8_t audio_tracks);
|
uint8_t audio_tracks);
|
||||||
|
|
||||||
bool game_running();
|
bool game_running();
|
||||||
WindowSize get_window_defined_size();
|
void close_engine();
|
||||||
WindowSize get_window_drawable_size();
|
// END GENERAL ENGINE API
|
||||||
|
|
||||||
|
// ASSET MANAGEMENT API
|
||||||
ObjectID add_object(void *object, EventHandlerPtr eh, UpdateFuncPtr uf,
|
ObjectID add_object(void *object, EventHandlerPtr eh, UpdateFuncPtr uf,
|
||||||
RenderFuncPtr rf);
|
RenderFuncPtr rf);
|
||||||
void remove_object(ObjectID *id);
|
void remove_object(ObjectID *id);
|
||||||
|
// END ASSET MANAGEMENT API
|
||||||
|
|
||||||
|
// ASSET MANAGEMENT API
|
||||||
AssetID load_asset(const char *path, AssetType type);
|
AssetID load_asset(const char *path, AssetType type);
|
||||||
|
void close_asset(AssetID *id);
|
||||||
|
// END ASSET MANAGEMENT API
|
||||||
|
|
||||||
|
// RENDERING API
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the user-defined window size or the screen size when in full screen.
|
||||||
|
*/
|
||||||
|
WindowSize get_window_defined_size();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the actual window size which can be different from the user-defined
|
||||||
|
* size or the screen size if the window is on a display that supports high DPI.
|
||||||
|
*/
|
||||||
|
WindowSize get_window_real_size();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the valid drawing area which can be a portion of the screen when
|
||||||
|
* running in full screen mode and the width to height ratio of the user-defined
|
||||||
|
* window size is different from the width to height ratio of the screen.
|
||||||
|
*/
|
||||||
|
WindowDrawingArea get_window_drawing_area();
|
||||||
|
|
||||||
|
void fill_rectangle(float x, float y, float w, float h, 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 render_texture_asset(AssetID id, float x, float y, float w, float h);
|
void render_texture_asset(AssetID id, float x, float y, float w, float h);
|
||||||
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);
|
||||||
|
// END RENDERING API
|
||||||
|
|
||||||
|
// AUDIO API
|
||||||
int8_t play_audio_asset(AssetID id, int16_t loops, bool fade_in,
|
int8_t play_audio_asset(AssetID id, int16_t loops, bool fade_in,
|
||||||
uint32_t fade_length_in_ms);
|
uint32_t fade_length_in_ms);
|
||||||
void pause_audio_asset_on_track(AssetID id, uint8_t track);
|
void pause_audio_asset_on_track(AssetID id, uint8_t track);
|
||||||
@@ -56,11 +105,13 @@ void stop_playing_music();
|
|||||||
void fade_out_playing_music(uint32_t fade_length_in_ms);
|
void fade_out_playing_music(uint32_t fade_length_in_ms);
|
||||||
void set_playing_music_volume(int8_t volume);
|
void set_playing_music_volume(int8_t volume);
|
||||||
bool is_music_playing();
|
bool is_music_playing();
|
||||||
void close_asset(AssetID *id);
|
// END AUDIO API
|
||||||
|
|
||||||
|
// GAME LOOP API
|
||||||
void handle_events();
|
void handle_events();
|
||||||
void update();
|
void update();
|
||||||
void render();
|
void render();
|
||||||
void close_engine();
|
// END GAME LOOP API
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,36 @@ typedef void (*RenderFuncPtr)(void *object);
|
|||||||
|
|
||||||
typedef struct object_store ObjectStore;
|
typedef struct object_store ObjectStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to allocate an ObjectStore object on the heap.
|
||||||
|
*
|
||||||
|
* Returns the pointer to the object when it succeeds, or NULL if it fails.
|
||||||
|
*/
|
||||||
ObjectStore *create_object_store();
|
ObjectStore *create_object_store();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to add an object to the store.
|
||||||
|
*
|
||||||
|
* Returns the ObjectID on success or an INVALID_ID in the case of failure.
|
||||||
|
*/
|
||||||
ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
||||||
UpdateFuncPtr uf, RenderFuncPtr rf);
|
UpdateFuncPtr uf, RenderFuncPtr rf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an object from the store using its ID.
|
||||||
|
*
|
||||||
|
* Does nothing if the ID is not valid.
|
||||||
|
*/
|
||||||
void remove_object_from_store(ObjectStore *os, ObjectID *id_ptr);
|
void remove_object_from_store(ObjectStore *os, ObjectID *id_ptr);
|
||||||
|
|
||||||
void handle_all_objects_events(ObjectStore *os, const SDL_Event *event);
|
void handle_all_objects_events(ObjectStore *os, const SDL_Event *event);
|
||||||
void update_all_objects(ObjectStore *os, float delta);
|
void update_all_objects(ObjectStore *os, float delta);
|
||||||
void render_all_objects(ObjectStore *os);
|
void render_all_objects(ObjectStore *os);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the memory allocated to the ObjectStore object and performs the
|
||||||
|
* necessary cleanup.
|
||||||
|
*/
|
||||||
void destroy_object_store(ObjectStore **os);
|
void destroy_object_store(ObjectStore **os);
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
|
|||||||
+28
-3
@@ -14,16 +14,41 @@ extern "C" {
|
|||||||
|
|
||||||
typedef struct renderer Renderer;
|
typedef struct renderer Renderer;
|
||||||
|
|
||||||
Renderer *create_renderer();
|
/**
|
||||||
bool init_renderer(Renderer *renderer, SDL_Window *window);
|
* Attempts to allocate a Renderer object on the heap.
|
||||||
void get_drawable_size(Renderer *renderer, int32_t *w, int32_t *h);
|
*
|
||||||
|
* Returns the pointer to the object when it succeeds, or NULL if it fails.
|
||||||
|
*/
|
||||||
|
Renderer *create_renderer(SDL_Window *window);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the valid drawable area that the renderer can use.
|
||||||
|
*
|
||||||
|
* Useful when rendering on screens that support high DPI since the drawable
|
||||||
|
* area is usually bigger than the user-defined size.
|
||||||
|
*/
|
||||||
|
void get_render_output_size(Renderer *renderer, int32_t *w, int32_t *h);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to load an SDL_Texture from a file path.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the object if it succeeds or NULL when it fails.
|
||||||
|
*/
|
||||||
SDL_Texture *load_texture(const Renderer *renderer, const char *path);
|
SDL_Texture *load_texture(const Renderer *renderer, const char *path);
|
||||||
|
|
||||||
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,
|
||||||
|
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 x,
|
||||||
float y, float w, float h);
|
float y, float w, float h);
|
||||||
void render_texture(const Renderer *renderer, SDL_Texture *texture, float x,
|
void render_texture(const Renderer *renderer, SDL_Texture *texture, float x,
|
||||||
float y, float w, float h);
|
float y, float w, float h);
|
||||||
void swap_buffers(const Renderer *renderer);
|
void swap_buffers(const Renderer *renderer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees the memory allocated to the Renderer object and performs the
|
||||||
|
* necessary cleanup.
|
||||||
|
*/
|
||||||
void destroy_renderer(Renderer **renderer);
|
void destroy_renderer(Renderer **renderer);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
+16
-1
@@ -16,12 +16,27 @@ typedef struct window_size {
|
|||||||
int32_t height;
|
int32_t height;
|
||||||
} WindowSize;
|
} WindowSize;
|
||||||
|
|
||||||
|
typedef struct drawing_area {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float width;
|
||||||
|
float height;
|
||||||
|
} WindowDrawingArea;
|
||||||
|
|
||||||
typedef struct window {
|
typedef struct window {
|
||||||
|
// We need to store the defined size because the coordinates of the mouse
|
||||||
|
// cursor are calculated according to it. In the case of displays that support
|
||||||
|
// high DPI, this creates a problem, because the mouse coordinates retrieved
|
||||||
|
// from an SDL_Event won't work with the actual window size. By storing the
|
||||||
|
// defined size of the window, this allows us to convert the mouse coordinates
|
||||||
|
// to a ratio of the defined size, then multiply that ratio by the real size.
|
||||||
WindowSize defined_size;
|
WindowSize defined_size;
|
||||||
WindowSize drawable_size;
|
WindowSize real_size;
|
||||||
|
WindowDrawingArea drawing_area;
|
||||||
Renderer *renderer;
|
Renderer *renderer;
|
||||||
SDL_Window *SDL_base_window;
|
SDL_Window *SDL_base_window;
|
||||||
SDL_Color background_color;
|
SDL_Color background_color;
|
||||||
|
bool full_screen;
|
||||||
} Window;
|
} Window;
|
||||||
|
|
||||||
bool init_window(Window *wnd, const char *title, WindowSize size,
|
bool init_window(Window *wnd, const char *title, WindowSize size,
|
||||||
|
|||||||
+22
-1
@@ -46,6 +46,10 @@ struct asset_manager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
size_t hash_path(const char *path) {
|
size_t hash_path(const char *path) {
|
||||||
|
/**
|
||||||
|
* Converts a string into a numerical index using a simple hashing algorithm
|
||||||
|
*/
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
for (size_t j = 0; path[j]; ++j) {
|
for (size_t j = 0; path[j]; ++j) {
|
||||||
@@ -125,6 +129,11 @@ void remove_id_node(IDNodeList *node_list, AssetID id) {
|
|||||||
|
|
||||||
AssetID get_asset_id_from_id_node(AssetManager *am, IDNodeList *node_list,
|
AssetID get_asset_id_from_id_node(AssetManager *am, IDNodeList *node_list,
|
||||||
const char *path) {
|
const char *path) {
|
||||||
|
/**
|
||||||
|
* Checks to see if an asset with the same path exists and returns the ID of
|
||||||
|
* that asset if it exists, or an INVALID_ID otherwise
|
||||||
|
*/
|
||||||
|
|
||||||
if (node_list->node_count == 0) {
|
if (node_list->node_count == 0) {
|
||||||
return INVALID_ID;
|
return INVALID_ID;
|
||||||
}
|
}
|
||||||
@@ -184,9 +193,14 @@ AssetID load_asset_to_manager(AssetManager *am, const char *path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
++(am->user_counter[existing_id]);
|
++(am->user_counter[existing_id]);
|
||||||
|
|
||||||
return existing_id;
|
return existing_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (am->count + 1 == MAX_ASSET_COUNT && am->deleted_count == 0) {
|
||||||
|
return INVALID_ID;
|
||||||
|
}
|
||||||
|
|
||||||
Asset asset = {};
|
Asset asset = {};
|
||||||
bool loaded = true;
|
bool loaded = true;
|
||||||
|
|
||||||
@@ -363,7 +377,14 @@ void destroy_asset_manager(AssetManager **am) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < (*am)->count; ++i) {
|
// TODO (Abdelrahman): Figure out if there is a better way to remove all of
|
||||||
|
// the existing assets without having to loop for the maximum number of
|
||||||
|
// assets allowed.
|
||||||
|
for (size_t i = 0; i < MAX_ASSET_COUNT; ++i) {
|
||||||
|
if (!(*am)->assets[i].path) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
(*am)->user_counter[i] = 0;
|
(*am)->user_counter[i] = 0;
|
||||||
|
|
||||||
size_t hash_index = hash_path((*am)->assets[i].path);
|
size_t hash_index = hash_path((*am)->assets[i].path);
|
||||||
|
|||||||
+82
-39
@@ -18,6 +18,7 @@
|
|||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "engine_build_config.h"
|
#include "engine_build_config.h"
|
||||||
#include "reusable_ids.h"
|
#include "reusable_ids.h"
|
||||||
|
#include <SDL2/SDL_pixels.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@@ -130,10 +131,32 @@ bool init_engine(const char *game_name, WindowSize window_size,
|
|||||||
|
|
||||||
bool game_running() { return GameEngine.running; }
|
bool game_running() { return GameEngine.running; }
|
||||||
|
|
||||||
WindowSize get_window_defined_size() { return GameEngine.window.defined_size; }
|
void close_engine() {
|
||||||
|
destroy_asset_manager(&(GameEngine.asset_manager));
|
||||||
|
|
||||||
WindowSize get_window_drawable_size() {
|
destroy_object_store(&(GameEngine.object_store));
|
||||||
return GameEngine.window.drawable_size;
|
|
||||||
|
destroy_window(&(GameEngine.window));
|
||||||
|
|
||||||
|
GameEngine.last_time = 0.0f;
|
||||||
|
|
||||||
|
GameEngine.delta = 0.0f;
|
||||||
|
|
||||||
|
GameEngine.running = false;
|
||||||
|
|
||||||
|
Mix_CloseAudio();
|
||||||
|
|
||||||
|
Mix_Quit();
|
||||||
|
|
||||||
|
TTF_Quit();
|
||||||
|
|
||||||
|
IMG_Quit();
|
||||||
|
|
||||||
|
SDL_Quit();
|
||||||
|
|
||||||
|
#ifdef DEBUG_ENGINE
|
||||||
|
printf("Game closed successfully\n");
|
||||||
|
#endif /* DEBUG_ENGINE */
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectID add_object(void *object, EventHandlerPtr event_handler,
|
ObjectID add_object(void *object, EventHandlerPtr event_handler,
|
||||||
@@ -162,6 +185,62 @@ AssetID load_asset(const char *path, AssetType type) {
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void close_asset(AssetID *id) {
|
||||||
|
if (*id < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_asset_from_manager(GameEngine.asset_manager, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
WindowSize get_window_defined_size() { return GameEngine.window.defined_size; }
|
||||||
|
|
||||||
|
WindowSize get_window_real_size() { return GameEngine.window.real_size; }
|
||||||
|
|
||||||
|
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 clip_render_rect_to_drawing_area(SDL_FRect *rect) {
|
||||||
|
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;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float x_diff = 0.0f;
|
||||||
|
float y_diff = 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 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
rect->w -= x_diff;
|
||||||
|
rect->h -= y_diff;
|
||||||
|
}
|
||||||
|
|
||||||
void render_texture_asset(AssetID id, float x, float y, float w, float h) {
|
void render_texture_asset(AssetID id, float x, float y, float w, float h) {
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
return;
|
return;
|
||||||
@@ -529,14 +608,6 @@ void set_playing_music_volume(int8_t volume) { Mix_VolumeMusic(volume); }
|
|||||||
|
|
||||||
bool is_music_playing() { return Mix_PlayingMusic(); }
|
bool is_music_playing() { return Mix_PlayingMusic(); }
|
||||||
|
|
||||||
void close_asset(AssetID *id) {
|
|
||||||
if (*id < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_asset_from_manager(GameEngine.asset_manager, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_events() {
|
void handle_events() {
|
||||||
if (!(GameEngine.running)) {
|
if (!(GameEngine.running)) {
|
||||||
return;
|
return;
|
||||||
@@ -586,31 +657,3 @@ void render() {
|
|||||||
|
|
||||||
swap_render_buffers(&(GameEngine.window));
|
swap_render_buffers(&(GameEngine.window));
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_engine() {
|
|
||||||
destroy_asset_manager(&(GameEngine.asset_manager));
|
|
||||||
|
|
||||||
destroy_object_store(&(GameEngine.object_store));
|
|
||||||
|
|
||||||
destroy_window(&(GameEngine.window));
|
|
||||||
|
|
||||||
GameEngine.last_time = 0.0f;
|
|
||||||
|
|
||||||
GameEngine.delta = 0.0f;
|
|
||||||
|
|
||||||
GameEngine.running = false;
|
|
||||||
|
|
||||||
Mix_CloseAudio();
|
|
||||||
|
|
||||||
Mix_Quit();
|
|
||||||
|
|
||||||
TTF_Quit();
|
|
||||||
|
|
||||||
IMG_Quit();
|
|
||||||
|
|
||||||
SDL_Quit();
|
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
|
||||||
printf("Game closed successfully\n");
|
|
||||||
#endif /* DEBUG_ENGINE */
|
|
||||||
}
|
|
||||||
+18
-10
@@ -41,9 +41,22 @@ ObjectStore *create_object_store() {
|
|||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool object_exists(ObjectStore *os, void *object) {
|
||||||
|
// This is a crude implementation for checking that an object has already
|
||||||
|
// been added.
|
||||||
|
// TODO (Abdelrahman): Figure out if there is a better way of doing this
|
||||||
|
for (size_t i = 0; i < MAX_OBJ_COUNT; ++i) {
|
||||||
|
if (object == os->object_ptrs[i]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
||||||
UpdateFuncPtr uf, RenderFuncPtr rf) {
|
UpdateFuncPtr uf, RenderFuncPtr rf) {
|
||||||
if (!os || !object ||
|
if (!os || !object || object_exists(os, object) ||
|
||||||
(os->count + 1 == MAX_OBJ_COUNT && os->deleted_count == 0)) {
|
(os->count + 1 == MAX_OBJ_COUNT && os->deleted_count == 0)) {
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
printf("Failed to add object\n");
|
printf("Failed to add object\n");
|
||||||
@@ -52,14 +65,6 @@ ObjectID add_object_to_store(ObjectStore *os, void *object, EventHandlerPtr eh,
|
|||||||
return INVALID_ID;
|
return INVALID_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (Abdelrahman): Need to figure out a way to check that the object
|
|
||||||
// hasn't already been added to the store. If it has been added before, the
|
|
||||||
// function should return -1 indicating an error to ensure that there aren't
|
|
||||||
// two references to the same object without the user being aware that they
|
|
||||||
// refer to the same thing. If the user intentionally copies the ID of one
|
|
||||||
// object, then it would be their responsibility to make sure they don't
|
|
||||||
// delete the object using one of the IDs, then try to use it with the other.
|
|
||||||
|
|
||||||
ObjectID id;
|
ObjectID id;
|
||||||
|
|
||||||
if (os->deleted_count > 0) {
|
if (os->deleted_count > 0) {
|
||||||
@@ -141,7 +146,10 @@ void destroy_object_store(ObjectStore **os) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < (*os)->count; ++i) {
|
// TODO (Abdelrahman): Figure out if there is a better way to remove all of
|
||||||
|
// the existing objects without having to loop for the maximum number of
|
||||||
|
// objects allowed.
|
||||||
|
for (size_t i = 0; i < MAX_OBJ_COUNT; ++i) {
|
||||||
(*os)->object_ptrs[i] = NULL;
|
(*os)->object_ptrs[i] = NULL;
|
||||||
(*os)->event_handlers[i] = NULL;
|
(*os)->event_handlers[i] = NULL;
|
||||||
(*os)->update_funcs[i] = NULL;
|
(*os)->update_funcs[i] = NULL;
|
||||||
|
|||||||
+20
-11
@@ -15,24 +15,24 @@ struct renderer {
|
|||||||
SDL_Renderer *SDL_base_renderer;
|
SDL_Renderer *SDL_base_renderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
Renderer *create_renderer() { return (Renderer *)malloc(sizeof(Renderer)); }
|
Renderer *create_renderer(SDL_Window *window) {
|
||||||
|
Renderer *renderer = (Renderer *)malloc(sizeof(Renderer));
|
||||||
bool init_renderer(Renderer *renderer, SDL_Window *window) {
|
if (!renderer) {
|
||||||
if (!renderer || !window) {
|
return NULL;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer->SDL_base_renderer = SDL_CreateRenderer(
|
renderer->SDL_base_renderer = SDL_CreateRenderer(
|
||||||
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||||
|
if (!(renderer->SDL_base_renderer)) {
|
||||||
|
destroy_renderer(&renderer);
|
||||||
|
|
||||||
// Technically speaking, I believe it should be possible to just return
|
return NULL;
|
||||||
// the pointer. However, to make sure that everything is clear, I am
|
}
|
||||||
// performing a test that returns true or false based on whether the
|
|
||||||
// pointer was initialised or not.
|
return renderer;
|
||||||
return renderer->SDL_base_renderer ? true : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_drawable_size(Renderer *renderer, int32_t *w, int32_t *h) {
|
void get_render_output_size(Renderer *renderer, int32_t *w, int32_t *h) {
|
||||||
SDL_GetRendererOutputSize(renderer->SDL_base_renderer, w, h);
|
SDL_GetRendererOutputSize(renderer->SDL_base_renderer, w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +47,15 @@ void render_clear(const Renderer *renderer, SDL_Color color) {
|
|||||||
SDL_RenderClear(renderer->SDL_base_renderer);
|
SDL_RenderClear(renderer->SDL_base_renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fill_rect(const Renderer *renderer, SDL_Color color, float x, float y,
|
||||||
|
float w, float h) {
|
||||||
|
SDL_FRect dest = {x, y, w, h};
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(renderer->SDL_base_renderer, color.r, color.g, color.b,
|
||||||
|
color.a);
|
||||||
|
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 x,
|
||||||
float y, float w, float h) {
|
float y, float w, float h) {
|
||||||
SDL_Texture *texture =
|
SDL_Texture *texture =
|
||||||
|
|||||||
+63
-8
@@ -4,8 +4,10 @@
|
|||||||
#include "engine_build_config.h"
|
#include "engine_build_config.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
|
#include <stdio.h>
|
||||||
#endif /* DEBUG_ENGINE */
|
#endif /* DEBUG_ENGINE */
|
||||||
|
|
||||||
bool init_window(Window *wnd, const char *title, WindowSize size,
|
bool init_window(Window *wnd, const char *title, WindowSize size,
|
||||||
@@ -32,22 +34,62 @@ bool init_window(Window *wnd, const char *title, WindowSize size,
|
|||||||
wnd->defined_size.height = size.height;
|
wnd->defined_size.height = size.height;
|
||||||
|
|
||||||
wnd->background_color = color;
|
wnd->background_color = color;
|
||||||
|
wnd->full_screen = full_screen;
|
||||||
|
|
||||||
wnd->renderer = create_renderer();
|
wnd->renderer = create_renderer(wnd->SDL_base_window);
|
||||||
|
|
||||||
if (!wnd->renderer || !init_renderer(wnd->renderer, wnd->SDL_base_window)) {
|
if (!wnd->renderer) {
|
||||||
destroy_window(wnd);
|
destroy_window(wnd);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_drawable_size(wnd->renderer, &(wnd->drawable_size.width),
|
get_render_output_size(wnd->renderer, &(wnd->real_size.width),
|
||||||
&(wnd->drawable_size.height));
|
&(wnd->real_size.height));
|
||||||
|
|
||||||
|
wnd->drawing_area.x = 0;
|
||||||
|
wnd->drawing_area.y = 0;
|
||||||
|
wnd->drawing_area.width = wnd->real_size.width;
|
||||||
|
wnd->drawing_area.height = wnd->real_size.height;
|
||||||
|
|
||||||
|
if (full_screen) {
|
||||||
|
// Fit the window into the screen when running in full screen mode on
|
||||||
|
// a non-mobile platform. Mobile platforms will be handled differently
|
||||||
|
|
||||||
|
float window_size_ratio =
|
||||||
|
(float)wnd->defined_size.width / (float)wnd->defined_size.height;
|
||||||
|
|
||||||
|
// Fit the drawing area size to the smallest dimension of the screen and
|
||||||
|
// make sure the drawing area is centered
|
||||||
|
if (wnd->real_size.height <= wnd->real_size.width) {
|
||||||
|
wnd->drawing_area.width =
|
||||||
|
(int32_t)(window_size_ratio * wnd->real_size.height);
|
||||||
|
wnd->drawing_area.x =
|
||||||
|
0.0f + ((wnd->real_size.width - wnd->drawing_area.width) / 2.0f);
|
||||||
|
} else {
|
||||||
|
wnd->drawing_area.height =
|
||||||
|
(int32_t)((float)wnd->real_size.width / window_size_ratio);
|
||||||
|
wnd->drawing_area.y =
|
||||||
|
0.0f + ((wnd->real_size.height - wnd->drawing_area.height) / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the defined size, because in full screen mode, it would be equal
|
||||||
|
// to the screen dimensions
|
||||||
|
SDL_DisplayMode mode;
|
||||||
|
if (SDL_GetWindowDisplayMode(wnd->SDL_base_window, &mode) != 0) {
|
||||||
|
destroy_window(wnd);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wnd->defined_size.width = mode.w;
|
||||||
|
wnd->defined_size.height = mode.h;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
printf("Renderer initialised successfully\n");
|
printf("Renderer initialised successfully\n");
|
||||||
printf("Window initialised successfully with width %d and height %d\n",
|
printf("Window initialised successfully with width %d and height %d\n",
|
||||||
wnd->drawable_size.width, wnd->drawable_size.height);
|
wnd->real_size.width, wnd->real_size.height);
|
||||||
#endif /* DEBUG_ENGINE */
|
#endif /* DEBUG_ENGINE */
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -58,7 +100,18 @@ void clear_window(const Window *wnd) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
render_clear(wnd->renderer, wnd->background_color);
|
if (wnd->full_screen) {
|
||||||
|
// When rendering in full screen on a non-mobile platform, we fill the
|
||||||
|
// entire screen with black, then fill an area that fits the window
|
||||||
|
// dimensions with the user-defined backgroud color of the window
|
||||||
|
|
||||||
|
render_clear(wnd->renderer, (SDL_Color){0, 0, 0, 255});
|
||||||
|
fill_rect(wnd->renderer, wnd->background_color, wnd->drawing_area.x,
|
||||||
|
wnd->drawing_area.y, wnd->drawing_area.width,
|
||||||
|
wnd->drawing_area.height);
|
||||||
|
} else {
|
||||||
|
render_clear(wnd->renderer, wnd->background_color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap_render_buffers(const Window *wnd) {
|
void swap_render_buffers(const Window *wnd) {
|
||||||
@@ -82,8 +135,10 @@ void destroy_window(Window *wnd) {
|
|||||||
SDL_DestroyWindow(wnd->SDL_base_window);
|
SDL_DestroyWindow(wnd->SDL_base_window);
|
||||||
wnd->SDL_base_window = NULL;
|
wnd->SDL_base_window = NULL;
|
||||||
|
|
||||||
|
wnd->full_screen = false;
|
||||||
wnd->defined_size = (WindowSize){0, 0};
|
wnd->defined_size = (WindowSize){0, 0};
|
||||||
wnd->drawable_size = (WindowSize){0, 0};
|
wnd->real_size = (WindowSize){0, 0};
|
||||||
|
wnd->drawing_area = (WindowDrawingArea){0.0f, 0.0f, 0.0f, 0.0f};
|
||||||
wnd->background_color = (SDL_Color){0, 0, 0, 255};
|
wnd->background_color = (SDL_Color){0, 0, 0, 255};
|
||||||
|
|
||||||
#ifdef DEBUG_ENGINE
|
#ifdef DEBUG_ENGINE
|
||||||
|
|||||||
Reference in new issue
Block a user