First commit
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
build
|
||||||
Binary file not shown.
+55
@@ -0,0 +1,55 @@
|
|||||||
|
project(
|
||||||
|
'scufpong',
|
||||||
|
'c',
|
||||||
|
default_options: [
|
||||||
|
'force_fallback_for=scufeng'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
c_args = [
|
||||||
|
'-std=c23',
|
||||||
|
'-Wall',
|
||||||
|
'-Wextra',
|
||||||
|
'-pedantic'
|
||||||
|
]
|
||||||
|
|
||||||
|
scufeng_dep = dependency(
|
||||||
|
'scufeng',
|
||||||
|
allow_fallback: true
|
||||||
|
)
|
||||||
|
|
||||||
|
game = executable(
|
||||||
|
'game',
|
||||||
|
'src/common/game.c',
|
||||||
|
'src/game/MainMenu.c',
|
||||||
|
'src/game/MultiPlayer.c',
|
||||||
|
'src/game/SinglePlayer.c',
|
||||||
|
'src/game/pong.c',
|
||||||
|
'src/game/screen.c',
|
||||||
|
include_directories: include_directories(
|
||||||
|
'src/common/'
|
||||||
|
),
|
||||||
|
c_args: [
|
||||||
|
c_args,
|
||||||
|
'-DFONT_PATH="../assets/LiberationSans-Regular.ttf"',
|
||||||
|
'-D_DEFAULT_SOURCE' # for inet_aton
|
||||||
|
],
|
||||||
|
link_args: [
|
||||||
|
'-lm'
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
scufeng_dep
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
server = executable(
|
||||||
|
'server',
|
||||||
|
'src/server/server.c',
|
||||||
|
c_args: [
|
||||||
|
c_args,
|
||||||
|
'-D_DEFAULT_SOURCE' # for inet_aton
|
||||||
|
],
|
||||||
|
dependencies: [
|
||||||
|
scufeng_dep
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
#include "cglm/call/vec2.h"
|
||||||
|
|
||||||
|
#include "game.h"
|
||||||
|
#include "scufeng/engine.h"
|
||||||
|
#include "scufeng/util.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BCR_PADDLE_L_GOAL,
|
||||||
|
BCR_PADDLE_R_GOAL,
|
||||||
|
} BALL_COLLISION_RESULT;
|
||||||
|
|
||||||
|
GameState GameState_new(
|
||||||
|
const float paddles_w,
|
||||||
|
const float paddles_h,
|
||||||
|
const float paddle_l_x,
|
||||||
|
const float paddle_speed,
|
||||||
|
const float ball_w,
|
||||||
|
const vec2 ball_pos,
|
||||||
|
const float ball_speed
|
||||||
|
) {
|
||||||
|
|
||||||
|
#define BALL_START_DIR { -1.0f, 0.0f }
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
GameState state = {
|
||||||
|
.paddle_l = {
|
||||||
|
.pos = { paddle_l_x, 0.5f },
|
||||||
|
.w = paddles_w,
|
||||||
|
.h = paddles_h,
|
||||||
|
.dirv = GLM_VEC2_ZERO_INIT,
|
||||||
|
.speed = paddle_speed
|
||||||
|
},
|
||||||
|
.paddle_r = {
|
||||||
|
.pos = { 1.0f - paddle_l_x, 0.5f },
|
||||||
|
.w = paddles_w,
|
||||||
|
.h = paddles_h,
|
||||||
|
.dirv = GLM_VEC2_ZERO_INIT,
|
||||||
|
.speed = paddle_speed
|
||||||
|
},
|
||||||
|
.ball = {
|
||||||
|
// .pos = { 0.5f, 0.5f },
|
||||||
|
.pos = { ball_pos[0], ball_pos[1] },
|
||||||
|
.w = ball_w,
|
||||||
|
.h = ball_w,
|
||||||
|
.dirv = BALL_START_DIR,
|
||||||
|
.speed = ball_speed
|
||||||
|
},
|
||||||
|
.ball_start_pos = { ball_pos[0], ball_pos[1] },
|
||||||
|
.ball_start_dir = BALL_START_DIR
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void paddle_collision_check(MovingObject* const paddle) {
|
||||||
|
if (paddle->pos[1] - paddle->h / 2.0f < 0.0f) {
|
||||||
|
paddle->pos[1] = paddle->h / 2.0f;
|
||||||
|
}
|
||||||
|
if (paddle->pos[1] + paddle->h / 2.0f > 1.0f) {
|
||||||
|
paddle->pos[1] = 1.0f - paddle->h / 2.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void paddle_r_move(GameState* const state) {
|
||||||
|
const float ball_y = state->ball.pos[1];
|
||||||
|
|
||||||
|
const float target_zone_range = state->paddle_r.h / 2.0f;
|
||||||
|
const float target_zone_top = state->paddle_r.pos[1] - target_zone_range;
|
||||||
|
const float target_zone_middle = state->paddle_r.pos[1];
|
||||||
|
const float target_zone_bottom = state->paddle_r.pos[1] + target_zone_range;
|
||||||
|
|
||||||
|
const bool ball_is_below = ball_y > target_zone_bottom;
|
||||||
|
const bool ball_is_above = ball_y < target_zone_top;
|
||||||
|
const bool ball_is_centered = ball_y <= target_zone_middle + target_zone_range / 2.0f
|
||||||
|
&& ball_y >= target_zone_middle - target_zone_range / 2.0f;
|
||||||
|
// printf("%d%d\n", ball_is_below, ball_is_above);
|
||||||
|
|
||||||
|
if (ball_is_below) {
|
||||||
|
state->paddle_r.dirv[1] = 1.0f;
|
||||||
|
} else if (ball_is_above) {
|
||||||
|
state->paddle_r.dirv[1] = -1.0f;
|
||||||
|
} else if (ball_is_centered) {
|
||||||
|
state->paddle_r.dirv[1] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void game_next_round(GameState* const state) {
|
||||||
|
glmc_vec2_copy(state->ball_start_pos, state->ball.pos);
|
||||||
|
glmc_vec2_copy(state->ball_start_dir, state->ball.dirv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ball_bounds_collision_check(GameState* const state, vec2 new_pos) {
|
||||||
|
MovingObject* const ball = &state->ball;
|
||||||
|
|
||||||
|
const float wd2 = ball->w / 2.0f;
|
||||||
|
const float hd2 = ball->h / 2.0f;
|
||||||
|
|
||||||
|
if (new_pos[0] + wd2 <= 0.0f) {
|
||||||
|
state->score_r++;
|
||||||
|
game_next_round(state);
|
||||||
|
return true;
|
||||||
|
} else if (new_pos[0] - wd2 >= 1.0f) {
|
||||||
|
state->score_l++;
|
||||||
|
game_next_round(state);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_pos[1] - hd2 < 0.0f) {
|
||||||
|
new_pos[1] = hd2;
|
||||||
|
glmc_vec2_reflect(ball->dirv, (vec2) { 0.0f, -1.0f }, ball->dirv);
|
||||||
|
}
|
||||||
|
if (new_pos[1] + hd2 > 1.0f) {
|
||||||
|
new_pos[1] = 1.0f - hd2;
|
||||||
|
glmc_vec2_reflect(ball->dirv, (vec2) { 0.0f, 1.0f }, ball->dirv);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ball_paddles_collision_check(GameState* const state, vec2 new_pos) {
|
||||||
|
static const float possible_y_directions[] = {
|
||||||
|
0.0f,
|
||||||
|
0.5f,
|
||||||
|
-0.5f
|
||||||
|
};
|
||||||
|
|
||||||
|
MovingObject* const ball = &state->ball;
|
||||||
|
const MovingObject* const paddle_l = &state->paddle_l;
|
||||||
|
const MovingObject* const paddle_r = &state->paddle_r;
|
||||||
|
|
||||||
|
const float ball_wd2 = ball->w / 2.0f;
|
||||||
|
const float ball_hd2 = ball->h / 2.0f;
|
||||||
|
const float paddle_wd2 = paddle_l->w / 2.0f;
|
||||||
|
const float paddle_hd2 = paddle_l->h / 2.0f;
|
||||||
|
vec2 paddle_side_top;
|
||||||
|
vec2 paddle_side_bottom;
|
||||||
|
vec2 ball_side_top;
|
||||||
|
vec2 ball_side_bottom;
|
||||||
|
float paddle_back_x;
|
||||||
|
vec2 ball_pos;
|
||||||
|
vec2 new_pos_adj;
|
||||||
|
paddle_side_top[0] = paddle_l->pos[0] + paddle_wd2;
|
||||||
|
paddle_side_top[1] = paddle_l->pos[1] - paddle_hd2;
|
||||||
|
paddle_side_bottom[0] = paddle_side_top[0];
|
||||||
|
paddle_side_bottom[1] = paddle_l->pos[1] + paddle_hd2;
|
||||||
|
ball_side_top[0] = ball->pos[0] - ball_wd2;
|
||||||
|
ball_side_top[1] = ball->pos[1] - ball_hd2;
|
||||||
|
ball_side_bottom[0] = ball_side_top[0];
|
||||||
|
ball_side_bottom[1] = ball->pos[1] + ball_hd2;
|
||||||
|
paddle_back_x = paddle_l->pos[0] - paddle_wd2;
|
||||||
|
glmc_vec2_copy(ball->pos, ball_pos);
|
||||||
|
glmc_vec2_copy(new_pos, new_pos_adj);
|
||||||
|
|
||||||
|
bool collision = false;
|
||||||
|
bool mirror_ip = false;
|
||||||
|
vec2 ip;
|
||||||
|
|
||||||
|
if (state->ball.dirv[0] > 0.0f) {
|
||||||
|
mirror_ip = true;
|
||||||
|
paddle_side_top[0] = 1.0f - (paddle_r->pos[0] - paddle_r->w / 2.0f);
|
||||||
|
paddle_side_top[1] = (paddle_r->pos[1] - paddle_r->h / 2.0f);
|
||||||
|
paddle_side_bottom[0] = paddle_side_top[0];
|
||||||
|
paddle_side_bottom[1] = paddle_side_top[1] + paddle_r->h;
|
||||||
|
ball_pos[0] = 1.0f - ball_pos[0];
|
||||||
|
ball_side_top[0] = ball_pos[0] - ball_wd2;
|
||||||
|
ball_side_bottom[0] = ball_side_top[0];
|
||||||
|
paddle_back_x = 1.0f - (paddle_r->pos[0] + paddle_r->w / 2.0f);
|
||||||
|
new_pos_adj[0] = 1.0f - new_pos_adj[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEResult res = se_render_line_segment_norm_coord(
|
||||||
|
// paddle_side_top,
|
||||||
|
// paddle_side_bottom,
|
||||||
|
// (vec4) { 0.0f, 1.0f, 0.0f, 1.0f }
|
||||||
|
// );
|
||||||
|
// if (res != SE_SUCCESS) {
|
||||||
|
// LOG_ERRORF("Failed to draw segment: %d", res);
|
||||||
|
// }
|
||||||
|
// res = se_render_line_segment_norm_coord(
|
||||||
|
// ball_side_top,
|
||||||
|
// ball_side_bottom,
|
||||||
|
// (vec4) { 1.0f, 0.0f, 0.0f, 1.0f }
|
||||||
|
// );
|
||||||
|
// if (res != SE_SUCCESS) {
|
||||||
|
// LOG_ERRORF("Failed to draw segment: %d", res);
|
||||||
|
// }
|
||||||
|
// res = se_render_line_segment_norm_coord(
|
||||||
|
// (vec2) { paddle_back_x, 0.0f },
|
||||||
|
// (vec2) { paddle_back_x, 1.0f },
|
||||||
|
// (vec4) { 0.0f, 1.0f, 0.0f, 1.0f }
|
||||||
|
// );
|
||||||
|
// if (res != SE_SUCCESS) {
|
||||||
|
// LOG_ERRORF("Failed to draw segment: %d", res);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const bool inside_paddle = (ball_side_top[0] <= paddle_side_top[0] && ball_side_top[0] >= paddle_back_x)
|
||||||
|
&& ((ball_side_top[1] <= paddle_side_bottom[1] && ball_side_top[1] >= paddle_side_top[1])
|
||||||
|
|| (ball_side_bottom[1] <= paddle_side_bottom[1] && ball_side_bottom[1] >= paddle_side_top[1]));
|
||||||
|
|
||||||
|
if (inside_paddle) {
|
||||||
|
ball->dirv[0] *= -1.0f;
|
||||||
|
ball->dirv[1] = possible_y_directions[se_rand_int() % 3];
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
collision = se_line_segments_intersect(
|
||||||
|
ball_pos,
|
||||||
|
new_pos_adj,
|
||||||
|
paddle_side_top,
|
||||||
|
paddle_side_bottom,
|
||||||
|
ip
|
||||||
|
);
|
||||||
|
|
||||||
|
if (collision) {
|
||||||
|
new_pos[0] = mirror_ip ? 1.0f - ip[0] : ip[0];
|
||||||
|
new_pos[1] = ip[1];
|
||||||
|
state->ball.dirv[0] *= -1.0f;
|
||||||
|
state->ball.dirv[1] = possible_y_directions[se_rand_int() % 3];
|
||||||
|
// state->ball.dirv[1] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ball_move(GameState* const state, const double delta) {
|
||||||
|
vec2 ball_movement;
|
||||||
|
const float ball_movement_scale = delta * state->ball.speed;
|
||||||
|
// glmc_vec2_normalize(state->ball.dirv);
|
||||||
|
glmc_vec2_scale(state->ball.dirv, ball_movement_scale, ball_movement);
|
||||||
|
|
||||||
|
vec2 new_pos;
|
||||||
|
glmc_vec2_add(state->ball.pos, ball_movement, new_pos);
|
||||||
|
|
||||||
|
if (ball_bounds_collision_check(state, new_pos)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ball_paddles_collision_check(state, new_pos);
|
||||||
|
|
||||||
|
glmc_vec2_copy(new_pos, state->ball.pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameState_move_paddle_l(GameState* const state, const SEDirection dir) {
|
||||||
|
switch (dir) {
|
||||||
|
case SE_UP:
|
||||||
|
state->paddle_l.dirv[1] = -1.0f;
|
||||||
|
break;
|
||||||
|
case SE_DOWN:
|
||||||
|
state->paddle_l.dirv[1] = 1.0f;
|
||||||
|
break;
|
||||||
|
case SE_NONE:
|
||||||
|
state->paddle_l.dirv[1] = 0.0f;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameState_update(GameState* const state, const double delta) {
|
||||||
|
// Paddles
|
||||||
|
vec2 paddle_movement;
|
||||||
|
const float paddle_movement_scale = delta * state->paddle_l.speed;
|
||||||
|
glmc_vec2_scale(state->paddle_l.dirv, paddle_movement_scale, paddle_movement);
|
||||||
|
glmc_vec2_add(state->paddle_l.pos, paddle_movement, state->paddle_l.pos);
|
||||||
|
paddle_collision_check(&state->paddle_l);
|
||||||
|
|
||||||
|
paddle_r_move(state);
|
||||||
|
glmc_vec2_scale(state->paddle_r.dirv, paddle_movement_scale, paddle_movement);
|
||||||
|
glmc_vec2_add(state->paddle_r.pos, paddle_movement, state->paddle_r.pos);
|
||||||
|
paddle_collision_check(&state->paddle_r);
|
||||||
|
|
||||||
|
// Ball
|
||||||
|
ball_move(state, delta);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef GAME_H_
|
||||||
|
#define GAME_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cglm/types.h"
|
||||||
|
|
||||||
|
#include "scufeng/engine.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vec2 pos;
|
||||||
|
float w;
|
||||||
|
float h;
|
||||||
|
vec2 dirv;
|
||||||
|
float speed;
|
||||||
|
} MovingObject;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MovingObject paddle_l;
|
||||||
|
MovingObject paddle_r;
|
||||||
|
MovingObject ball;
|
||||||
|
vec2 ball_start_pos;
|
||||||
|
vec2 ball_start_dir;
|
||||||
|
uint8_t score_l;
|
||||||
|
uint8_t score_r;
|
||||||
|
} GameState;
|
||||||
|
|
||||||
|
GameState GameState_new(
|
||||||
|
const float paddles_w,
|
||||||
|
const float paddles_h,
|
||||||
|
const float paddle_l_x,
|
||||||
|
const float paddle_speed,
|
||||||
|
const float ball_w,
|
||||||
|
const vec2 ball_pos,
|
||||||
|
const float ball_speed
|
||||||
|
);
|
||||||
|
void GameState_move_paddle_l(GameState *const state, const SEDirection dir);
|
||||||
|
void GameState_update(GameState *const state, const double delta);
|
||||||
|
|
||||||
|
#endif // GAME_H_
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "scufeng/engine.h"
|
||||||
|
#include "scufeng/Shape.h"
|
||||||
|
#include "scufeng/Scene.h"
|
||||||
|
#include "cglm/vec3.h"
|
||||||
|
|
||||||
|
#include "MainMenu.h"
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
MainMenu MainMenu_alloc(const unsigned int screen_w, const unsigned int screen_h) {
|
||||||
|
MainMenu mm;
|
||||||
|
|
||||||
|
mm.title_text = SEMesh_string_alloc("Pong", 1.0f, GLM_VEC3_ONE);
|
||||||
|
mm.title_text.transform.pos[0] = screen_w / 2.0f;
|
||||||
|
mm.title_text.transform.pos[1] = screen_h * 0.8f;
|
||||||
|
|
||||||
|
mm.sp_text = SEMesh_string_alloc("Singleplayer", 1.0f, GLM_VEC3_ONE);
|
||||||
|
mm.sp_text.transform.pos[0] = screen_w * 0.25f;
|
||||||
|
mm.sp_text.transform.pos[1] = screen_h * 0.5f;
|
||||||
|
|
||||||
|
mm.mp_text = SEMesh_string_alloc("Multiplayer", 1.0f, GLM_VEC3_ONE);
|
||||||
|
mm.mp_text.transform.pos[0] = screen_w - mm.sp_text.transform.pos[0];
|
||||||
|
mm.mp_text.transform.pos[1] = mm.sp_text.transform.pos[1];
|
||||||
|
|
||||||
|
return mm;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Screen MainMenu_input_handle(MainMenu *const mm) {
|
||||||
|
if (se_get_mouse_button(SE_MOUSE_BUTTON_LEFT) == SE_KEY_ACTION_PRESS) {
|
||||||
|
double x, y;
|
||||||
|
se_get_mouse_pos(&x, &y);
|
||||||
|
|
||||||
|
if (SEMesh_rect_is_pos_inside(&mm->sp_text, x, y)) {
|
||||||
|
printf("SP\n");
|
||||||
|
return PONG_SINGLEPLAYER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SEMesh_rect_is_pos_inside(&mm->mp_text, x, y)) {
|
||||||
|
printf("MP\n");
|
||||||
|
return PONG_MULTIPLAYER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PONG_MAIN_MENU;
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen MainMenu_tick(MainMenu *const mm) {
|
||||||
|
const Screen screen = MainMenu_input_handle(mm);
|
||||||
|
if (screen != PONG_MAIN_MENU) {
|
||||||
|
return screen;
|
||||||
|
}
|
||||||
|
SEMesh *meshes[] = {
|
||||||
|
&mm->title_text,
|
||||||
|
&mm->sp_text,
|
||||||
|
&mm->mp_text
|
||||||
|
};
|
||||||
|
se_render_meshes_2d(meshes, sizeof(meshes) / sizeof(meshes[0]));
|
||||||
|
|
||||||
|
return PONG_MAIN_MENU;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "scufeng/Shape.h"
|
||||||
|
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SEMesh title_text;
|
||||||
|
SEMesh sp_text;
|
||||||
|
SEMesh mp_text;
|
||||||
|
} MainMenu;
|
||||||
|
|
||||||
|
MainMenu MainMenu_alloc(const unsigned int screen_w, const unsigned int screen_h);
|
||||||
|
Screen MainMenu_tick(MainMenu *const mm);
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "scufeng/log.h"
|
||||||
|
|
||||||
|
#include "MultiPlayer.h"
|
||||||
|
|
||||||
|
MultiPlayer MultiPlayer_alloc(
|
||||||
|
const char *server_host,
|
||||||
|
const uint16_t server_port
|
||||||
|
) {
|
||||||
|
MultiPlayer mp;
|
||||||
|
|
||||||
|
struct protoent *proto = getprotobyname("tcp");
|
||||||
|
mp.sock = socket(AF_INET, SOCK_STREAM, proto->p_proto);
|
||||||
|
if (mp.sock == -1) {
|
||||||
|
LOG_FATALF("socket failed: %d %s", errno, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct in_addr server_addr;
|
||||||
|
int res = inet_aton(server_host, &server_addr);
|
||||||
|
if (res == 0) {
|
||||||
|
LOG_FATAL("inet_aton failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in server_sockaddr = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_addr = server_addr,
|
||||||
|
.sin_port = htons(server_port)
|
||||||
|
};
|
||||||
|
|
||||||
|
mp.conn = connect(
|
||||||
|
mp.sock,
|
||||||
|
(struct sockaddr *) &server_sockaddr,
|
||||||
|
sizeof(server_sockaddr)
|
||||||
|
);
|
||||||
|
if (mp.conn == -1) {
|
||||||
|
LOG_FATALF("connect failed: %d %s", errno, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiPlayer_free(MultiPlayer *const mp) {
|
||||||
|
close(mp->conn);
|
||||||
|
mp->conn = 0;
|
||||||
|
close(mp->sock);
|
||||||
|
mp->sock = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiPlayer_tick(MultiPlayer *const mp) {
|
||||||
|
char buf[1024] = { 0 };
|
||||||
|
const size_t buf_size = sizeof(buf) / sizeof(buf[0]);
|
||||||
|
fgets(buf, buf_size, stdin);
|
||||||
|
|
||||||
|
send(mp->conn, buf, strlen(buf), 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int sock;
|
||||||
|
int conn;
|
||||||
|
} MultiPlayer;
|
||||||
|
|
||||||
|
MultiPlayer MultiPlayer_alloc(
|
||||||
|
const char *server_host,
|
||||||
|
const uint16_t server_port
|
||||||
|
);
|
||||||
|
void MultiPlayer_free(MultiPlayer *const mp);
|
||||||
|
void MultiPlayer_tick(MultiPlayer *const mp);
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
#include "cglm/vec4.h"
|
||||||
|
#include "scufeng/Scene.h"
|
||||||
|
|
||||||
|
#include "SinglePlayer.h"
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
SinglePlayer SinglePlayer_alloc(
|
||||||
|
unsigned int screen_w,
|
||||||
|
unsigned int screen_h,
|
||||||
|
float paddles_w,
|
||||||
|
float paddles_h,
|
||||||
|
float paddle_l_x,
|
||||||
|
float paddle_speed,
|
||||||
|
float ball_w,
|
||||||
|
vec2 ball_pos,
|
||||||
|
float ball_speed
|
||||||
|
) {
|
||||||
|
SinglePlayer sp = {
|
||||||
|
.screen_w = screen_w,
|
||||||
|
.screen_h = screen_h,
|
||||||
|
.state = GameState_new(
|
||||||
|
paddles_w,
|
||||||
|
paddles_h,
|
||||||
|
paddle_l_x,
|
||||||
|
paddle_speed,
|
||||||
|
ball_w,
|
||||||
|
ball_pos,
|
||||||
|
ball_speed
|
||||||
|
),
|
||||||
|
.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),
|
||||||
|
};
|
||||||
|
sp.paddle_l.transform.scale[0] = screen_w * paddles_w;
|
||||||
|
sp.paddle_l.transform.scale[1] = screen_h * paddles_h;
|
||||||
|
sp.paddle_l.transform.pos[0] = screen_w * paddle_l_x;
|
||||||
|
sp.paddle_l.transform.pos[1] = screen_h / 2.0f;
|
||||||
|
|
||||||
|
sp.paddle_r.transform.scale[0] = screen_w * paddles_w;
|
||||||
|
sp.paddle_r.transform.scale[1] = screen_h * paddles_h;
|
||||||
|
sp.paddle_r.transform.pos[0] = screen_w * (1.0f - paddle_l_x);
|
||||||
|
sp.paddle_r.transform.pos[1] = screen_h / 2.0f;
|
||||||
|
|
||||||
|
sp.ball.transform.scale[0] = screen_w * ball_w;
|
||||||
|
sp.ball.transform.scale[1] = sp.ball.transform.scale[0];
|
||||||
|
sp.ball.transform.pos[0] = screen_w * ball_pos[0];
|
||||||
|
sp.ball.transform.pos[1] = screen_h * ball_pos[1];
|
||||||
|
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SinglePlayer_free(SinglePlayer *sp) {
|
||||||
|
SEMesh_free(&sp->paddle_l);
|
||||||
|
SEMesh_free(&sp->paddle_r);
|
||||||
|
SEMesh_free(&sp->ball);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pos_convert(
|
||||||
|
vec3 render_pos,
|
||||||
|
const vec3 state_pos,
|
||||||
|
const unsigned int screen_w,
|
||||||
|
const unsigned int screen_h
|
||||||
|
) {
|
||||||
|
render_pos[0] = state_pos[0] * screen_w;
|
||||||
|
render_pos[1] = (1.0f - state_pos[1]) * screen_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_shapes(
|
||||||
|
const GameState *const state,
|
||||||
|
SEMesh *const paddle_l,
|
||||||
|
SEMesh *const paddle_r,
|
||||||
|
SEMesh *const ball,
|
||||||
|
const unsigned int screen_w,
|
||||||
|
const unsigned int screen_h
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Paddles
|
||||||
|
pos_convert(paddle_l->transform.pos, state->paddle_l.pos, screen_w, screen_h);
|
||||||
|
pos_convert(paddle_r->transform.pos, state->paddle_r.pos, screen_w, screen_h);
|
||||||
|
|
||||||
|
// Ball
|
||||||
|
pos_convert(ball->transform.pos, state->ball.pos, screen_w, screen_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool key_input_handle(GameState *const state) {
|
||||||
|
if (se_get_key(SE_KEY_W) == SE_KEY_ACTION_PRESS) {
|
||||||
|
GameState_move_paddle_l(state, SE_UP);
|
||||||
|
} else if (se_get_key(SE_KEY_S) == SE_KEY_ACTION_PRESS) {
|
||||||
|
GameState_move_paddle_l(state, SE_DOWN);
|
||||||
|
} else {
|
||||||
|
GameState_move_paddle_l(state, SE_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (se_get_key(SE_KEY_ESCAPE) == SE_KEY_ACTION_PRESS) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen SinglePlayer_tick(SinglePlayer *const sp, const double delta) {
|
||||||
|
if (key_input_handle(&sp->state)) {
|
||||||
|
return PONG_MAIN_MENU;
|
||||||
|
}
|
||||||
|
GameState_update(&sp->state, delta);
|
||||||
|
update_shapes(
|
||||||
|
&sp->state,
|
||||||
|
&sp->paddle_l,
|
||||||
|
&sp->paddle_r,
|
||||||
|
&sp->ball,
|
||||||
|
sp->screen_w,
|
||||||
|
sp->screen_h
|
||||||
|
);
|
||||||
|
SEMesh *meshes[] = {
|
||||||
|
&sp->paddle_l,
|
||||||
|
&sp->paddle_r,
|
||||||
|
&sp->ball
|
||||||
|
};
|
||||||
|
se_render_meshes_2d(meshes, sizeof(meshes) / sizeof(meshes[0]));
|
||||||
|
|
||||||
|
return PONG_SINGLEPLAYER;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "scufeng/Shape.h"
|
||||||
|
|
||||||
|
#include "game.h"
|
||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int screen_w;
|
||||||
|
unsigned int screen_h;
|
||||||
|
GameState state;
|
||||||
|
SEMesh paddle_l;
|
||||||
|
SEMesh paddle_r;
|
||||||
|
SEMesh ball;
|
||||||
|
} SinglePlayer;
|
||||||
|
|
||||||
|
SinglePlayer SinglePlayer_alloc(
|
||||||
|
unsigned int screen_w,
|
||||||
|
unsigned int screen_h,
|
||||||
|
float paddles_w,
|
||||||
|
float paddles_h,
|
||||||
|
float paddle_l_x,
|
||||||
|
float paddle_speed,
|
||||||
|
float ball_w,
|
||||||
|
vec2 ball_pos,
|
||||||
|
float ball_speed
|
||||||
|
);
|
||||||
|
void SinglePlayer_free(SinglePlayer *sp);
|
||||||
|
Screen SinglePlayer_tick(SinglePlayer *const sp, const double delta);
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#include "cglm/types.h"
|
||||||
|
#include "scufeng/engine.h"
|
||||||
|
#include "scufeng/text.h"
|
||||||
|
|
||||||
|
#include "screen.h"
|
||||||
|
#include "MainMenu.h"
|
||||||
|
#include "SinglePlayer.h"
|
||||||
|
#include "MultiPlayer.h"
|
||||||
|
|
||||||
|
static const unsigned int screen_w = 1200;
|
||||||
|
static const unsigned int screen_h = 600;
|
||||||
|
static const float paddles_w = 0.01f;
|
||||||
|
static const float paddles_h = 0.10f;
|
||||||
|
static const float paddle_l_x = (1.0f / 16);
|
||||||
|
static const float ball_w = paddles_w * 0.5f;
|
||||||
|
static vec2 ball_pos = { 0.5f, 0.5f };
|
||||||
|
static const float paddle_speed = 0.7f;
|
||||||
|
static const float ball_speed = 0.7f;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
se_init(true);
|
||||||
|
se_window_create(screen_w, screen_h, "Pong", -1);
|
||||||
|
se_swap_interval(0);
|
||||||
|
se_fps_lock_set_fps(60);
|
||||||
|
se_font_load(FONT_PATH, 0, 48);
|
||||||
|
|
||||||
|
se_clear_color(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
MainMenu mm = MainMenu_alloc(screen_w, screen_h);
|
||||||
|
SinglePlayer sp;
|
||||||
|
|
||||||
|
double last_frame_time = 0.0;
|
||||||
|
while (!se_window_should_close()) {
|
||||||
|
const double current_time = se_get_time();
|
||||||
|
const double delta = current_time - last_frame_time;
|
||||||
|
last_frame_time = current_time;
|
||||||
|
se_fps_lock_frame_start_s(current_time);
|
||||||
|
|
||||||
|
se_clear();
|
||||||
|
se_handle_events();
|
||||||
|
|
||||||
|
switch (current_screen) {
|
||||||
|
case PONG_MAIN_MENU:
|
||||||
|
current_screen = MainMenu_tick(&mm);
|
||||||
|
if (current_screen == PONG_SINGLEPLAYER) {
|
||||||
|
sp = SinglePlayer_alloc(
|
||||||
|
screen_w,
|
||||||
|
screen_h,
|
||||||
|
paddles_w,
|
||||||
|
paddles_h,
|
||||||
|
paddle_l_x,
|
||||||
|
paddle_speed,
|
||||||
|
ball_w,
|
||||||
|
ball_pos,
|
||||||
|
ball_speed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PONG_SINGLEPLAYER:
|
||||||
|
current_screen = SinglePlayer_tick(&sp, delta);
|
||||||
|
if (current_screen == PONG_MAIN_MENU) {
|
||||||
|
SinglePlayer_free(&sp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PONG_MULTIPLAYER:
|
||||||
|
MultiPlayer_tick();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("%u %u\n", sp.state.score_l, sp.state.score_r);
|
||||||
|
se_fps_lock_wait();
|
||||||
|
se_swap_buffers();
|
||||||
|
// printf("FT: %lf FPS: %lf\n", se_get_time() - current_time, 1.0 / (se_get_time() - current_time));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#include "screen.h"
|
||||||
|
|
||||||
|
Screen current_screen = PONG_MAIN_MENU;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PONG_MAIN_MENU,
|
||||||
|
PONG_SINGLEPLAYER,
|
||||||
|
PONG_MULTIPLAYER,
|
||||||
|
} Screen;
|
||||||
|
|
||||||
|
extern Screen current_screen;
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "scufeng/log.h"
|
||||||
|
|
||||||
|
#define SERVER_HOST "127.0.0.1"
|
||||||
|
#define SERVER_PORT 8080
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
struct protoent *proto = getprotobyname("tcp");
|
||||||
|
if (proto == nullptr) {
|
||||||
|
LOG_FATAL("getprotobyname failed");
|
||||||
|
}
|
||||||
|
const int sock = socket(AF_INET, SOCK_STREAM, proto->p_proto);
|
||||||
|
if (sock == -1) {
|
||||||
|
LOG_FATALF("socket failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct in_addr addr;
|
||||||
|
int res = inet_aton(SERVER_HOST, &addr);
|
||||||
|
if (res == 0) {
|
||||||
|
LOG_FATAL("inet_aton failed");
|
||||||
|
}
|
||||||
|
struct sockaddr_in own_addr = {
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
.sin_addr = addr,
|
||||||
|
.sin_port = htons(SERVER_PORT)
|
||||||
|
};
|
||||||
|
res = bind(sock, (struct sockaddr*) &own_addr, sizeof(own_addr));
|
||||||
|
if (res == -1) {
|
||||||
|
LOG_FATALF("bind failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = listen(sock, 5);
|
||||||
|
if (res == -1) {
|
||||||
|
LOG_FATALF("listen failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
int conn = -1;
|
||||||
|
|
||||||
|
conn = accept(sock, nullptr, nullptr);
|
||||||
|
if (conn == -1) {
|
||||||
|
LOG_FATALF("accept failed: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
char buf[1024] = {0};
|
||||||
|
const size_t buf_size = sizeof(buf) / sizeof(buf[0]);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int received = recv(conn, buf, buf_size, 0);
|
||||||
|
if (received == 0) {
|
||||||
|
printf("buf: %s\n", buf);
|
||||||
|
buf[0] = '\0';
|
||||||
|
break;
|
||||||
|
} else if (received == -1) {
|
||||||
|
LOG_FATALF("recv failed: %d %s", errno, strerror(errno));
|
||||||
|
} else {
|
||||||
|
buf[received] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
c505e04113e221188440051de27fad12c0670205
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef SCUFENG_CAMERA_H_
|
||||||
|
#define SCUFENG_CAMERA_H_
|
||||||
|
|
||||||
|
#include "cglm/types.h"
|
||||||
|
|
||||||
|
#include "scufeng/engine.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vec3 pos;
|
||||||
|
float pitch_rad;
|
||||||
|
float yaw_rad;
|
||||||
|
float fov_rad;
|
||||||
|
float near_clip;
|
||||||
|
float far_clip;
|
||||||
|
vec3 front;
|
||||||
|
vec3 right;
|
||||||
|
mat4 view;
|
||||||
|
mat4 projection;
|
||||||
|
} SECamera;
|
||||||
|
|
||||||
|
SECamera SECamera_new(
|
||||||
|
vec3 pos,
|
||||||
|
const float fov_rad,
|
||||||
|
const float near_clip,
|
||||||
|
const float far_clip
|
||||||
|
);
|
||||||
|
|
||||||
|
void SECamera_set_perspective(SECamera *const camera);
|
||||||
|
void SECamera_pos_set(SECamera *const camera, vec3 pos);
|
||||||
|
void SECamera_move_to_direction(SECamera *const camera, SEDirection dir, const float mag);
|
||||||
|
void SECamera_look_dir(SECamera *const camera, vec3 dir);
|
||||||
|
void SECamera_look_at(SECamera *const camera, vec3 target);
|
||||||
|
void SECamera_pitch_add(SECamera *const camera, const float pitch_rad);
|
||||||
|
void SECamera_yaw_add(SECamera *const camera, const float yaw_rad);
|
||||||
|
void SECamera_view_update(SECamera *const camera);
|
||||||
|
|
||||||
|
#endif // SCUFENG_CAMERA_H_
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef SCUFENG_SCENE_H_
|
||||||
|
#define SCUFENG_SCENE_H_
|
||||||
|
|
||||||
|
#include "scufeng/Shape.h"
|
||||||
|
#include "engine.h"
|
||||||
|
|
||||||
|
void se_render_meshes_2d(SEMesh *const *const meshes, const size_t meshes_n);
|
||||||
|
SEResult se_render_line_segment(const vec2 p1, const vec2 p2, const vec4 color);
|
||||||
|
SEResult se_render_line_segment_norm_coord(const vec2 p1, const vec2 p2, const vec4 color);
|
||||||
|
void se_text_render(const char* text, int x, int y, float scale, const vec3 color);
|
||||||
|
|
||||||
|
#endif // SCUFENG_SCENE_H_
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
#ifndef SCUFENG_SHAPE_H_
|
||||||
|
#define SCUFENG_SHAPE_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "cglm/types.h"
|
||||||
|
|
||||||
|
#include "scufeng/engine.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SE_TRIANGLES,
|
||||||
|
SE_TRIANGLE_STRIP,
|
||||||
|
SE_TRIANGLE_FAN,
|
||||||
|
SE_LINES,
|
||||||
|
SE_LINE_STRIP
|
||||||
|
} SEDrawMode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vec3 pos;
|
||||||
|
vec3 scale;
|
||||||
|
vec3 rotation;
|
||||||
|
} SETransform;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float pos[3];
|
||||||
|
float tex_coords[2];
|
||||||
|
} SEVertex;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SE_MESH_COLOR,
|
||||||
|
SE_MESH_TEXTURE
|
||||||
|
} SEMeshType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int id;
|
||||||
|
float w;
|
||||||
|
float h;
|
||||||
|
} SEMeshTexture;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int vao;
|
||||||
|
unsigned int vbo;
|
||||||
|
size_t verts_n;
|
||||||
|
int draw_mode;
|
||||||
|
|
||||||
|
SETransform transform;
|
||||||
|
|
||||||
|
SEMeshType type;
|
||||||
|
union {
|
||||||
|
SEMeshTexture texture;
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
} SEMesh;
|
||||||
|
|
||||||
|
SEResult SEShape_alloc(
|
||||||
|
SETransform *const shape,
|
||||||
|
const SEVertex *const vertices,
|
||||||
|
const size_t vertices_n,
|
||||||
|
const vec4 color,
|
||||||
|
const SEDrawMode draw_mode
|
||||||
|
);
|
||||||
|
void SEMesh_free(SEMesh *const mesh);
|
||||||
|
void SEMesh_set_draw_mode(SEMesh *mesh, const SEDrawMode mode);
|
||||||
|
void SEMesh_render(const SEMesh *const mesh);
|
||||||
|
void SEMesh_bbox_get_2d(
|
||||||
|
const SEMesh *const mesh,
|
||||||
|
float *left,
|
||||||
|
float *right,
|
||||||
|
float *top,
|
||||||
|
float *bottom
|
||||||
|
);
|
||||||
|
bool SEMesh_rect_is_pos_inside(const SEMesh *const mesh, const float x, const float y);
|
||||||
|
void SEShape_rotation_set(SETransform *shape, vec3 rotation);
|
||||||
|
void SEShape_rotate_2d_center(SETransform *const shape, const float w, const float h, const float angle_rad);
|
||||||
|
void SEShape_scale_set(SETransform *shape, vec3 scale);
|
||||||
|
void SEShape_scale(SETransform *const shape, vec3 scale);
|
||||||
|
void SEShape_pos_set(SETransform *const shape, vec3 pos);
|
||||||
|
void SEShape_translate_2d_center(SETransform *const shape, const float w, const float h, const vec2 pos);
|
||||||
|
void SEShape_transform_reset(SETransform *shape);
|
||||||
|
|
||||||
|
SEMesh SEMesh_rect_color_alloc(vec4 color);
|
||||||
|
SEMesh SEMesh_string_alloc(
|
||||||
|
const char *text,
|
||||||
|
const float scale,
|
||||||
|
const vec3 color
|
||||||
|
);
|
||||||
|
// void SEShape_transform_apply(SEShape *const shape);
|
||||||
|
|
||||||
|
#endif // SCUFENG_SHAPE_H_
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#ifndef SCUFENG_H_
|
||||||
|
#define SCUFENG_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "keys.h" // IWYU pragma: export
|
||||||
|
|
||||||
|
#define SERESULT_X(X) \
|
||||||
|
X(SE_SUCCESS) \
|
||||||
|
X(SE_OUT_OF_MEMORY) \
|
||||||
|
X(SE_FC_FAILURE) \
|
||||||
|
X(SE_NOT_FOUND) \
|
||||||
|
X(SE_FT_FAILURE)
|
||||||
|
|
||||||
|
#define X(val) val,
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SERESULT_X(X)
|
||||||
|
} SEResult;
|
||||||
|
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SE_FILL,
|
||||||
|
SE_LINE,
|
||||||
|
SE_POINT
|
||||||
|
} SEPolygonMode;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SE_NONE,
|
||||||
|
SE_FORWARD,
|
||||||
|
SE_BACKWARD,
|
||||||
|
SE_LEFT,
|
||||||
|
SE_RIGHT,
|
||||||
|
SE_UP,
|
||||||
|
SE_DOWN
|
||||||
|
} SEDirection;
|
||||||
|
|
||||||
|
typedef void (*SEKeyCb)(SEKey key, SEKeyAction action, SEKeyMod mods);
|
||||||
|
|
||||||
|
void se_init(const bool debug);
|
||||||
|
void se_deinit(void);
|
||||||
|
void se_window_create(
|
||||||
|
const int w,
|
||||||
|
const int h,
|
||||||
|
const char* title,
|
||||||
|
const int fullscreen_monitor_i
|
||||||
|
);
|
||||||
|
void se_window_close();
|
||||||
|
void se_clear_color(
|
||||||
|
const float r,
|
||||||
|
const float g,
|
||||||
|
const float b,
|
||||||
|
const float a
|
||||||
|
);
|
||||||
|
void se_clear(void);
|
||||||
|
void se_swap_buffers(void);
|
||||||
|
bool se_window_should_close(void);
|
||||||
|
void se_handle_events(void);
|
||||||
|
double se_get_time(void);
|
||||||
|
double se_delta_time(const double current_time);
|
||||||
|
void se_set_polygon_mode(const SEPolygonMode mode);
|
||||||
|
void se_set_key_callback(SEKeyCb cb);
|
||||||
|
SEKeyAction se_get_key(const SEKey key);
|
||||||
|
SEKeyAction se_get_mouse_button(const SEMouseButton btn);
|
||||||
|
void se_get_mouse_pos(double *x, double *y);
|
||||||
|
void se_swap_interval(const int interval);
|
||||||
|
void se_fps_lock_set_fps(const unsigned int fps);
|
||||||
|
void se_fps_lock_frame_start_s(const double frame_start_s);
|
||||||
|
void se_fps_lock_wait(void);
|
||||||
|
|
||||||
|
const char* SEResult_to_str(const SEResult res);
|
||||||
|
|
||||||
|
#endif // SCUFENG_H_
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
#ifndef SCUFENG_KEYS_H_
|
||||||
|
#define SCUFENG_KEYS_H_
|
||||||
|
|
||||||
|
#include "GLFW/glfw3.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SE_KEY_UNKNOWN = GLFW_KEY_UNKNOWN,
|
||||||
|
|
||||||
|
/* Printable keys */
|
||||||
|
SE_KEY_SPACE = GLFW_KEY_SPACE,
|
||||||
|
SE_KEY_APOSTROPHE = GLFW_KEY_APOSTROPHE,
|
||||||
|
SE_KEY_COMMA = GLFW_KEY_COMMA,
|
||||||
|
SE_KEY_MINUS = GLFW_KEY_MINUS,
|
||||||
|
SE_KEY_PERIOD = GLFW_KEY_PERIOD,
|
||||||
|
SE_KEY_SLASH = GLFW_KEY_SLASH,
|
||||||
|
SE_KEY_0 = GLFW_KEY_0,
|
||||||
|
SE_KEY_1 = GLFW_KEY_1,
|
||||||
|
SE_KEY_2 = GLFW_KEY_2,
|
||||||
|
SE_KEY_3 = GLFW_KEY_3,
|
||||||
|
SE_KEY_4 = GLFW_KEY_4,
|
||||||
|
SE_KEY_5 = GLFW_KEY_5,
|
||||||
|
SE_KEY_6 = GLFW_KEY_6,
|
||||||
|
SE_KEY_7 = GLFW_KEY_7,
|
||||||
|
SE_KEY_8 = GLFW_KEY_8,
|
||||||
|
SE_KEY_9 = GLFW_KEY_9,
|
||||||
|
SE_KEY_SEMICOLON = GLFW_KEY_SEMICOLON,
|
||||||
|
SE_KEY_EQUAL = GLFW_KEY_EQUAL,
|
||||||
|
SE_KEY_A = GLFW_KEY_A,
|
||||||
|
SE_KEY_B = GLFW_KEY_B,
|
||||||
|
SE_KEY_C = GLFW_KEY_C,
|
||||||
|
SE_KEY_D = GLFW_KEY_D,
|
||||||
|
SE_KEY_E = GLFW_KEY_E,
|
||||||
|
SE_KEY_F = GLFW_KEY_F,
|
||||||
|
SE_KEY_G = GLFW_KEY_G,
|
||||||
|
SE_KEY_H = GLFW_KEY_H,
|
||||||
|
SE_KEY_I = GLFW_KEY_I,
|
||||||
|
SE_KEY_J = GLFW_KEY_J,
|
||||||
|
SE_KEY_K = GLFW_KEY_K,
|
||||||
|
SE_KEY_L = GLFW_KEY_L,
|
||||||
|
SE_KEY_M = GLFW_KEY_M,
|
||||||
|
SE_KEY_N = GLFW_KEY_N,
|
||||||
|
SE_KEY_O = GLFW_KEY_O,
|
||||||
|
SE_KEY_P = GLFW_KEY_P,
|
||||||
|
SE_KEY_Q = GLFW_KEY_Q,
|
||||||
|
SE_KEY_R = GLFW_KEY_R,
|
||||||
|
SE_KEY_S = GLFW_KEY_S,
|
||||||
|
SE_KEY_T = GLFW_KEY_T,
|
||||||
|
SE_KEY_U = GLFW_KEY_U,
|
||||||
|
SE_KEY_V = GLFW_KEY_V,
|
||||||
|
SE_KEY_W = GLFW_KEY_W,
|
||||||
|
SE_KEY_X = GLFW_KEY_X,
|
||||||
|
SE_KEY_Y = GLFW_KEY_Y,
|
||||||
|
SE_KEY_Z = GLFW_KEY_Z,
|
||||||
|
SE_KEY_LEFT_BRACKET = GLFW_KEY_LEFT_BRACKET,
|
||||||
|
SE_KEY_BACKSLASH = GLFW_KEY_BACKSLASH,
|
||||||
|
SE_KEY_RIGHT_BRACKET = GLFW_KEY_RIGHT_BRACKET,
|
||||||
|
SE_KEY_GRAVE_ACCENT = GLFW_KEY_GRAVE_ACCENT,
|
||||||
|
SE_KEY_WORLD_1 = GLFW_KEY_WORLD_1,
|
||||||
|
SE_KEY_WORLD_2 = GLFW_KEY_WORLD_2,
|
||||||
|
|
||||||
|
/* Function keys */
|
||||||
|
SE_KEY_ESCAPE = GLFW_KEY_ESCAPE,
|
||||||
|
SE_KEY_ENTER = GLFW_KEY_ENTER,
|
||||||
|
SE_KEY_TAB = GLFW_KEY_TAB,
|
||||||
|
SE_KEY_BACKSPACE = GLFW_KEY_BACKSPACE,
|
||||||
|
SE_KEY_INSERT = GLFW_KEY_INSERT,
|
||||||
|
SE_KEY_DELETE = GLFW_KEY_DELETE,
|
||||||
|
SE_KEY_RIGHT = GLFW_KEY_RIGHT,
|
||||||
|
SE_KEY_LEFT = GLFW_KEY_LEFT,
|
||||||
|
SE_KEY_DOWN = GLFW_KEY_DOWN,
|
||||||
|
SE_KEY_UP = GLFW_KEY_UP,
|
||||||
|
SE_KEY_PAGE_UP = GLFW_KEY_PAGE_UP,
|
||||||
|
SE_KEY_PAGE_DOWN = GLFW_KEY_PAGE_DOWN,
|
||||||
|
SE_KEY_HOME = GLFW_KEY_HOME,
|
||||||
|
SE_KEY_END = GLFW_KEY_END,
|
||||||
|
SE_KEY_CAPS_LOCK = GLFW_KEY_CAPS_LOCK,
|
||||||
|
SE_KEY_SCROLL_LOCK = GLFW_KEY_SCROLL_LOCK,
|
||||||
|
SE_KEY_NUM_LOCK = GLFW_KEY_NUM_LOCK,
|
||||||
|
SE_KEY_PRINT_SCREEN = GLFW_KEY_PRINT_SCREEN,
|
||||||
|
SE_KEY_PAUSE = GLFW_KEY_PAUSE,
|
||||||
|
SE_KEY_F1 = GLFW_KEY_F1,
|
||||||
|
SE_KEY_F2 = GLFW_KEY_F2,
|
||||||
|
SE_KEY_F3 = GLFW_KEY_F3,
|
||||||
|
SE_KEY_F4 = GLFW_KEY_F4,
|
||||||
|
SE_KEY_F5 = GLFW_KEY_F5,
|
||||||
|
SE_KEY_F6 = GLFW_KEY_F6,
|
||||||
|
SE_KEY_F7 = GLFW_KEY_F7,
|
||||||
|
SE_KEY_F8 = GLFW_KEY_F8,
|
||||||
|
SE_KEY_F9 = GLFW_KEY_F9,
|
||||||
|
SE_KEY_F10 = GLFW_KEY_F10,
|
||||||
|
SE_KEY_F11 = GLFW_KEY_F11,
|
||||||
|
SE_KEY_F12 = GLFW_KEY_F12,
|
||||||
|
SE_KEY_F13 = GLFW_KEY_F13,
|
||||||
|
SE_KEY_F14 = GLFW_KEY_F14,
|
||||||
|
SE_KEY_F15 = GLFW_KEY_F15,
|
||||||
|
SE_KEY_F16 = GLFW_KEY_F16,
|
||||||
|
SE_KEY_F17 = GLFW_KEY_F17,
|
||||||
|
SE_KEY_F18 = GLFW_KEY_F18,
|
||||||
|
SE_KEY_F19 = GLFW_KEY_F19,
|
||||||
|
SE_KEY_F20 = GLFW_KEY_F20,
|
||||||
|
SE_KEY_F21 = GLFW_KEY_F21,
|
||||||
|
SE_KEY_F22 = GLFW_KEY_F22,
|
||||||
|
SE_KEY_F23 = GLFW_KEY_F23,
|
||||||
|
SE_KEY_F24 = GLFW_KEY_F24,
|
||||||
|
SE_KEY_F25 = GLFW_KEY_F25,
|
||||||
|
SE_KEY_KP_0 = GLFW_KEY_KP_0,
|
||||||
|
SE_KEY_KP_1 = GLFW_KEY_KP_1,
|
||||||
|
SE_KEY_KP_2 = GLFW_KEY_KP_2,
|
||||||
|
SE_KEY_KP_3 = GLFW_KEY_KP_3,
|
||||||
|
SE_KEY_KP_4 = GLFW_KEY_KP_4,
|
||||||
|
SE_KEY_KP_5 = GLFW_KEY_KP_5,
|
||||||
|
SE_KEY_KP_6 = GLFW_KEY_KP_6,
|
||||||
|
SE_KEY_KP_7 = GLFW_KEY_KP_7,
|
||||||
|
SE_KEY_KP_8 = GLFW_KEY_KP_8,
|
||||||
|
SE_KEY_KP_9 = GLFW_KEY_KP_9,
|
||||||
|
SE_KEY_KP_DECIMAL = GLFW_KEY_KP_DECIMAL,
|
||||||
|
SE_KEY_KP_DIVIDE = GLFW_KEY_KP_DIVIDE,
|
||||||
|
SE_KEY_KP_MULTIPLY = GLFW_KEY_KP_MULTIPLY,
|
||||||
|
SE_KEY_KP_SUBTRACT = GLFW_KEY_KP_SUBTRACT,
|
||||||
|
SE_KEY_KP_ADD = GLFW_KEY_KP_ADD,
|
||||||
|
SE_KEY_KP_ENTER = GLFW_KEY_KP_ENTER,
|
||||||
|
SE_KEY_KP_EQUAL = GLFW_KEY_KP_EQUAL,
|
||||||
|
SE_KEY_LEFT_SHIFT = GLFW_KEY_LEFT_SHIFT,
|
||||||
|
SE_KEY_LEFT_CONTROL = GLFW_KEY_LEFT_CONTROL,
|
||||||
|
SE_KEY_LEFT_ALT = GLFW_KEY_LEFT_ALT,
|
||||||
|
SE_KEY_LEFT_SUPER = GLFW_KEY_LEFT_SUPER,
|
||||||
|
SE_KEY_RIGHT_SHIFT = GLFW_KEY_RIGHT_SHIFT,
|
||||||
|
SE_KEY_RIGHT_CONTROL = GLFW_KEY_RIGHT_CONTROL,
|
||||||
|
SE_KEY_RIGHT_ALT = GLFW_KEY_RIGHT_ALT,
|
||||||
|
SE_KEY_RIGHT_SUPER = GLFW_KEY_RIGHT_SUPER,
|
||||||
|
SE_KEY_MENU = GLFW_KEY_MENU,
|
||||||
|
} SEKey;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SE_KEY_ACTION_RELEASE = GLFW_RELEASE,
|
||||||
|
SE_KEY_ACTION_PRESS = GLFW_PRESS,
|
||||||
|
SE_KEY_ACTION_REPEAT = GLFW_REPEAT,
|
||||||
|
} SEKeyAction;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SE_KEY_MOD_SHIFT = GLFW_MOD_SHIFT,
|
||||||
|
SE_KEY_MOD_CONTROL = GLFW_MOD_CONTROL,
|
||||||
|
SE_KEY_MOD_ALT = GLFW_MOD_ALT,
|
||||||
|
SE_KEY_MOD_SUPER = GLFW_MOD_SUPER,
|
||||||
|
SE_KEY_MOD_CAPS_LOCK = GLFW_MOD_CAPS_LOCK,
|
||||||
|
SE_KEY_MOD_NUM_LOCK = GLFW_MOD_NUM_LOCK,
|
||||||
|
} SEKeyMod;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SE_MOUSE_BUTTON_1 = 0,
|
||||||
|
SE_MOUSE_BUTTON_2 = 1,
|
||||||
|
SE_MOUSE_BUTTON_3 = 2,
|
||||||
|
SE_MOUSE_BUTTON_4 = 3,
|
||||||
|
SE_MOUSE_BUTTON_5 = 4,
|
||||||
|
SE_MOUSE_BUTTON_6 = 5,
|
||||||
|
SE_MOUSE_BUTTON_7 = 6,
|
||||||
|
SE_MOUSE_BUTTON_8 = 7,
|
||||||
|
SE_MOUSE_BUTTON_LAST = GLFW_MOUSE_BUTTON_8,
|
||||||
|
SE_MOUSE_BUTTON_LEFT = GLFW_MOUSE_BUTTON_1,
|
||||||
|
SE_MOUSE_BUTTON_RIGHT = GLFW_MOUSE_BUTTON_2,
|
||||||
|
SE_MOUSE_BUTTON_MIDDLE = GLFW_MOUSE_BUTTON_3,
|
||||||
|
} SEMouseButton;
|
||||||
|
|
||||||
|
#endif // SCUFENG_KEYS_H_
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef LOG_H_
|
||||||
|
#define LOG_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define LOG(str) log_with_tag(stdout, __FILE__, __LINE__, "LOG", (str))
|
||||||
|
#define LOGF(fmt, ...) logf_with_tag(stdout, __FILE__, __LINE__, "LOG", (fmt), __VA_ARGS__)
|
||||||
|
|
||||||
|
#define LOG_ERROR(str) log_with_tag(stderr, __FILE__, __LINE__, "ERROR", (str))
|
||||||
|
#define LOG_ERRORF(fmt, ...) logf_with_tag(stderr, __FILE__, __LINE__, "ERROR", (fmt), __VA_ARGS__)
|
||||||
|
|
||||||
|
#define LOG_FATAL(str) LOG_ERROR(str); exit(-1)
|
||||||
|
#define LOG_FATALF(fmt, ...) LOG_ERRORF(fmt, __VA_ARGS__); exit(-1)
|
||||||
|
|
||||||
|
#define LOG_FATAL_TODO(str) log_with_tag(stderr, __FILE__, __LINE__, "FATAL TODO", (str)); exit(-1)
|
||||||
|
#define LOG_FATAL_TODOF(fmt, ...) logf_with_tag(stderr, __FILE__, __LINE__, "FATAL TODO", (fmt), __VA_ARGS__); exit(-1)
|
||||||
|
|
||||||
|
void log_with_tag(FILE* out_file, char* file_name, size_t line, const char* tag, char* str);
|
||||||
|
void logf_with_tag(FILE* out_file, char* file_name, size_t line, const char* tag, char* fmt, ...);
|
||||||
|
|
||||||
|
#endif // LOG_H_
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef SCUFENG_MODEL_H_
|
||||||
|
#define SCUFENG_MODEL_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float* vertices;
|
||||||
|
size_t vertices_n;
|
||||||
|
} Mesh;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Mesh* meshes;
|
||||||
|
size_t meshes_n;
|
||||||
|
} Model;
|
||||||
|
|
||||||
|
Model model_load_gltf(const char* path);
|
||||||
|
|
||||||
|
#endif // SCUFENG_MODEL_H_
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef SE_SCUFCONT_IMPL_H_
|
||||||
|
#define SE_SCUFCONT_IMPL_H_
|
||||||
|
|
||||||
|
#include "scufcont/DArray.h"
|
||||||
|
#include "scufeng/Shape.h"
|
||||||
|
|
||||||
|
SCDARRAY_HEADER(SETransform*, SEShapep)
|
||||||
|
|
||||||
|
#endif // SE_SCUFCONT_IMPL_H_
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef SCUFENG_TEXT_H_
|
||||||
|
#define SCUFENG_TEXT_H_
|
||||||
|
|
||||||
|
#include "scufeng/engine.h"
|
||||||
|
|
||||||
|
SEResult se_font_load(
|
||||||
|
const char *path,
|
||||||
|
const unsigned int pixel_w,
|
||||||
|
const unsigned int pixel_h
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // SCUFENG_TEXT_H_
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef SCUFENG_UTIL_H_
|
||||||
|
#define SCUFENG_UTIL_H_
|
||||||
|
|
||||||
|
#include "cglm/types.h"
|
||||||
|
|
||||||
|
int se_rand_int();
|
||||||
|
bool se_line_segments_intersect(
|
||||||
|
const vec2 a1,
|
||||||
|
const vec2 a2,
|
||||||
|
const vec2 b1,
|
||||||
|
const vec2 b2,
|
||||||
|
vec2 ip
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif // SCUFENG_UTIL_H_
|
||||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
|||||||
|
project('scufeng', 'c')
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
|
scufeng_lib_dep = cc.find_library(
|
||||||
|
'scufeng',
|
||||||
|
dirs: meson.current_source_dir()
|
||||||
|
)
|
||||||
|
|
||||||
|
scufeng_dep = declare_dependency(
|
||||||
|
dependencies: scufeng_lib_dep,
|
||||||
|
include_directories: include_directories('include')
|
||||||
|
)
|
||||||
|
|
||||||
|
meson.override_dependency('scufeng', scufeng_dep)
|
||||||
Reference in New Issue
Block a user