summaryrefslogtreecommitdiff
path: root/src/sars.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sars.c')
-rw-r--r--src/sars.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/sars.c b/src/sars.c
new file mode 100644
index 0000000..bff0796
--- /dev/null
+++ b/src/sars.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2020 - Vito Caputo - <vcaputo@pengaru.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <SDL.h>
+
+#include <play.h>
+#include <stage.h>
+
+#include "clear-node.h"
+#include "glad.h"
+#include "macros.h"
+#include "sars.h"
+
+#define SARS_DEFAULT_WIDTH 800
+#define SARS_DEFAULT_HEIGHT 600
+//#define SARS_WINDOW_FLAGS (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL)
+#define SARS_WINDOW_FLAGS (SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI)
+
+#if 0
+#define SARS_ASPECT_RATIO .7
+#endif
+
+
+void sars_canvas_size(sars_t *sars, int *res_width, int *res_height)
+{
+ assert(sars);
+ assert(res_width);
+ assert(res_height);
+
+ SDL_GL_GetDrawableSize(sars->window, res_width, res_height);
+}
+
+
+void sars_canvas_to_ndc(sars_t *sars, int x, int y, float *res_x, float *res_y)
+{
+ int w, h;
+
+ assert(sars);
+ assert(res_x);
+ assert(res_y);
+
+ sars_canvas_size(sars, &w, &h);
+
+ *res_x = (float)x / (float)w * 2.f - 1.f;
+ *res_y = (1.f - (float)y / (float)h) * 2.f - 1.f;
+}
+
+
+void sars_canvas_from_ndc(sars_t *sars, float x, float y, int *res_x, int *res_y)
+{
+ int w, h;
+
+ assert(sars);
+ assert(res_x);
+ assert(res_y);
+
+ sars_canvas_size(sars, &w, &h);
+
+ *res_x = roundf(x * (float)w * .5f + .5f * (float)w);
+ *res_y = roundf(y * (float)h * .5f + .5f * (float)h);
+}
+
+
+void sars_viewport_size(sars_t *sars, int *res_width, int *res_height)
+{
+ assert(sars);
+ assert(res_width);
+ assert(res_height);
+
+ SDL_GetWindowSize(sars->window, res_width, res_height);
+}
+
+
+void sars_viewport_to_ndc(sars_t *sars, int x, int y, float *res_x, float *res_y)
+{
+ int w, h;
+
+ assert(sars);
+ assert(res_x);
+ assert(res_y);
+
+ sars_viewport_size(sars, &w, &h);
+
+ *res_x = (float)x / (float)w * 2.f - 1.f;
+ *res_y = (1.f - (float)y / (float)h) * 2.f - 1.f;
+}
+
+
+void sars_viewport_from_ndc(sars_t *sars, float x, float y, int *res_x, int *res_y)
+{
+ int w, h;
+
+ assert(sars);
+ assert(res_x);
+ assert(res_y);
+
+ sars_viewport_size(sars, &w, &h);
+
+ *res_x = roundf(x * (float)w * .5f + .5f * (float)w);
+ *res_y = roundf(y * (float)h * .5f + .5f * (float)h);
+}
+
+
+uint32_t sars_viewport_id(sars_t *sars)
+{
+ return SDL_GetWindowID(sars->window);
+}
+
+
+void sars_toggle_fullscreen(sars_t *sars)
+{
+ if (sars->windowed) {
+ if (!SDL_SetWindowFullscreen(sars->window, SDL_WINDOW_FULLSCREEN_DESKTOP))
+ sars->windowed = 0;
+ } else {
+ if (!SDL_SetWindowFullscreen(sars->window, 0))
+ sars->windowed = 1;
+ }
+}
+
+
+static void * sars_init(play_t *play, int argc, char *argv[])
+{
+ sars_t *sars;
+
+ sars = calloc(1, sizeof(sars_t));
+ fatal_if(!sars, "Unable to allocate sars_t");
+
+ sars->stage = stage_new(&(stage_conf_t){.name = "sars", .active = 1, .alpha = 1.f}, NULL, NULL);
+ fatal_if(!sars->stage, "Unable to create new stage");
+
+ (void) clear_node_new(&(stage_conf_t){.parent = sars->stage, .name = "gl-clear-sars", .active = 1});
+
+ sars->window_width = SARS_DEFAULT_WIDTH;
+ sars->window_height = SARS_DEFAULT_HEIGHT;
+
+ if (argc > 1) {
+ /* for now just support --window [WxH] */
+ if (!strcasecmp(argv[1], "--window")) {
+ sars->windowed = 1;
+
+ if (argc > 2)
+ sscanf(argv[2], "%ux%u", &sars->window_width, &sars->window_height);
+ }
+ }
+
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY) < 0,
+ "Unable to set GL core profile attribute");
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2) < 0,
+ "Unable to set GL major version attribute");
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1) < 0,
+ "Unable to set GL minor version attribute");
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) < 0,
+ "Unable to set GL doublebuffer attribute");
+
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8) < 0,
+ "Unable to set GL red size attribute");
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8) < 0,
+ "Unable to set GL green size attribute");
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8) < 0,
+ "Unable to set GL blue size attribute");
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8) < 0, /* this in particular is required for cache-node.c to work w/alpha */
+ "Unable to set GL alpha size attribute");
+
+#define MSAA_RENDER_TARGET
+#ifdef MSAA_RENDER_TARGET
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4) < 0,
+ "Unable to et GL multisample samples attribute");
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) < 0,
+ "Unable to set GL multisample buffers attribute");
+#endif
+
+/* On older SDL versions, this define is missing at compile-time,
+ * but we can just provide it here and still try the sethint call,
+ * just in case the runtime SDL version knows how to handle it.
+ */
+#ifndef SDL_HINT_TOUCH_MOUSE_EVENTS
+#define SDL_HINT_TOUCH_MOUSE_EVENTS "SDL_TOUCH_MOUSE_EVENTS"
+#endif
+
+ warn_if(!SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"),
+ "Unable to suppress synthetic mouse events on touch");
+
+ sars->window = SDL_CreateWindow("Eon",
+ SDL_WINDOWPOS_CENTERED,
+ SDL_WINDOWPOS_CENTERED,
+ sars->window_width, sars->window_height,
+ SARS_WINDOW_FLAGS | (sars->windowed ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP));
+
+ if (!sars->window) {
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0) < 0,
+ "Unable to clear GL multisample samples attribute");
+ fatal_if(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0) < 0,
+ "Unable to clear GL multisample buffers attribute");
+
+ sars->window = SDL_CreateWindow("Eon",
+ SDL_WINDOWPOS_CENTERED,
+ SDL_WINDOWPOS_CENTERED,
+ sars->window_width, sars->window_height,
+ SARS_WINDOW_FLAGS | (sars->windowed ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP));
+
+ fatal_if(!sars->window,
+ "Unable to create SDL window");
+ }
+
+ sars->gl = SDL_GL_CreateContext(sars->window);
+ fatal_if(!sars->gl,
+ "Unable to create GL context");
+
+ fatal_if(SDL_GL_SetSwapInterval(1) < 0,
+ "Unable to enable vsync");
+
+ fatal_if(!gladLoadGL(),
+ "Failed to initialize GLAD OpenGL extension loader");
+
+ //This seems unnecessary now that the game grabs the mouse,
+ //and it's undesirable with clickable UI elements outside the
+ //gameplay - otherwise I'd have to draw a pointer.
+ //SDL_ShowCursor(SDL_DISABLE);
+
+#ifdef MSAA_RENDER_TARGET
+ glEnable(GL_MULTISAMPLE);
+#endif
+ return sars;
+}
+
+
+static void sars_update(play_t *play, void *context)
+{
+ play_context_enter(play, SARS_CONTEXT_HUNGRYCAT);
+}
+
+
+/* XXX: note render and dispatch are public and ignore the passed-in context,
+ * so other contexts can use these as-is for convenience */
+void sars_render(play_t *play, void *context)
+{
+ sars_t *sars = play_context(play, SARS_CONTEXT_SARS);
+
+ if (stage_render(sars->stage, play)) {
+ SDL_GL_SwapWindow(sars->window);
+ } else {
+ SDL_Delay(100); // FIXME: this should be computed
+ }
+}
+
+
+void sars_dispatch(play_t *play, void *context, SDL_Event *event)
+{
+ sars_t *sars = play_context(play, SARS_CONTEXT_SARS);
+
+ if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED) {
+ int w, h;
+
+ /* on highdpi the window size and pixels are decoupled, so ignore what
+ * the event contains and query the canvas size.
+ */
+ sars_canvas_size(sars, &w, &h);
+ glViewport(0, 0, w, h);
+ stage_dirty(sars->stage);
+ }
+}
+
+
+const play_ops_t sars_ops = {
+ .init = sars_init,
+ .update = sars_update,
+// .shutdown = sars_shutdown,
+};
© All Rights Reserved