|
@@ -1,10 +1,13 @@
|
|
|
-#include <stdio.h>
|
|
|
|
|
|
|
+#include <stdint.h>
|
|
|
|
|
+#include <string.h>
|
|
|
#include <unistd.h>
|
|
#include <unistd.h>
|
|
|
|
|
+#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "cglm/vec4.h"
|
|
#include "cglm/vec4.h"
|
|
|
#include "cglm/vec3.h"
|
|
#include "cglm/vec3.h"
|
|
|
#include "scufeng/Mesh.h"
|
|
#include "scufeng/Mesh.h"
|
|
|
-#include "scufeng/text.h"
|
|
|
|
|
|
|
+#include "scufeng/engine.h"
|
|
|
|
|
+#include "scufeng/log.h"
|
|
|
|
|
|
|
|
#include "game_common.h"
|
|
#include "game_common.h"
|
|
|
#include "game.h"
|
|
#include "game.h"
|
|
@@ -21,87 +24,138 @@ static void pos_convert(
|
|
|
render_pos[1] = state_pos[1] * screen_h;
|
|
render_pos[1] = state_pos[1] * screen_h;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void GameShapes_update(
|
|
|
|
|
|
|
+static void score_update_shape(
|
|
|
|
|
+ SEMesh *const score_mesh,
|
|
|
|
|
+ const bool left,
|
|
|
|
|
+ const unsigned int screen_w,
|
|
|
|
|
+ const unsigned int screen_h
|
|
|
|
|
+) {
|
|
|
|
|
+ const float x = left ? 0.25f : 1.0f - 0.25f;
|
|
|
|
|
+ SEMesh_rect_textured_scale_set(score_mesh, 0.0f, screen_h * 0.1f);
|
|
|
|
|
+ score_mesh->transform.pos[0] = screen_w * x;
|
|
|
|
|
+ score_mesh->transform.pos[1] = score_mesh->transform.scale[1] / 2.0f + screen_h * 0.1f;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ @return SE_OUT_OF_MEMORY
|
|
|
|
|
+ @return SE_SUCCESS
|
|
|
|
|
+*/
|
|
|
|
|
+static SEResult score_update(
|
|
|
GameShapes *const shapes,
|
|
GameShapes *const shapes,
|
|
|
const GameState *const state,
|
|
const GameState *const state,
|
|
|
|
|
+ const bool left,
|
|
|
const unsigned int screen_w,
|
|
const unsigned int screen_w,
|
|
|
const unsigned int screen_h
|
|
const unsigned int screen_h
|
|
|
) {
|
|
) {
|
|
|
|
|
+ uint8_t score;
|
|
|
|
|
+ SEMesh *mesh = nullptr;
|
|
|
|
|
+
|
|
|
|
|
+ if (left) {
|
|
|
|
|
+ score = state->score_l;
|
|
|
|
|
+ mesh = &shapes->score_l;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ score = state->score_r;
|
|
|
|
|
+ mesh = &shapes->score_r;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const unsigned long mesh_score = strtoul(SEMesh_string_c_str(mesh), nullptr, 10);
|
|
|
|
|
+ if (mesh_score != (unsigned long) score) {
|
|
|
|
|
+ char buf[4]; // Score max is 255 since GameState.score_x is a uint8_t
|
|
|
|
|
+ snprintf(buf, 4, "%u", score);
|
|
|
|
|
+ SEResult res = SEMesh_string_text_replace(mesh, buf, strlen(buf), mesh->string.color);
|
|
|
|
|
+ if (res != SE_SUCCESS) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+ score_update_shape(mesh, left, screen_w, screen_h);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return SE_SUCCESS;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+SEResult GameShapes_update(
|
|
|
|
|
+ GameShapes *const shapes,
|
|
|
|
|
+ const GameState *const state,
|
|
|
|
|
+ const unsigned int screen_w,
|
|
|
|
|
+ const unsigned int screen_h
|
|
|
|
|
+) {
|
|
|
// Paddles
|
|
// Paddles
|
|
|
pos_convert(shapes->paddle_l.transform.pos, state->paddle_l.pos, screen_w, screen_h);
|
|
pos_convert(shapes->paddle_l.transform.pos, state->paddle_l.pos, screen_w, screen_h);
|
|
|
pos_convert(shapes->paddle_r.transform.pos, state->paddle_r.pos, screen_w, screen_h);
|
|
pos_convert(shapes->paddle_r.transform.pos, state->paddle_r.pos, screen_w, screen_h);
|
|
|
|
|
|
|
|
// Ball
|
|
// Ball
|
|
|
pos_convert(shapes->ball.transform.pos, state->ball.pos, screen_w, screen_h);
|
|
pos_convert(shapes->ball.transform.pos, state->ball.pos, screen_w, screen_h);
|
|
|
|
|
+
|
|
|
|
|
+ // Scores
|
|
|
|
|
+ SEResult res = score_update(shapes, state, true, screen_w, screen_h);
|
|
|
|
|
+ if (res != SE_SUCCESS) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+ res = score_update(shapes, state, false, screen_w, screen_h);
|
|
|
|
|
+ if (res != SE_SUCCESS) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return SE_SUCCESS;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-GameShapes GameShapes_alloc(
|
|
|
|
|
|
|
+SEResult GameShapes_alloc(
|
|
|
|
|
+ GameShapes *const shapes,
|
|
|
unsigned int screen_w,
|
|
unsigned int screen_w,
|
|
|
unsigned int screen_h,
|
|
unsigned int screen_h,
|
|
|
GameStateParameters params
|
|
GameStateParameters params
|
|
|
) {
|
|
) {
|
|
|
- GameShapes shapes = {
|
|
|
|
|
- .paddle_l = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
|
|
|
|
|
- .paddle_r = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
|
|
|
|
|
- .ball = SEMesh_rect_color_alloc(GLM_VEC4_ONE),
|
|
|
|
|
- };
|
|
|
|
|
- shapes.paddle_l.transform.scale[0] = screen_w * params.paddles_w;
|
|
|
|
|
- shapes.paddle_l.transform.scale[1] = screen_h * params.paddles_h;
|
|
|
|
|
- shapes.paddle_l.transform.pos[0] = screen_w * params.paddle_l_x;
|
|
|
|
|
- shapes.paddle_l.transform.pos[1] = screen_h / 2.0f;
|
|
|
|
|
-
|
|
|
|
|
- shapes.paddle_r.transform.scale[0] = screen_w * params.paddles_w;
|
|
|
|
|
- shapes.paddle_r.transform.scale[1] = screen_h * params.paddles_h;
|
|
|
|
|
- shapes.paddle_r.transform.pos[0] = screen_w * (1.0f - params.paddle_l_x);
|
|
|
|
|
- shapes.paddle_r.transform.pos[1] = screen_h / 2.0f;
|
|
|
|
|
-
|
|
|
|
|
- shapes.ball.transform.scale[0] = screen_w * params.ball_w;
|
|
|
|
|
- shapes.ball.transform.scale[1] = shapes.ball.transform.scale[0];
|
|
|
|
|
- shapes.ball.transform.pos[0] = screen_w * params.ball_pos[0];
|
|
|
|
|
- shapes.ball.transform.pos[1] = screen_h * params.ball_pos[1];
|
|
|
|
|
-
|
|
|
|
|
- return shapes;
|
|
|
|
|
|
|
+ shapes->paddle_l = SEMesh_rect_color_alloc(GLM_VEC4_ONE);
|
|
|
|
|
+ shapes->paddle_l.transform.scale[0] = screen_w * params.paddles_w;
|
|
|
|
|
+ shapes->paddle_l.transform.scale[1] = screen_h * params.paddles_h;
|
|
|
|
|
+ shapes->paddle_l.transform.pos[0] = screen_w * params.paddle_l_x;
|
|
|
|
|
+ shapes->paddle_l.transform.pos[1] = screen_h / 2.0f;
|
|
|
|
|
+
|
|
|
|
|
+ shapes->paddle_r = SEMesh_rect_color_alloc(GLM_VEC4_ONE);
|
|
|
|
|
+ shapes->paddle_r.transform.scale[0] = screen_w * params.paddles_w;
|
|
|
|
|
+ shapes->paddle_r.transform.scale[1] = screen_h * params.paddles_h;
|
|
|
|
|
+ shapes->paddle_r.transform.pos[0] = screen_w * (1.0f - params.paddle_l_x);
|
|
|
|
|
+ shapes->paddle_r.transform.pos[1] = screen_h / 2.0f;
|
|
|
|
|
+
|
|
|
|
|
+ shapes->ball = SEMesh_rect_color_alloc(GLM_VEC4_ONE);
|
|
|
|
|
+ shapes->ball.transform.scale[0] = screen_w * params.ball_w;
|
|
|
|
|
+ shapes->ball.transform.scale[1] = shapes->ball.transform.scale[0];
|
|
|
|
|
+ shapes->ball.transform.pos[0] = screen_w * params.ball_pos[0];
|
|
|
|
|
+ shapes->ball.transform.pos[1] = screen_h * params.ball_pos[1];
|
|
|
|
|
+
|
|
|
|
|
+ SEResult res = SEMesh_string_alloc(&shapes->score_l, "0", 1, GLM_VEC3_ONE);
|
|
|
|
|
+ if (res != SE_SUCCESS) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+ score_update_shape(&shapes->score_l, true, screen_w, screen_h);
|
|
|
|
|
+
|
|
|
|
|
+ res = SEMesh_string_alloc(&shapes->score_r, "0", 1, GLM_VEC3_ONE);
|
|
|
|
|
+ if (res != SE_SUCCESS) {
|
|
|
|
|
+ return res;
|
|
|
|
|
+ }
|
|
|
|
|
+ score_update_shape(&shapes->score_r, false, screen_w, screen_h);
|
|
|
|
|
+
|
|
|
|
|
+ return SE_SUCCESS;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void GameShapes_free(GameShapes *const shapes) {
|
|
void GameShapes_free(GameShapes *const shapes) {
|
|
|
SEMesh_free(&shapes->paddle_l);
|
|
SEMesh_free(&shapes->paddle_l);
|
|
|
SEMesh_free(&shapes->paddle_r);
|
|
SEMesh_free(&shapes->paddle_r);
|
|
|
SEMesh_free(&shapes->ball);
|
|
SEMesh_free(&shapes->ball);
|
|
|
|
|
+ SEMesh_free(&shapes->score_l);
|
|
|
|
|
+ SEMesh_free(&shapes->score_r);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void GameShapes_render(
|
|
void GameShapes_render(
|
|
|
- GameShapes *const shapes,
|
|
|
|
|
- const GameState *const state,
|
|
|
|
|
- const unsigned int screen_w,
|
|
|
|
|
- const unsigned int screen_h
|
|
|
|
|
|
|
+ GameShapes *const shapes
|
|
|
) {
|
|
) {
|
|
|
SEMesh *meshes[] = {
|
|
SEMesh *meshes[] = {
|
|
|
&shapes->paddle_l,
|
|
&shapes->paddle_l,
|
|
|
&shapes->paddle_r,
|
|
&shapes->paddle_r,
|
|
|
- &shapes->ball
|
|
|
|
|
|
|
+ &shapes->ball,
|
|
|
|
|
+ &shapes->score_l,
|
|
|
|
|
+ &shapes->score_r
|
|
|
};
|
|
};
|
|
|
SEMesh_render_multiple_2d(meshes, sizeof(meshes) / sizeof(meshes[0]));
|
|
SEMesh_render_multiple_2d(meshes, sizeof(meshes) / sizeof(meshes[0]));
|
|
|
-
|
|
|
|
|
- const float score_w = 0.25f;
|
|
|
|
|
- const float score_h = 0.1f;
|
|
|
|
|
- char score_txt[4] = { 0 };
|
|
|
|
|
- snprintf(score_txt, 4, "%d", state->score_l);
|
|
|
|
|
- se_text_render(
|
|
|
|
|
- score_txt,
|
|
|
|
|
- screen_w * score_w,
|
|
|
|
|
- screen_h * score_h,
|
|
|
|
|
- 1.0f,
|
|
|
|
|
- GLM_VEC3_ONE
|
|
|
|
|
- );
|
|
|
|
|
- snprintf(score_txt, 4, "%d", state->score_r);
|
|
|
|
|
- se_text_render(
|
|
|
|
|
- score_txt,
|
|
|
|
|
- screen_w * (1.0f - score_w),
|
|
|
|
|
- screen_h * score_h,
|
|
|
|
|
- 1.0f,
|
|
|
|
|
- GLM_VEC3_ONE
|
|
|
|
|
- );
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void win_lose_render(
|
|
void win_lose_render(
|
|
@@ -110,10 +164,17 @@ void win_lose_render(
|
|
|
const unsigned int screen_h
|
|
const unsigned int screen_h
|
|
|
) {
|
|
) {
|
|
|
const char *text_str = win ? "You Win!" : "You Lose!";
|
|
const char *text_str = win ? "You Win!" : "You Lose!";
|
|
|
- SEMesh text = SEMesh_string_alloc(
|
|
|
|
|
|
|
+ SEMesh text;
|
|
|
|
|
+ SEResult res = SEMesh_string_alloc(
|
|
|
|
|
+ &text,
|
|
|
text_str,
|
|
text_str,
|
|
|
|
|
+ strlen(text_str),
|
|
|
(vec3) { 1.0f, 1.0f, 1.0f }
|
|
(vec3) { 1.0f, 1.0f, 1.0f }
|
|
|
);
|
|
);
|
|
|
|
|
+ if (res != SE_SUCCESS) {
|
|
|
|
|
+ SE_LOG_FATALF("Failed to alloc win/lose string: %s", SEResult_to_str(res));
|
|
|
|
|
+ }
|
|
|
|
|
+ SEMesh_rect_textured_scale_set(&text, screen_w * 0.25f, 0.0f);
|
|
|
text.transform.pos[0] = screen_w / 2.0f;
|
|
text.transform.pos[0] = screen_w / 2.0f;
|
|
|
text.transform.pos[1] = screen_h / 2.0f;
|
|
text.transform.pos[1] = screen_h / 2.0f;
|
|
|
|
|
|