summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2021-12-25 22:01:57 -0800
committerVito Caputo <vcaputo@pengaru.com>2021-12-25 22:01:57 -0800
commit189eac273ba14c8ca0d22b31182b030ccc4c7756 (patch)
treec49ac8c15404cb68ae4ccb4cf2a2ba0f7417c705
parent8da03aff8bca547bb83f1b049a65232f03123d5a (diff)
*: introduce a projection matrix and winmodesrev3
The bulk of this is mechanical wiring up of a projection_x to all the nodes. But this also introduces maintenance of the projection_x, with aspect-ratio preservation in two of the modes: WINDOWED and FULLSCREEN, with the previously default stretched-to-fill fullscreen mode now relegated to a third FILLSCREEN winmode. The default at startup is now an aspect ratio-preserving windowed mode. Simply press the 'f' key at any time to cycle through them. This was mostly done in sars to provide a source-available test for reproducing a fullscreen SDL2 bug I filed @ https://github.com/libsdl-org/SDL/issues/5139 Otherwise it's pretty silly to bother with doing anything on sars... but it is a handy little mule for such things.
-rw-r--r--src/adult-node.c4
-rw-r--r--src/adult-node.h2
-rw-r--r--src/baby-node.c4
-rw-r--r--src/baby-node.h2
-rw-r--r--src/digit-node.c4
-rw-r--r--src/digit-node.h2
-rw-r--r--src/game.c22
-rw-r--r--src/hungrycat-node.c4
-rw-r--r--src/hungrycat-node.h2
-rw-r--r--src/hungrycat.c2
-rw-r--r--src/plasma-node.c12
-rw-r--r--src/plasma-node.h3
-rw-r--r--src/sars.c98
-rw-r--r--src/sars.h13
-rw-r--r--src/tex-node.c10
-rw-r--r--src/tex-node.h4
-rw-r--r--src/tex.c12
-rw-r--r--src/tex.h2
-rw-r--r--src/tv-node.c4
-rw-r--r--src/tv-node.h2
-rw-r--r--src/virus-node.c4
-rw-r--r--src/virus-node.h2
22 files changed, 152 insertions, 62 deletions
diff --git a/src/adult-node.c b/src/adult-node.c
index f314715..d3cdaf7 100644
--- a/src/adult-node.c
+++ b/src/adult-node.c
@@ -23,10 +23,10 @@
static tex_t *adult_tex;
-stage_t * adult_node_new(stage_conf_t *conf, m4f_t *model_x)
+stage_t * adult_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x)
{
if (!adult_tex)
adult_tex = tex_new(gfx_adult.width, gfx_adult.height, gfx_adult.pixel_data);
- return tex_node_new_tex(conf, adult_tex, model_x);
+ return tex_node_new_tex(conf, adult_tex, projection_x, model_x);
}
diff --git a/src/adult-node.h b/src/adult-node.h
index 151014f..848a92d 100644
--- a/src/adult-node.h
+++ b/src/adult-node.h
@@ -20,6 +20,6 @@
typedef struct stage_conf_t stage_conf_t;
typedef struct m4f_t m4f_t;
-stage_t * adult_node_new(stage_conf_t *conf, m4f_t *model_x);
+stage_t * adult_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x);
#endif
diff --git a/src/baby-node.c b/src/baby-node.c
index 8f49670..c7befca 100644
--- a/src/baby-node.c
+++ b/src/baby-node.c
@@ -23,10 +23,10 @@
static tex_t *baby_tex;
-stage_t * baby_node_new(stage_conf_t *conf, m4f_t *model_x)
+stage_t * baby_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x)
{
if (!baby_tex)
baby_tex = tex_new(gfx_baby.width, gfx_baby.height, gfx_baby.pixel_data);
- return tex_node_new_tex(conf, baby_tex, model_x);
+ return tex_node_new_tex(conf, baby_tex, projection_x, model_x);
}
diff --git a/src/baby-node.h b/src/baby-node.h
index f6cc02e..0eba576 100644
--- a/src/baby-node.h
+++ b/src/baby-node.h
@@ -20,6 +20,6 @@
typedef struct stage_conf_t stage_conf_t;
typedef struct m4f_t m4f_t;
-stage_t * baby_node_new(stage_conf_t *conf, m4f_t *model_x);
+stage_t * baby_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x);
#endif
diff --git a/src/digit-node.c b/src/digit-node.c
index a5e2795..8d970e2 100644
--- a/src/digit-node.c
+++ b/src/digit-node.c
@@ -49,12 +49,12 @@ static tex_t *digits_tex[10];
#define DIGIT_WIDTH 184
#define DIGIT_HEIGHT 288
-stage_t * digit_node_new(stage_conf_t *conf, unsigned digit, m4f_t *model_x)
+stage_t * digit_node_new(stage_conf_t *conf, unsigned digit, m4f_t *projection_x, m4f_t *model_x)
{
assert(digit < 10);
if (!digits_tex[digit])
digits_tex[digit] = tex_new(DIGIT_WIDTH, DIGIT_HEIGHT, digits_pixels[digit]);
- return tex_node_new_tex(conf, digits_tex[digit], model_x);
+ return tex_node_new_tex(conf, digits_tex[digit], projection_x, model_x);
}
diff --git a/src/digit-node.h b/src/digit-node.h
index 9e686de..fd94bdd 100644
--- a/src/digit-node.h
+++ b/src/digit-node.h
@@ -20,6 +20,6 @@
typedef struct stage_conf_t stage_conf_t;
typedef struct m4f_t m4f_t;
-stage_t * digit_node_new(stage_conf_t *conf, unsigned digit, m4f_t *model_x);
+stage_t * digit_node_new(stage_conf_t *conf, unsigned digit, m4f_t *projection_x, m4f_t *model_x);
#endif
diff --git a/src/game.c b/src/game.c
index 5bbf007..e938298 100644
--- a/src/game.c
+++ b/src/game.c
@@ -124,6 +124,7 @@ union entity_t {
typedef struct game_t {
game_state_t state;
+ sars_t *sars;
stage_t *stage;
stage_t *game_node;
stage_t *babies_node;
@@ -179,7 +180,7 @@ static adult_t * adult_new(game_t *game, stage_t *parent)
fatal_if(!adult, "unale to allocate adult_t");
adult->entity.type = ENTITY_TYPE_ADULT;
- adult->entity.node = adult_node_new(&(stage_conf_t){ .parent = parent, .name = "adult", .layer = 3, .alpha = 1.f }, &adult->entity.model_x);
+ adult->entity.node = adult_node_new(&(stage_conf_t){ .parent = parent, .name = "adult", .layer = 3, .alpha = 1.f }, &game->sars->projection_x, &adult->entity.model_x);
adult->entity.scale = GAME_ADULT_SCALE;
entity_update_x(game, &adult->entity);
@@ -195,7 +196,7 @@ static baby_t * baby_new(game_t *game, stage_t *parent)
fatal_if(!baby, "unale to allocate baby_t");
baby->entity.type = ENTITY_TYPE_BABY;
- baby->entity.node = baby_node_new(&(stage_conf_t){ .parent = parent, .name = "baby", .active = 1, .alpha = 1.f }, &baby->entity.model_x);
+ baby->entity.node = baby_node_new(&(stage_conf_t){ .parent = parent, .name = "baby", .active = 1, .alpha = 1.f }, &game->sars->projection_x, &baby->entity.model_x);
baby->entity.scale = GAME_BABY_SCALE;
baby->entity.position.x = randf();
baby->entity.position.y = randf();
@@ -213,7 +214,7 @@ static tv_t * tv_new(game_t *game, stage_t *parent)
fatal_if(!tv, "unale to allocate tv_t");
tv->entity.type = ENTITY_TYPE_TV;
- tv->entity.node = tv_node_new(&(stage_conf_t){ .parent = parent, .name = "tv", .layer = 1, .alpha = 1.f }, &tv->entity.model_x);
+ tv->entity.node = tv_node_new(&(stage_conf_t){ .parent = parent, .name = "tv", .layer = 1, .alpha = 1.f }, &game->sars->projection_x, &tv->entity.model_x);
tv->entity.scale = GAME_TV_SCALE;
entity_update_x(game, &tv->entity);
@@ -236,7 +237,7 @@ static virus_t * virus_new(game_t *game, stage_t *parent)
fatal_if(!virus, "unale to allocate virus_t");
virus->entity.type = ENTITY_TYPE_VIRUS;
- virus->entity.node = virus_node_new(&(stage_conf_t){ .parent = parent, .name = "virus", .alpha = 1.f }, &virus->entity.model_x);
+ virus->entity.node = virus_node_new(&(stage_conf_t){ .parent = parent, .name = "virus", .alpha = 1.f }, &game->sars->projection_x, &virus->entity.model_x);
virus->entity.scale = GAME_VIRUS_SCALE;
randomize_virus(virus);
entity_update_x(game, &virus->entity);
@@ -265,7 +266,7 @@ static ix2_search_status_t virus_search(void *cb_context, ix2_object_t *ix2_obje
switch (entity->any.type) {
case ENTITY_TYPE_BABY:
/* convert baby into inanimate virus (off the viruses array) */
- (void) virus_node_new(&(stage_conf_t){ .stage = entity->any.node, .replace = 1, .name = "baby-virus", .active = 1, .alpha = 1.f }, &entity->any.model_x);
+ (void) virus_node_new(&(stage_conf_t){ .stage = entity->any.node, .replace = 1, .name = "baby-virus", .active = 1, .alpha = 1.f }, &search->game->sars->projection_x, &entity->any.model_x);
sfx_play(sfx.baby_infected);
entity->any.type = ENTITY_TYPE_VIRUS;
@@ -277,7 +278,7 @@ static ix2_search_status_t virus_search(void *cb_context, ix2_object_t *ix2_obje
case ENTITY_TYPE_ADULT:
/* convert adult into inanimate virus (off the viruses array) */
- (void) virus_node_new(&(stage_conf_t){ .stage = entity->any.node, .replace = 1, .name = "adult-virus", .active = 1, .alpha = 1.f }, &entity->any.model_x);
+ (void) virus_node_new(&(stage_conf_t){ .stage = entity->any.node, .replace = 1, .name = "adult-virus", .active = 1, .alpha = 1.f }, &search->game->sars->projection_x, &entity->any.model_x);
sfx_play(sfx.adult_infected);
search->game->state = GAME_STATE_OVER;
return IX2_SEARCH_STOP_HIT;
@@ -370,11 +371,11 @@ static ix2_search_status_t adult_search(void *cb_context, ix2_object_t *ix2_obje
return IX2_SEARCH_MORE_MISS;
/* convert adult into inanimate virus (off the viruses array) */
- (void) virus_node_new(&(stage_conf_t){ .stage = game->adult->entity.node, .replace = 1, .name = "adult-virus", .active = 1, .alpha = 1.f }, &game->adult->entity.model_x);
+ (void) virus_node_new(&(stage_conf_t){ .stage = game->adult->entity.node, .replace = 1, .name = "adult-virus", .active = 1, .alpha = 1.f }, &game->sars->projection_x, &game->adult->entity.model_x);
sfx_play(sfx.adult_infected);
if (game->adult->holding) {
- (void) virus_node_new(&(stage_conf_t){ .stage = game->adult->holding->any.node, .replace = 1, .name = "baby-virus", .active = 1, .alpha = 1.f }, &game->adult->holding->any.model_x);
+ (void) virus_node_new(&(stage_conf_t){ .stage = game->adult->holding->any.node, .replace = 1, .name = "baby-virus", .active = 1, .alpha = 1.f }, &game->sars->projection_x, &game->adult->holding->any.model_x);
sfx_play(sfx.baby_infected);
}
game->state = GAME_STATE_OVER;
@@ -483,7 +484,7 @@ static void show_score(game_t *game)
for (unsigned i = 1000000000, pos = 0; i > 0; score %= i, i /= 10, pos++) {
unsigned v = score / i;
- digit_node_new(&(stage_conf_t){ .parent = game->score_node, .name = "score-digit", .active = 1, .alpha = 1.f }, v, &game->score_digits_x[pos]);
+ digit_node_new(&(stage_conf_t){ .parent = game->score_node, .name = "score-digit", .active = 1, .alpha = 1.f }, v, &game->sars->projection_x, &game->score_digits_x[pos]);
}
stage_set_active(game->score_node, 1);
@@ -500,8 +501,9 @@ static void * game_init(play_t *play, int argc, char *argv[])
game = calloc(1, sizeof(game_t));
fatal_if(!game, "Unable to allocate game_t");
+ game->sars = sars;
game->stage = sars->stage;
- game->plasma_node = plasma_node_new(&(stage_conf_t){ .parent = sars->stage, .name = "plasma", .alpha = 1 });
+ game->plasma_node = plasma_node_new(&(stage_conf_t){ .parent = sars->stage, .name = "plasma", .alpha = 1 }, &sars->projection_x);
game->ix2 = ix2_new(NULL, 4, 4, 1 /* increase for nested searches */);
diff --git a/src/hungrycat-node.c b/src/hungrycat-node.c
index da78ed9..b880eda 100644
--- a/src/hungrycat-node.c
+++ b/src/hungrycat-node.c
@@ -21,7 +21,7 @@
#include "tex-node.h"
-stage_t * hungrycat_node_new(stage_conf_t *conf, m4f_t *model_x)
+stage_t * hungrycat_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x)
{
- return tex_node_new_mem(conf, gfx_hungrycat.width, gfx_hungrycat.height, gfx_hungrycat.pixel_data, model_x);
+ return tex_node_new_mem(conf, gfx_hungrycat.width, gfx_hungrycat.height, gfx_hungrycat.pixel_data, projection_x, model_x);
}
diff --git a/src/hungrycat-node.h b/src/hungrycat-node.h
index 8c5839f..31ba133 100644
--- a/src/hungrycat-node.h
+++ b/src/hungrycat-node.h
@@ -20,6 +20,6 @@
typedef struct stage_conf_t stage_conf_t;
typedef struct m4f_t m4f_t;
-stage_t * hungrycat_node_new(stage_conf_t *conf, m4f_t *model_x);
+stage_t * hungrycat_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x);
#endif
diff --git a/src/hungrycat.c b/src/hungrycat.c
index bae9c10..8457d8a 100644
--- a/src/hungrycat.c
+++ b/src/hungrycat.c
@@ -57,7 +57,7 @@ static void * hungrycat_init(play_t *play, int argc, char *argv[])
hungrycat = calloc(1, sizeof(hungrycat_t));
fatal_if(!hungrycat, "Unable to allocate hungrycat_t");
- hungrycat->node = hungrycat_node_new(&(stage_conf_t){ .parent = sars->stage, .name = "hungrycat", .active = 1 }, &hungrycat->model_x);
+ hungrycat->node = hungrycat_node_new(&(stage_conf_t){ .parent = sars->stage, .name = "hungrycat", .active = 1 }, &sars->projection_x, &hungrycat->model_x);
fatal_if(!hungrycat->node, "Unable to create hungrycat->node");
hungrycat->model_x = m4f_identity();
diff --git a/src/plasma-node.c b/src/plasma-node.c
index 1bc0e40..1eb4c7a 100644
--- a/src/plasma-node.c
+++ b/src/plasma-node.c
@@ -22,19 +22,21 @@
#include "glad.h"
#include "plasma-node.h"
#include "shader-node.h"
+#include "m4f.h"
static const char *plasma_vs = ""
"#version 120\n"
+ "uniform mat4 projection_x;"
+
"attribute vec3 vertex;"
"attribute vec2 texcoord;"
"void main()"
"{"
" gl_TexCoord[0].xy = texcoord;"
- //" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
- " gl_Position = vec4(vertex, 1.f);"
+ " gl_Position = projection_x * vec4(vertex, 1.f);"
"}"
"";
@@ -78,16 +80,18 @@ static void plasma_uniforms(void *uniforms_ctxt, void *render_ctxt, unsigned n_u
glUniform1f(uniforms[0], alpha);
glUniform1f(uniforms[1], play_ticks(play, PLAY_TICKS_TIMER0) * .001f); // FIXME KLUDGE ALERT
+ glUniformMatrix4fv(uniforms[2], 1, GL_FALSE, &model_x->m[0][0]);
}
/* create plasma rendering stage */
-stage_t * plasma_node_new(const stage_conf_t *conf)
+stage_t * plasma_node_new(const stage_conf_t *conf, m4f_t *projection_x)
{
- return shader_node_new_src(conf, plasma_vs, plasma_fs, NULL, plasma_uniforms, NULL, 2,
+ return shader_node_new_src(conf, plasma_vs, plasma_fs, projection_x, plasma_uniforms, NULL, 3,
(const char *[]){
"alpha",
"time",
+ "projection_x",
}
);
}
diff --git a/src/plasma-node.h b/src/plasma-node.h
index 1607ece..2c52431 100644
--- a/src/plasma-node.h
+++ b/src/plasma-node.h
@@ -17,9 +17,10 @@
#ifndef _PLASMA_NODE_H
#define _PLASMA_NODE_H
+typedef struct m4f_t m4f_t;
typedef struct stage_t stage_t;
typedef struct stage_conf_t stage_conf_t;
-stage_t * plasma_node_new(const stage_conf_t *conf);
+stage_t * plasma_node_new(const stage_conf_t *conf, m4f_t *projection_x);
#endif
diff --git a/src/sars.c b/src/sars.c
index 6d866e9..6960f7e 100644
--- a/src/sars.c
+++ b/src/sars.c
@@ -21,18 +21,14 @@
#include "clear-node.h"
#include "glad.h"
+#include "m4f-3dx.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)
{
@@ -120,15 +116,78 @@ uint32_t sars_viewport_id(sars_t *sars)
}
-void sars_toggle_fullscreen(sars_t *sars)
+/* produce a boxed transformation matrix for the current screen/window dimensions */
+static m4f_t sars_boxed_projection_x(sars_t *sars)
{
- if (sars->windowed) {
- if (!SDL_SetWindowFullscreen(sars->window, SDL_WINDOW_FULLSCREEN_DESKTOP))
- sars->windowed = 0;
+ static const float desired_ratio = (float)SARS_DEFAULT_WIDTH / (float)SARS_DEFAULT_HEIGHT;
+ v3f_t scale = { .x = 1.f, .y = 1.f, .z = 1.f };
+ float display_ratio;
+ int w, h;
+
+ sars_viewport_size(sars, &w, &h);
+ assert(w > 0 && h > 0);
+
+ display_ratio = (float)w / (float)h;
+
+ if (desired_ratio <= display_ratio) {
+ /* display is equal to or wider than desired, "pillarbox" / X-padded */
+ scale.x = (float)h * desired_ratio / (float)w;
} else {
- if (!SDL_SetWindowFullscreen(sars->window, 0))
- sars->windowed = 1;
+ /* display is taller than desired, "letterbox" / Y-padded */
+ scale.y = (float)w * (1.f / desired_ratio) / (float)h;
+ }
+
+ return m4f_scale(NULL, &scale);
+}
+
+
+static void sars_update_projection_x(sars_t *sars)
+{
+ assert(sars);
+
+ if (sars->winmode == SARS_WINMODE_FILLSCREEN)
+ sars->projection_x = m4f_identity();
+ else
+ sars->projection_x = sars_boxed_projection_x(sars);
+}
+
+
+sars_winmode_t sars_winmode_set(sars_t *sars, sars_winmode_t winmode)
+{
+ assert(sars);
+
+ if (sars->winmode == winmode)
+ return sars->winmode;
+
+ switch (winmode) {
+ case SARS_WINMODE_WINDOW:
+ if (SDL_SetWindowFullscreen(sars->window, 0))
+ return sars->winmode;
+ break;
+
+ case SARS_WINMODE_FULLSCREEN:
+ if (sars->winmode == SARS_WINMODE_WINDOW) {
+ if (SDL_SetWindowFullscreen(sars->window, SDL_WINDOW_FULLSCREEN_DESKTOP))
+ return sars->winmode;
+ }
+ break;
+
+ case SARS_WINMODE_FILLSCREEN:
+ if (sars->winmode == SARS_WINMODE_WINDOW) {
+ if (SDL_SetWindowFullscreen(sars->window, SDL_WINDOW_FULLSCREEN_DESKTOP))
+ return sars->winmode;
+ }
+ break;
+
+ default:
+ assert(0);
}
+
+ sars->winmode = winmode;
+
+ sars_update_projection_x(sars);
+
+ return sars->winmode;
}
@@ -145,16 +204,17 @@ static void * sars_init(play_t *play, int argc, char *argv[])
(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;
+ sars->window_height = SARS_DEFAULT_HEIGHT;
if (argc > 1) {
/* for now just support --window [WxH] */
if (!strcasecmp(argv[1], "--window")) {
- sars->windowed = 1;
+ sars->winmode = SARS_WINMODE_WINDOW; /* this is kinda redundant since we default to windowed now */
if (argc > 2)
sscanf(argv[2], "%ux%u", &sars->window_width, &sars->window_height);
}
+ /* TODO: add --fullscreen? */
}
fatal_if(SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY) < 0,
@@ -198,7 +258,7 @@ static void * sars_init(play_t *play, int argc, char *argv[])
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
sars->window_width, sars->window_height,
- SARS_WINDOW_FLAGS | (sars->windowed ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP));
+ SARS_WINDOW_FLAGS | (sars->winmode == SARS_WINMODE_WINDOW ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP));
if (!sars->window) {
fatal_if(SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0) < 0,
@@ -210,7 +270,7 @@ static void * sars_init(play_t *play, int argc, char *argv[])
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
sars->window_width, sars->window_height,
- SARS_WINDOW_FLAGS | (sars->windowed ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP));
+ SARS_WINDOW_FLAGS | (sars->winmode == SARS_WINMODE_WINDOW ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP));
fatal_if(!sars->window,
"Unable to create SDL window");
@@ -234,6 +294,9 @@ static void * sars_init(play_t *play, int argc, char *argv[])
#ifdef MSAA_RENDER_TARGET
glEnable(GL_MULTISAMPLE);
#endif
+
+ sars_update_projection_x(sars);
+
return sars;
}
@@ -270,8 +333,13 @@ void sars_dispatch(play_t *play, void *context, SDL_Event *event)
*/
sars_canvas_size(sars, &w, &h);
glViewport(0, 0, w, h);
+ sars_update_projection_x(sars);
stage_dirty(sars->stage);
}
+
+ /* cycle fullscreen/windowed winmodes */
+ if (event->type == SDL_KEYDOWN && event->key.keysym.sym == SDLK_f)
+ sars_winmode_set(sars, (sars->winmode + 1) % SARS_WINMODE_CNT);
}
diff --git a/src/sars.h b/src/sars.h
index 39675e5..734e016 100644
--- a/src/sars.h
+++ b/src/sars.h
@@ -30,12 +30,21 @@ typedef enum sars_context_t {
SARS_CONTEXT_CNT
} sars_context_t;
+typedef enum sars_winmode_t {
+ SARS_WINMODE_WINDOW, /* windowed in the ideal aspect ratio (may be letterboxed if resized or --window WxH) */
+ SARS_WINMODE_FULLSCREEN, /* fullscreened, in the ideal aspect ratio (likely letterboxed) */
+ SARS_WINMODE_FILLSCREEN, /* fullscreened, in the screen's aspect ratio (likely stretched) */
+ SARS_WINMODE_CNT
+} sars_winmode_t;
+
typedef struct sars_t {
SDL_Window *window;
SDL_GLContext *gl;
stage_t *stage;
unsigned window_width, window_height;
- unsigned windowed:1;
+ sars_winmode_t winmode;
+
+ m4f_t projection_x;
} sars_t;
void sars_canvas_size(sars_t *sars, int *res_width, int *res_height);
@@ -45,8 +54,8 @@ void sars_viewport_size(sars_t *sars, int *res_width, int *res_height);
void sars_viewport_to_ndc(sars_t *sars, int x, int y, float *res_x, float *res_y);
void sars_viewport_from_ndc(sars_t *sars, float x, float y, int *res_x, int *res_y);
uint32_t sars_viewport_id(sars_t *sars);
-void sars_toggle_fullscreen(sars_t *sars);
void sars_render(play_t *play, void *context);
void sars_dispatch(play_t *play, void *context, SDL_Event *event);
+sars_winmode_t sars_winmode_set(sars_t *sars, sars_winmode_t winmode);
#endif
diff --git a/src/tex-node.c b/src/tex-node.c
index 6d049ca..a3e0830 100644
--- a/src/tex-node.c
+++ b/src/tex-node.c
@@ -32,6 +32,7 @@
typedef struct tex_node_t {
tex_t *tex;
+ m4f_t *projection_x;
m4f_t *model_x;
} tex_node_t;
@@ -44,7 +45,7 @@ static void tex_node_render(const stage_t *stage, void *object, float alpha, voi
assert(stage);
assert(tex_node);
- tex_render(tex_node->tex, alpha, tex_node->model_x);
+ tex_render(tex_node->tex, alpha, tex_node->projection_x, tex_node->model_x);
}
@@ -65,7 +66,7 @@ static const stage_ops_t tex_node_ops = {
/* retun a tex node from a reusable refcounted tex instance */
-stage_t * tex_node_new_tex(stage_conf_t *conf, tex_t *tex, m4f_t *model_x)
+stage_t * tex_node_new_tex(stage_conf_t *conf, tex_t *tex, m4f_t *projection_x, m4f_t *model_x)
{
tex_node_t *tex_node;
stage_t *s;
@@ -79,6 +80,7 @@ stage_t * tex_node_new_tex(stage_conf_t *conf, tex_t *tex, m4f_t *model_x)
fatal_if(!s, "Unable to create stage \"%s\"", conf->name);
tex_node->tex = tex_ref(tex);
+ tex_node->projection_x = projection_x;
tex_node->model_x = model_x;
return s;
@@ -89,10 +91,10 @@ stage_t * tex_node_new_tex(stage_conf_t *conf, tex_t *tex, m4f_t *model_x)
/* return a tex node from a pix array
* the pixels are used in-place and no duplicate is made.
*/
-stage_t * tex_node_new_mem(stage_conf_t *conf, int width, int height, const unsigned char *buf, m4f_t *model_x)
+stage_t * tex_node_new_mem(stage_conf_t *conf, int width, int height, const unsigned char *buf, m4f_t *projection_x, m4f_t *model_x)
{
tex_t *tex = tex_new(width, height, buf);
- stage_t *stage = tex_node_new_tex(conf, tex_new(width, height, buf), model_x);
+ stage_t *stage = tex_node_new_tex(conf, tex_new(width, height, buf), projection_x, model_x);
tex_free(tex);
diff --git a/src/tex-node.h b/src/tex-node.h
index 59c731b..d9a7f3f 100644
--- a/src/tex-node.h
+++ b/src/tex-node.h
@@ -21,7 +21,7 @@ typedef struct m4f_t m4f_t;
typedef struct stage_t stage_t;
typedef struct tex_t tex_t;
-stage_t * tex_node_new_tex(stage_conf_t *conf, tex_t *tex, m4f_t *model_x);
-stage_t * tex_node_new_mem(stage_conf_t *conf, int width, int height, const unsigned char *buf, m4f_t *model_x);
+stage_t * tex_node_new_tex(stage_conf_t *conf, tex_t *tex, m4f_t *projection_x, m4f_t *model_x);
+stage_t * tex_node_new_mem(stage_conf_t *conf, int width, int height, const unsigned char *buf, m4f_t *projection_x, m4f_t *model_x);
#endif
diff --git a/src/tex.c b/src/tex.c
index b67af17..af110f0 100644
--- a/src/tex.c
+++ b/src/tex.c
@@ -54,6 +54,7 @@ static const char *tex_vs = ""
"#version 120\n"
"uniform mat4 model_x;"
+ "uniform mat4 projection_x;"
"attribute vec3 vertex;"
"attribute vec2 texcoord;"
@@ -61,7 +62,7 @@ static const char *tex_vs = ""
"void main()"
"{"
" gl_TexCoord[0].xy = texcoord;"
- " gl_Position = model_x * vec4(vertex, 1.f);"
+ " gl_Position = projection_x * model_x * vec4(vertex, 1.f);"
"}"
"";
@@ -81,11 +82,12 @@ static const char *tex_fs = ""
/* Render simply renders a texd texture onto the screen */
-void tex_render(tex_t *tex, float alpha, m4f_t *model_x)
+void tex_render(tex_t *tex, float alpha, m4f_t *projection_x, m4f_t *model_x)
{
int *uniforms, *attributes;
assert(tex);
+ assert(projection_x);
assert(model_x);
shader_use(tex_shader, NULL, &uniforms, NULL, &attributes);
@@ -104,7 +106,8 @@ void tex_render(tex_t *tex, float alpha, m4f_t *model_x)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glUniform1f(uniforms[0], alpha);
- glUniformMatrix4fv(uniforms[1], 1, GL_FALSE, &model_x->m[0][0]);
+ glUniformMatrix4fv(uniforms[1], 1, GL_FALSE, &projection_x->m[0][0]);
+ glUniformMatrix4fv(uniforms[2], 1, GL_FALSE, &model_x->m[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
@@ -123,9 +126,10 @@ tex_t * tex_new(int width, int height, const unsigned char *buf)
if (!vbo) {
/* common to all tex instances */
tex_shader = shader_pair_new(tex_vs, tex_fs,
- 2,
+ 3,
(const char *[]) {
"alpha",
+ "projection_x",
"model_x",
},
2,
diff --git a/src/tex.h b/src/tex.h
index 00e5759..2ca4df4 100644
--- a/src/tex.h
+++ b/src/tex.h
@@ -22,7 +22,7 @@
typedef struct tex_t tex_t;
typedef struct m4f_t m4f_t;
-void tex_render(tex_t *tex, float alpha, m4f_t *model_x);
+void tex_render(tex_t *tex, float alpha, m4f_t *projection_x, m4f_t *model_x);
tex_t * tex_new(int width, int height, const unsigned char *buf);
tex_t * tex_ref(tex_t *tex);
tex_t * tex_free(tex_t *tex);
diff --git a/src/tv-node.c b/src/tv-node.c
index 267e2e2..0ca999f 100644
--- a/src/tv-node.c
+++ b/src/tv-node.c
@@ -23,10 +23,10 @@
static tex_t *tv_tex;
-stage_t * tv_node_new(stage_conf_t *conf, m4f_t *model_x)
+stage_t * tv_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x)
{
if (!tv_tex)
tv_tex = tex_new(gfx_tv.width, gfx_tv.height, gfx_tv.pixel_data);
- return tex_node_new_tex(conf, tv_tex, model_x);
+ return tex_node_new_tex(conf, tv_tex, projection_x, model_x);
}
diff --git a/src/tv-node.h b/src/tv-node.h
index 3974994..f989c77 100644
--- a/src/tv-node.h
+++ b/src/tv-node.h
@@ -20,6 +20,6 @@
typedef struct stage_conf_t stage_conf_t;
typedef struct m4f_t m4f_t;
-stage_t * tv_node_new(stage_conf_t *conf, m4f_t *model_x);
+stage_t * tv_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x);
#endif
diff --git a/src/virus-node.c b/src/virus-node.c
index bf52385..5d22718 100644
--- a/src/virus-node.c
+++ b/src/virus-node.c
@@ -23,10 +23,10 @@
static tex_t *virus_tex;
-stage_t * virus_node_new(stage_conf_t *conf, m4f_t *model_x)
+stage_t * virus_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x)
{
if (!virus_tex)
virus_tex = tex_new(gfx_virus.width, gfx_virus.height, gfx_virus.pixel_data);
- return tex_node_new_tex(conf, virus_tex, model_x);
+ return tex_node_new_tex(conf, virus_tex, projection_x, model_x);
}
diff --git a/src/virus-node.h b/src/virus-node.h
index 3c437ce..a7815d1 100644
--- a/src/virus-node.h
+++ b/src/virus-node.h
@@ -20,6 +20,6 @@
typedef struct stage_conf_t stage_conf_t;
typedef struct m4f_t m4f_t;
-stage_t * virus_node_new(stage_conf_t *conf, m4f_t *model_x);
+stage_t * virus_node_new(stage_conf_t *conf, m4f_t *projection_x, m4f_t *model_x);
#endif
© All Rights Reserved