[RELEASE] u22-v03
This version is submitted to U22 breau.
This commit is contained in:
1
app/CMakeLists.txt
Normal file
1
app/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
||||
add_subdirectory(sdl)
|
14
app/sdl/CMakeLists.txt
Normal file
14
app/sdl/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
add_executable(app-sdl
|
||||
args.c
|
||||
event.c
|
||||
main.c
|
||||
)
|
||||
target_link_libraries(app-sdl
|
||||
GLEW::GLEW
|
||||
SDL2::SDL2
|
||||
|
||||
conv
|
||||
parsarg
|
||||
|
||||
loscene
|
||||
)
|
104
app/sdl/args.c
Normal file
104
app/sdl/args.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "./args.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util/parsarg/parsarg.h"
|
||||
|
||||
#include "core/loscene/param.h"
|
||||
|
||||
void app_args_parse(app_args_t* args, int argc, char** argv) {
|
||||
assert(args != NULL);
|
||||
assert(argc > 0);
|
||||
|
||||
parsarg_t pa;
|
||||
parsarg_initialize(&pa, argc-1, argv+1);
|
||||
|
||||
while (!parsarg_finished(&pa)) {
|
||||
size_t nlen;
|
||||
char* n = parsarg_pop_name(&pa, &nlen);
|
||||
|
||||
char* v;
|
||||
parsarg_pop_value(&pa, &v);
|
||||
|
||||
if (n == NULL && v == NULL) continue;
|
||||
|
||||
bool ok = false;
|
||||
|
||||
# define bool_(name, var) do { \
|
||||
if (strncmp(name, n, nlen) == 0 && name[nlen] == 0) { \
|
||||
if (v == NULL) { \
|
||||
var = true; \
|
||||
ok = true; \
|
||||
} else { \
|
||||
fprintf(stderr, "option '"name"' cannot take any values"); \
|
||||
abort(); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# define int_(name, var, min, max) do { \
|
||||
if (strncmp(name, n, nlen) == 0 && name[nlen] == 0) { \
|
||||
char* end; \
|
||||
const intmax_t i = strtoimax(v, &end, 0); \
|
||||
if (*end == 0 && min <= i && i < max) { \
|
||||
var = i; \
|
||||
ok = true; \
|
||||
} else { \
|
||||
fprintf(stderr, \
|
||||
"option '"name"' requires " \
|
||||
"an integer value (%"PRIdMAX"~%"PRIdMAX")\n", \
|
||||
(intmax_t) min, (intmax_t) max); \
|
||||
abort(); \
|
||||
} \
|
||||
continue; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* ---- scene parameters ---- */
|
||||
int_("width", args->scene.width, 640, INT32_MAX);
|
||||
int_("height", args->scene.height, 360, INT32_MAX);
|
||||
int_("dpi-x", args->scene.dpi.x, 1, INT32_MAX);
|
||||
int_("dpi-y", args->scene.dpi.y, 1, INT32_MAX);
|
||||
|
||||
int_("max-msaa", args->scene.max_msaa, 1, INT32_MAX);
|
||||
int_("brightness", args->scene.brightness, 0, 2000);
|
||||
|
||||
bool_("disable-heavy-backwall",
|
||||
args->scene.environment.disable_heavy_backwall);
|
||||
bool_("disable-heavy-fog",
|
||||
args->scene.environment.disable_heavy_fog);
|
||||
|
||||
bool_("skip-title", args->scene.skip_title);
|
||||
|
||||
bool_("test-poolset-packing", args->scene.test.loworld_poolset_packing);
|
||||
bool_("test-player-packing", args->scene.test.loplayer_packing);
|
||||
|
||||
/* ---- app parameters ---- */
|
||||
int_("max-fps", args->max_fps, 1, INT32_MAX);
|
||||
|
||||
bool_("override-dpi", args->override_dpi);
|
||||
|
||||
bool_("force-window", args->force_window);
|
||||
bool_("force-desktop-fullscreen", args->force_desktop_fullscreen);
|
||||
bool_("force-fullscreen", args->force_fullscreen);
|
||||
|
||||
# undef int_
|
||||
# undef bool_
|
||||
|
||||
if (!ok) {
|
||||
if (n == NULL) {
|
||||
fprintf(stderr, "missing option name for the value '%s'\n", v);
|
||||
} else {
|
||||
fprintf(stderr, "unknown option '%.*s'\n", (int) nlen, n);
|
||||
}
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
parsarg_deinitialize(&pa);
|
||||
}
|
24
app/sdl/args.h
Normal file
24
app/sdl/args.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "core/loscene/param.h"
|
||||
|
||||
typedef struct {
|
||||
loscene_param_t scene;
|
||||
|
||||
int32_t max_fps;
|
||||
|
||||
bool override_dpi;
|
||||
|
||||
bool force_window;
|
||||
bool force_desktop_fullscreen;
|
||||
bool force_fullscreen;
|
||||
} app_args_t;
|
||||
|
||||
void
|
||||
app_args_parse(
|
||||
app_args_t* args,
|
||||
int argc,
|
||||
char** argv
|
||||
);
|
52
app/sdl/event.c
Normal file
52
app/sdl/event.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "./event.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "core/locommon/input.h"
|
||||
|
||||
#define APP_EVENT_GET_BUTTON_BIT_FROM_KEY(k) ( \
|
||||
(k) == SDLK_a? LOCOMMON_INPUT_BUTTON_LEFT: \
|
||||
(k) == SDLK_d? LOCOMMON_INPUT_BUTTON_RIGHT: \
|
||||
(k) == SDLK_w? LOCOMMON_INPUT_BUTTON_UP: \
|
||||
(k) == SDLK_s? LOCOMMON_INPUT_BUTTON_DOWN: \
|
||||
(k) == SDLK_SPACE? LOCOMMON_INPUT_BUTTON_JUMP: \
|
||||
(k) == SDLK_LSHIFT? LOCOMMON_INPUT_BUTTON_DASH: \
|
||||
(k) == SDLK_ESCAPE? LOCOMMON_INPUT_BUTTON_MENU: \
|
||||
0)
|
||||
|
||||
#define APP_EVENT_GET_BUTTON_BIT_FROM_MOUSE(m) ( \
|
||||
(m) == SDL_BUTTON_LEFT? LOCOMMON_INPUT_BUTTON_ATTACK: \
|
||||
(m) == SDL_BUTTON_RIGHT? LOCOMMON_INPUT_BUTTON_GUARD: \
|
||||
0)
|
||||
|
||||
bool app_event_handle(locommon_input_t* input, const SDL_Event* e) {
|
||||
assert(input != NULL);
|
||||
assert(e != NULL);
|
||||
|
||||
switch (e->type) {
|
||||
case SDL_MOUSEMOTION:
|
||||
input->cursor = vec2(
|
||||
e->motion.x/input->resolution.x, e->motion.y/input->resolution.y);
|
||||
input->cursor.x = input->cursor.x*2 - 1;
|
||||
input->cursor.y = 1 - input->cursor.y*2;
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
input->buttons |= APP_EVENT_GET_BUTTON_BIT_FROM_MOUSE(e->button.button);
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
input->buttons &= ~APP_EVENT_GET_BUTTON_BIT_FROM_MOUSE(e->button.button);
|
||||
break;
|
||||
case SDL_KEYDOWN:
|
||||
input->buttons |= APP_EVENT_GET_BUTTON_BIT_FROM_KEY(e->key.keysym.sym);
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
input->buttons &= ~APP_EVENT_GET_BUTTON_BIT_FROM_KEY(e->key.keysym.sym);
|
||||
break;
|
||||
case SDL_QUIT:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
13
app/sdl/event.h
Normal file
13
app/sdl/event.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "core/locommon/input.h"
|
||||
|
||||
bool
|
||||
app_event_handle(
|
||||
locommon_input_t* input,
|
||||
const SDL_Event* e
|
||||
);
|
172
app/sdl/main.c
Normal file
172
app/sdl/main.c
Normal file
@@ -0,0 +1,172 @@
|
||||
#define SDL_MAIN_HANDLED
|
||||
#define NO_STDIO_REDIRECT
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "core/loscene/context.h"
|
||||
|
||||
#include "./args.h"
|
||||
#include "./event.h"
|
||||
|
||||
static const app_args_t app_default_args_ = {
|
||||
.scene = {
|
||||
.width = 960,
|
||||
.height = 540,
|
||||
.dpi = vec2(96, 96),
|
||||
|
||||
.max_msaa = 8,
|
||||
.brightness = 1000,
|
||||
},
|
||||
.max_fps = 60,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
SDL_Window* win;
|
||||
SDL_GLContext gl;
|
||||
} libs_t;
|
||||
|
||||
static void app_initialize_libraries_(libs_t* libs, app_args_t* args) {
|
||||
assert(libs != NULL);
|
||||
assert(args != NULL);
|
||||
|
||||
SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
|
||||
if (SDL_Init(SDL_INIT_VIDEO)) {
|
||||
fprintf(stderr, "failed to initialize SDL: %s\n", SDL_GetError());
|
||||
abort();
|
||||
}
|
||||
|
||||
SDL_GL_SetAttribute(
|
||||
SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
|
||||
SDL_GL_SetAttribute(
|
||||
SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
|
||||
uint32_t win_flags =
|
||||
SDL_WINDOW_ALLOW_HIGHDPI |
|
||||
SDL_WINDOW_OPENGL |
|
||||
SDL_WINDOW_SHOWN;
|
||||
if (args->force_window) {
|
||||
} else if (args->force_desktop_fullscreen) {
|
||||
win_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
} else if (args->force_fullscreen) {
|
||||
win_flags |= SDL_WINDOW_FULLSCREEN;
|
||||
} else {
|
||||
# ifdef NDEBUG
|
||||
win_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
# endif
|
||||
}
|
||||
|
||||
libs->win = SDL_CreateWindow(
|
||||
"LEFTONE", /* title */
|
||||
SDL_WINDOWPOS_CENTERED, /* X position */
|
||||
SDL_WINDOWPOS_CENTERED, /* Y position */
|
||||
args->scene.width,
|
||||
args->scene.height,
|
||||
win_flags);
|
||||
if (libs->win == NULL) {
|
||||
fprintf(stderr, "failed to create window: %s\n", SDL_GetError());
|
||||
abort();
|
||||
}
|
||||
|
||||
int w, h;
|
||||
SDL_GetWindowSize(libs->win, &w, &h);
|
||||
args->scene.width = w;
|
||||
args->scene.height = h;
|
||||
|
||||
libs->gl = SDL_GL_CreateContext(libs->win);
|
||||
|
||||
glewExperimental = 1;
|
||||
if (glewInit() != GLEW_OK) {
|
||||
fprintf(stderr, "failed to init GLEW\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
glViewport(0, 0, args->scene.width, args->scene.height);
|
||||
}
|
||||
static void app_deinitialize_libraries_(libs_t* libs) {
|
||||
assert(libs != NULL);
|
||||
|
||||
SDL_GL_DeleteContext(libs->gl);
|
||||
SDL_DestroyWindow(libs->win);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
static void app_get_dpi_(libs_t* libs, app_args_t* args) {
|
||||
assert(libs != NULL);
|
||||
assert(args != NULL);
|
||||
|
||||
if (args->override_dpi) return;
|
||||
|
||||
const int32_t disp = SDL_GetWindowDisplayIndex(libs->win);
|
||||
|
||||
float x, y;
|
||||
if (SDL_GetDisplayDPI(disp, NULL, &x, &y) == 0) {
|
||||
args->scene.dpi = vec2(x, y);
|
||||
} else {
|
||||
fprintf(stderr, "failed to get display DPI: %s\n", SDL_GetError());
|
||||
fprintf(stderr, "Anti-aliasing may not work properly.\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
(void) argc, (void) argv;
|
||||
|
||||
app_args_t args = app_default_args_;
|
||||
app_args_parse(&args, argc, argv);
|
||||
|
||||
libs_t libs;
|
||||
app_initialize_libraries_(&libs, &args);
|
||||
|
||||
app_get_dpi_(&libs, &args);
|
||||
|
||||
loscene_context_t* ctx = loscene_context_new(&args.scene);
|
||||
|
||||
locommon_input_t input = {
|
||||
.resolution = vec2(args.scene.width, args.scene.height),
|
||||
.dpi = args.scene.dpi,
|
||||
.cursor = vec2(0, 0),
|
||||
};
|
||||
|
||||
glClearColor(0, 0, 0, 0);
|
||||
|
||||
const uint64_t min_frame_time = 1000 / args.max_fps;
|
||||
for (;;) {
|
||||
const uint64_t base_time = SDL_GetTicks();
|
||||
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
if (!app_event_handle(&input, &e)) goto EXIT;
|
||||
}
|
||||
|
||||
if (!loscene_context_update(ctx, &input, base_time)) goto EXIT;
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
loscene_context_draw(ctx);
|
||||
SDL_GL_SwapWindow(libs.win);
|
||||
|
||||
# ifndef NDEBUG
|
||||
/* for debugging in MSYS */
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
# endif
|
||||
|
||||
const uint64_t elapsed = SDL_GetTicks() - base_time;
|
||||
if (elapsed < min_frame_time) {
|
||||
SDL_Delay(min_frame_time - elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
EXIT:
|
||||
loscene_context_delete(ctx);
|
||||
app_deinitialize_libraries_(&libs);
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user