commit
69bc08cdde
|
@ -22,4 +22,10 @@
|
|||
#define CAMERA_RATIO_X 16.0f
|
||||
#define CAMERA_RATIO_Y 9.0f
|
||||
|
||||
#define METADATA_TITLE_MAX_SIZE 256
|
||||
#define METADATA_VERSION_MAX_SIZE 256
|
||||
#define METADATA_FILEPATH_MAX_SIZE 512
|
||||
|
||||
#define VERSION "1"
|
||||
|
||||
#endif // CONFIG_H_
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#define DYNARRAY_INIT_CAPACITY 8
|
||||
|
||||
void *dynarray_pointer_at(Dynarray *dynarray, size_t index)
|
||||
void *dynarray_pointer_at(const Dynarray *dynarray, size_t index)
|
||||
{
|
||||
trace_assert(index < dynarray->count);
|
||||
return (uint8_t *)dynarray->data + index * dynarray->element_size;
|
||||
|
|
|
@ -24,7 +24,7 @@ Dynarray create_dynarray(size_t element_size)
|
|||
return result;
|
||||
}
|
||||
|
||||
void *dynarray_pointer_at(Dynarray *dynarray, size_t index);
|
||||
void *dynarray_pointer_at(const Dynarray *dynarray, size_t index);
|
||||
void dynarray_replace_at(Dynarray *dynarray, size_t index, void *element);
|
||||
void dynarray_copy_to(Dynarray *dynarray, void *dest, size_t index);
|
||||
void dynarray_clear(Dynarray *dynarray);
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#include "color.h"
|
||||
#include "game/camera.h"
|
||||
|
||||
typedef struct LineStream LineStream;
|
||||
|
||||
typedef struct {
|
||||
Color base_color;
|
||||
} Background;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
typedef struct Boxes Boxes;
|
||||
typedef struct Player Player;
|
||||
typedef struct LineStream LineStream;
|
||||
typedef struct Player Player;
|
||||
typedef struct RectLayer RectLayer;
|
||||
|
||||
|
|
|
@ -35,83 +35,6 @@ struct Goals {
|
|||
float angle;
|
||||
};
|
||||
|
||||
Goals *create_goals_from_line_stream(LineStream *line_stream)
|
||||
{
|
||||
trace_assert(line_stream);
|
||||
|
||||
Lt *lt = create_lt();
|
||||
|
||||
Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
|
||||
if (goals == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
goals->count = 0;
|
||||
if (sscanf(
|
||||
line_stream_next(line_stream),
|
||||
"%zu",
|
||||
&goals->count) == EOF) {
|
||||
log_fail("Could not read amount of goals\n");
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
goals->ids = PUSH_LT(
|
||||
lt,
|
||||
nth_calloc(1, sizeof(char*) * goals->count),
|
||||
free);
|
||||
if (goals->ids == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
for (size_t i = 0; i < goals->count; ++i) {
|
||||
goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
|
||||
if (goals->ids[i] == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * goals->count), free);
|
||||
if (goals->positions == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
|
||||
if (goals->colors == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
|
||||
if (goals->cue_states == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
|
||||
if (goals->visible == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
char color[7];
|
||||
for (size_t i = 0; i < goals->count; ++i) {
|
||||
if (sscanf(
|
||||
line_stream_next(line_stream),
|
||||
"%" STRINGIFY(ENTITY_MAX_ID_SIZE) "s%f%f%6s",
|
||||
goals->ids[i],
|
||||
&goals->positions[i].x,
|
||||
&goals->positions[i].y,
|
||||
color) < 0) {
|
||||
log_fail("Could not read %dth goal\n", i);
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
goals->colors[i] = hexstr(color);
|
||||
goals->cue_states[i] = CUE_STATE_VIRGIN;
|
||||
goals->visible[i] = true;
|
||||
}
|
||||
|
||||
goals->lt = lt;
|
||||
goals->angle = 0.0f;
|
||||
|
||||
return goals;
|
||||
}
|
||||
|
||||
Goals *create_goals_from_point_layer(const PointLayer *point_layer)
|
||||
{
|
||||
trace_assert(point_layer);
|
||||
|
|
|
@ -9,10 +9,8 @@
|
|||
#include "config.h"
|
||||
|
||||
typedef struct Goals Goals;
|
||||
typedef struct LineStream LineStream;
|
||||
typedef struct PointLayer PointLayer;
|
||||
|
||||
Goals *create_goals_from_line_stream(LineStream *line_stream);
|
||||
Goals *create_goals_from_point_layer(const PointLayer *point_layer);
|
||||
void destroy_goals(Goals *goals);
|
||||
|
||||
|
|
|
@ -34,96 +34,6 @@ struct Labels
|
|||
enum LabelState *states;
|
||||
};
|
||||
|
||||
Labels *create_labels_from_line_stream(LineStream *line_stream)
|
||||
{
|
||||
trace_assert(line_stream);
|
||||
|
||||
Lt *lt = create_lt();
|
||||
|
||||
Labels * const labels = PUSH_LT(lt, nth_calloc(1, sizeof(Labels)), free);
|
||||
if (labels == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
labels->lt = lt;
|
||||
|
||||
if (sscanf(
|
||||
line_stream_next(line_stream),
|
||||
"%zu",
|
||||
&labels->count) == EOF) {
|
||||
log_fail("Could not read amount of labels\n");
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->ids = PUSH_LT(lt, nth_calloc(labels->count, sizeof(char) * ENTITY_MAX_ID_SIZE), free);
|
||||
if (labels->ids == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Vec2f) * labels->count), free);
|
||||
if (labels->positions == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * labels->count), free);
|
||||
if (labels->colors == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->texts = PUSH_LT(lt, nth_calloc(1, sizeof(char*) * labels->count), free);
|
||||
if (labels->texts == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->alphas = PUSH_LT(lt, nth_calloc(1, sizeof(float) * labels->count), free);
|
||||
if (labels->alphas == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->delta_alphas = PUSH_LT(lt, nth_calloc(1, sizeof(float) * labels->count), free);
|
||||
if (labels->delta_alphas == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->states = PUSH_LT(lt, nth_calloc(1, sizeof(enum LabelState) * labels->count), free);
|
||||
if (labels->states == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
char color[7];
|
||||
for (size_t i = 0; i < labels->count; ++i) {
|
||||
if (sscanf(
|
||||
line_stream_next(line_stream),
|
||||
"%" STRINGIFY(ENTITY_MAX_ID_SIZE) "s%f%f%6s\n",
|
||||
labels->ids + i * ENTITY_MAX_ID_SIZE,
|
||||
&labels->positions[i].x,
|
||||
&labels->positions[i].y,
|
||||
color) == EOF) {
|
||||
log_fail("Could not read position and color of %dth label\n", i);
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->colors[i] = hexstr(color);
|
||||
|
||||
const char *label_text = line_stream_next(line_stream);
|
||||
if (label_text == NULL) {
|
||||
log_fail("Could not read text of %dth label\n", i);
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
labels->texts[i] = PUSH_LT(
|
||||
lt,
|
||||
string_duplicate(label_text, NULL),
|
||||
free);
|
||||
if (labels->texts[i] == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
trim_endline(labels->texts[i]);
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
|
||||
Labels *create_labels_from_label_layer(const LabelLayer *label_layer)
|
||||
{
|
||||
trace_assert(label_layer);
|
||||
|
|
|
@ -6,10 +6,8 @@
|
|||
#include "config.h"
|
||||
|
||||
typedef struct Labels Labels;
|
||||
typedef struct LineStream LineStream;
|
||||
typedef struct LabelLayer LabelLayer;
|
||||
|
||||
Labels *create_labels_from_line_stream(LineStream *line_stream);
|
||||
Labels *create_labels_from_label_layer(const LabelLayer *label_layer);
|
||||
void destroy_labels(Labels *label);
|
||||
|
||||
|
|
|
@ -20,42 +20,6 @@ struct Lava {
|
|||
Wavy_rect **rects;
|
||||
};
|
||||
|
||||
Lava *create_lava_from_line_stream(LineStream *line_stream)
|
||||
{
|
||||
trace_assert(line_stream);
|
||||
|
||||
Lt *lt = create_lt();
|
||||
|
||||
Lava *lava = PUSH_LT(lt, nth_calloc(1, sizeof(Lava)), free);
|
||||
if (lava == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
if (sscanf(
|
||||
line_stream_next(line_stream),
|
||||
"%zu",
|
||||
&lava->rects_count) < 0) {
|
||||
log_fail("Could not read amount of lava\n");
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
lava->rects = PUSH_LT(lt, nth_calloc(1, sizeof(Wavy_rect*) * lava->rects_count), free);
|
||||
if (lava->rects == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < lava->rects_count; ++i) {
|
||||
lava->rects[i] = PUSH_LT(lt, create_wavy_rect_from_line_stream(line_stream), destroy_wavy_rect);
|
||||
if (lava->rects[i] == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
lava->lt = lt;
|
||||
|
||||
return lava;
|
||||
}
|
||||
|
||||
Lava *create_lava_from_rect_layer(const RectLayer *rect_layer)
|
||||
{
|
||||
Lt *lt = create_lt();
|
||||
|
|
|
@ -8,10 +8,8 @@
|
|||
#include "math/rect.h"
|
||||
|
||||
typedef struct Lava Lava;
|
||||
typedef struct LineStream LineStream;
|
||||
typedef struct RectLayer RectLayer;
|
||||
|
||||
Lava *create_lava_from_line_stream(LineStream *line_stream);
|
||||
Lava *create_lava_from_rect_layer(const RectLayer *rect_layer);
|
||||
void destroy_lava(Lava *lava);
|
||||
|
||||
|
|
|
@ -39,27 +39,6 @@ Wavy_rect *create_wavy_rect(Rect rect, Color color)
|
|||
return wavy_rect;
|
||||
}
|
||||
|
||||
Wavy_rect *create_wavy_rect_from_line_stream(LineStream *line_stream)
|
||||
{
|
||||
trace_assert(line_stream);
|
||||
char color_name[7];
|
||||
Rect rect;
|
||||
|
||||
if (sscanf(
|
||||
line_stream_next(line_stream),
|
||||
"%f%f%f%f%6s\n",
|
||||
&rect.x, &rect.y,
|
||||
&rect.w, &rect.h,
|
||||
color_name) < 0) {
|
||||
log_fail("Could not read a wavy rect\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Color color = hexstr(color_name);
|
||||
|
||||
return create_wavy_rect(rect, color);
|
||||
}
|
||||
|
||||
void destroy_wavy_rect(Wavy_rect *wavy_rect)
|
||||
{
|
||||
trace_assert(wavy_rect);
|
||||
|
|
|
@ -8,10 +8,8 @@
|
|||
#include "math/rect.h"
|
||||
|
||||
typedef struct Wavy_rect Wavy_rect;
|
||||
typedef struct LineStream LineStream;
|
||||
|
||||
Wavy_rect *create_wavy_rect(Rect rect, Color color);
|
||||
Wavy_rect *create_wavy_rect_from_line_stream(LineStream *line_stream);
|
||||
void destroy_wavy_rect(Wavy_rect *wavy_rect);
|
||||
|
||||
int wavy_rect_render(const Wavy_rect *wavy_rect,
|
||||
|
|
|
@ -63,12 +63,12 @@ LevelEditor *create_level_editor(Cursor *cursor)
|
|||
memset(level_editor->metadata.version, 0, METADATA_VERSION_MAX_SIZE);
|
||||
memcpy(level_editor->metadata.version,
|
||||
VERSION,
|
||||
min_size_t(sizeof(VERSION), METADATA_VERSION_MAX_SIZE - 1));
|
||||
MIN(size_t, sizeof(VERSION), METADATA_VERSION_MAX_SIZE - 1));
|
||||
|
||||
memset(level_editor->metadata.title, 0, METADATA_TITLE_MAX_SIZE);
|
||||
memcpy(level_editor->metadata.title,
|
||||
DEFAULT_LEVEL_TITLE,
|
||||
min_size_t(sizeof(DEFAULT_LEVEL_TITLE), METADATA_TITLE_MAX_SIZE - 1));
|
||||
MIN(size_t, sizeof(DEFAULT_LEVEL_TITLE), METADATA_TITLE_MAX_SIZE - 1));
|
||||
|
||||
level_editor->background_layer = create_background_layer(hexstr("fffda5"));
|
||||
|
||||
|
@ -196,7 +196,7 @@ LevelEditor *create_level_editor_from_file(const char *file_name, Cursor *cursor
|
|||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
if (metadata_load_from_line_stream(&level_editor->metadata, level_stream) < 0) {
|
||||
if (metadata_load_from_line_stream(&level_editor->metadata, level_stream, level_editor->file_name) < 0) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "math/rect.h"
|
||||
|
||||
typedef struct Platforms Platforms;
|
||||
typedef struct LineStream LineStream;
|
||||
typedef struct RectLayer RectLayer;
|
||||
|
||||
Platforms *create_platforms_from_rect_layer(const RectLayer *layer);
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
typedef struct Player Player;
|
||||
typedef struct Goals Goals;
|
||||
typedef struct LineStream LineStream;
|
||||
typedef struct RigidBodies RigidBodies;
|
||||
|
||||
Player *create_player_from_player_layer(const PlayerLayer *player_layer,
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
typedef struct Regions Regions;
|
||||
typedef struct Player Player;
|
||||
typedef struct LineStream LineStream;
|
||||
typedef struct Level Level;
|
||||
typedef struct RectLayer RectLayer;
|
||||
typedef struct Labels Labels;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
typedef struct RigidBodies RigidBodies;
|
||||
typedef struct Platforms Platforms;
|
||||
typedef struct LineStream LineStream;
|
||||
|
||||
typedef size_t RigidBodyId;
|
||||
|
||||
|
|
|
@ -15,102 +15,40 @@
|
|||
|
||||
#include "./level_folder.h"
|
||||
|
||||
#define LEVEL_FOLDER_MAX_LENGTH 512
|
||||
|
||||
struct LevelFolder
|
||||
void level_folder_read(const char *dirpath, LevelFolder *folder)
|
||||
{
|
||||
Lt *lt;
|
||||
Dynarray filenames;
|
||||
Dynarray titles;
|
||||
};
|
||||
|
||||
LevelFolder *create_level_folder(const char *dirpath)
|
||||
{
|
||||
trace_assert(dirpath);
|
||||
|
||||
Lt *lt = create_lt();
|
||||
|
||||
LevelFolder *level_folder = PUSH_LT(
|
||||
lt,
|
||||
nth_calloc(1, sizeof(LevelFolder)),
|
||||
free);
|
||||
if (level_folder == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
DIR *level_dir = opendir(dirpath);
|
||||
if (level_dir == NULL) {
|
||||
log_fail("Can't open asset folder: %s\n", dirpath);
|
||||
abort();
|
||||
}
|
||||
level_folder->lt = lt;
|
||||
|
||||
level_folder->filenames = create_dynarray(sizeof(const char*));
|
||||
level_folder->titles = create_dynarray(sizeof(const char*));
|
||||
dynarray_clear(&folder->metadatas);
|
||||
|
||||
char path[LEVEL_FOLDER_MAX_LENGTH];
|
||||
DIR *level_dir = PUSH_LT(lt, opendir(dirpath), closedir_lt);
|
||||
|
||||
LevelMetadata level_metadata;
|
||||
char filepath[METADATA_FILEPATH_MAX_SIZE];
|
||||
LevelMetadata metadata;
|
||||
for (struct dirent *d = readdir(level_dir);
|
||||
d != NULL;
|
||||
d = readdir(level_dir)) {
|
||||
if (*d->d_name == '.') {
|
||||
if (*d->d_name == '.') continue;
|
||||
|
||||
snprintf(filepath, METADATA_FILEPATH_MAX_SIZE,
|
||||
"%s/%s", dirpath, d->d_name);
|
||||
|
||||
if (metadata_load_from_file(&metadata, filepath) < 0) {
|
||||
log_warn("Can't read level: %s\n", filepath);
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(path, LEVEL_FOLDER_MAX_LENGTH, "%s/%s", dirpath, d->d_name);
|
||||
const char *filepath = PUSH_LT(lt, string_duplicate(trim_endline(path), NULL), free);
|
||||
if (filepath == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
if (metadata_load_from_file(&level_metadata, filepath) < 0) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
|
||||
const char *version = PUSH_LT(
|
||||
lt,
|
||||
string_duplicate(level_metadata.version, NULL),
|
||||
free);
|
||||
const char *title = PUSH_LT(
|
||||
lt,
|
||||
string_duplicate(level_metadata.title, NULL),
|
||||
free);
|
||||
|
||||
if(strcmp(version, VERSION) == 0) {
|
||||
dynarray_push(&level_folder->titles, &title);
|
||||
dynarray_push(&level_folder->filenames, &filepath);
|
||||
} else {
|
||||
log_info(
|
||||
if(strcmp(metadata.version, VERSION) != 0) {
|
||||
log_warn(
|
||||
"Unsupported version for level [%s]: Expected `%s`, got `%s`\n",
|
||||
d->d_name,
|
||||
VERSION,
|
||||
version);
|
||||
filepath, VERSION, metadata.version);
|
||||
continue;
|
||||
}
|
||||
|
||||
dynarray_push(&folder->metadatas, &metadata);
|
||||
}
|
||||
|
||||
closedir(RELEASE_LT(lt, level_dir));
|
||||
|
||||
return level_folder;
|
||||
}
|
||||
|
||||
void destroy_level_folder(LevelFolder *level_folder)
|
||||
{
|
||||
trace_assert(level_folder);
|
||||
free(level_folder->filenames.data);
|
||||
free(level_folder->titles.data);
|
||||
RETURN_LT0(level_folder->lt);
|
||||
}
|
||||
|
||||
const char **level_folder_filenames(const LevelFolder *level_folder)
|
||||
{
|
||||
trace_assert(level_folder);
|
||||
return (const char **)level_folder->filenames.data;
|
||||
}
|
||||
|
||||
const char **level_folder_titles(const LevelFolder *level_folder)
|
||||
{
|
||||
trace_assert(level_folder);
|
||||
return (const char **)level_folder->titles.data;
|
||||
}
|
||||
|
||||
size_t level_folder_count(const LevelFolder *level_folder)
|
||||
{
|
||||
trace_assert(level_folder);
|
||||
return level_folder->filenames.count;
|
||||
closedir(level_dir);
|
||||
}
|
||||
|
|
|
@ -1,13 +1,27 @@
|
|||
#ifndef LEVEL_FOLDER_H_
|
||||
#define LEVEL_FOLDER_H_
|
||||
|
||||
typedef struct LevelFolder LevelFolder;
|
||||
#include "level_metadata.h"
|
||||
|
||||
LevelFolder *create_level_folder(const char *dirpath);
|
||||
void destroy_level_folder(LevelFolder *level_folder);
|
||||
typedef struct {
|
||||
Dynarray metadatas;
|
||||
} LevelFolder;
|
||||
|
||||
const char **level_folder_filenames(const LevelFolder *level_folder);
|
||||
const char **level_folder_titles(const LevelFolder *level_folder);
|
||||
size_t level_folder_count(const LevelFolder *level_folder);
|
||||
static inline
|
||||
LevelFolder create_level_folder(void)
|
||||
{
|
||||
LevelFolder result = {
|
||||
.metadatas = create_dynarray(sizeof(LevelMetadata)),
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline
|
||||
void destroy_level_folder(LevelFolder level_folder)
|
||||
{
|
||||
free(level_folder.metadatas.data);
|
||||
}
|
||||
|
||||
void level_folder_read(const char *dirpath, LevelFolder *folder);
|
||||
|
||||
#endif // LEVEL_FOLDER_H_
|
||||
|
|
|
@ -9,21 +9,16 @@
|
|||
#include "level_metadata.h"
|
||||
#include "math/extrema.h"
|
||||
|
||||
struct LevelMetadata
|
||||
{
|
||||
Lt *lt;
|
||||
const char *version;
|
||||
const char *title;
|
||||
};
|
||||
|
||||
int metadata_load_from_line_stream(LevelMetadata *metadata,
|
||||
LineStream *line_stream)
|
||||
LineStream *line_stream,
|
||||
const char *filepath)
|
||||
{
|
||||
trace_assert(metadata);
|
||||
trace_assert(line_stream);
|
||||
|
||||
memset(metadata->version, 0, METADATA_VERSION_MAX_SIZE);
|
||||
memset(metadata->title, 0, METADATA_TITLE_MAX_SIZE);
|
||||
memset(metadata->filepath, 0, METADATA_FILEPATH_MAX_SIZE);
|
||||
|
||||
const char *line = line_stream_next(line_stream);
|
||||
if (line == NULL) return -1;
|
||||
|
@ -41,18 +36,23 @@ int metadata_load_from_line_stream(LevelMetadata *metadata,
|
|||
min_size_t(strlen(line), METADATA_VERSION_MAX_SIZE - 1));
|
||||
trim_endline(metadata->title);
|
||||
|
||||
memcpy(metadata->filepath,
|
||||
filepath,
|
||||
min_size_t(strlen(filepath), METADATA_FILEPATH_MAX_SIZE - 1));
|
||||
trim_endline(metadata->filepath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int metadata_load_from_file(LevelMetadata *metadata, const char *filename)
|
||||
int metadata_load_from_file(LevelMetadata *metadata, const char *filepath)
|
||||
{
|
||||
trace_assert(metadata);
|
||||
trace_assert(filename);
|
||||
trace_assert(filepath);
|
||||
|
||||
LineStream *line_stream = create_line_stream(filename, "r", 256);
|
||||
LineStream *line_stream = create_line_stream(filepath, "r", 256);
|
||||
if (line_stream == NULL) return -1;
|
||||
|
||||
int err = metadata_load_from_line_stream(metadata, line_stream);
|
||||
int err = metadata_load_from_line_stream(metadata, line_stream, filepath);
|
||||
destroy_line_stream(line_stream);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,17 @@
|
|||
#ifndef LEVEL_METADATA_H_
|
||||
#define LEVEL_METADATA_H_
|
||||
|
||||
#include "config.h"
|
||||
|
||||
typedef struct LineStream LineStream;
|
||||
|
||||
#define VERSION "1"
|
||||
|
||||
#define METADATA_TITLE_MAX_SIZE 256
|
||||
#define METADATA_VERSION_MAX_SIZE 256
|
||||
|
||||
typedef struct {
|
||||
char filepath[METADATA_FILEPATH_MAX_SIZE];
|
||||
char version[METADATA_VERSION_MAX_SIZE];
|
||||
char title[METADATA_TITLE_MAX_SIZE];
|
||||
} LevelMetadata;
|
||||
|
||||
int metadata_load_from_file(LevelMetadata *metadata, const char *file);
|
||||
int metadata_load_from_line_stream(LevelMetadata *metadata, LineStream *line_stream);
|
||||
int metadata_load_from_file(LevelMetadata *metadata, const char *filepath);
|
||||
int metadata_load_from_line_stream(LevelMetadata *metadata, LineStream *line_stream, const char *filepath);
|
||||
|
||||
#endif // LEVEL_METADATA_H_
|
||||
|
|
|
@ -21,11 +21,18 @@ struct LevelPicker
|
|||
Lt *lt;
|
||||
Background background;
|
||||
Vec2f camera_position;
|
||||
LevelFolder *level_folder;
|
||||
LevelFolder level_folder;
|
||||
WigglyText wiggly_text;
|
||||
ListSelector *list_selector;
|
||||
ListSelector list_selector;
|
||||
};
|
||||
|
||||
static inline
|
||||
const char *list_item_text(void *element)
|
||||
{
|
||||
trace_assert(element);
|
||||
return ((LevelMetadata *)element)->title;
|
||||
}
|
||||
|
||||
LevelPicker *create_level_picker(const char *dirpath)
|
||||
{
|
||||
trace_assert(dirpath);
|
||||
|
@ -45,13 +52,8 @@ LevelPicker *create_level_picker(const char *dirpath)
|
|||
|
||||
level_picker->camera_position = vec(0.0f, 0.0f);
|
||||
|
||||
level_picker->level_folder = PUSH_LT(
|
||||
lt,
|
||||
create_level_folder(dirpath),
|
||||
destroy_level_folder);
|
||||
if (level_picker->level_folder == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
level_picker->level_folder = create_level_folder();
|
||||
level_folder_read("./assets/levels", &level_picker->level_folder);
|
||||
|
||||
level_picker->wiggly_text = (WigglyText) {
|
||||
.text = "Select Level",
|
||||
|
@ -59,17 +61,10 @@ LevelPicker *create_level_picker(const char *dirpath)
|
|||
.color = COLOR_WHITE,
|
||||
};
|
||||
|
||||
level_picker->list_selector = PUSH_LT(
|
||||
lt,
|
||||
create_list_selector(
|
||||
level_folder_titles(level_picker->level_folder),
|
||||
level_folder_count(level_picker->level_folder),
|
||||
vec(5.0f, 5.0f),
|
||||
50.0f),
|
||||
destroy_list_selector);
|
||||
if (level_picker->list_selector == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
level_picker->list_selector.items = level_picker->level_folder.metadatas;
|
||||
level_picker->list_selector.font_scale = vec(5.0f, 5.0f);
|
||||
level_picker->list_selector.padding_bottom = 50.0f;
|
||||
level_picker->list_selector.list_item_text = list_item_text;
|
||||
|
||||
return level_picker;
|
||||
}
|
||||
|
@ -77,6 +72,7 @@ LevelPicker *create_level_picker(const char *dirpath)
|
|||
void destroy_level_picker(LevelPicker *level_picker)
|
||||
{
|
||||
trace_assert(level_picker);
|
||||
destroy_level_folder(level_picker->level_folder);
|
||||
RETURN_LT0(level_picker->lt);
|
||||
}
|
||||
|
||||
|
@ -98,9 +94,7 @@ int level_picker_render(const LevelPicker *level_picker,
|
|||
camera,
|
||||
vec(viewport.w * 0.5f - title_size.x * 0.5f, TITLE_MARGIN_TOP));
|
||||
|
||||
if (list_selector_render(camera, level_picker->list_selector) < 0) {
|
||||
return -1;
|
||||
}
|
||||
list_selector_render(camera, &level_picker->list_selector);
|
||||
|
||||
{
|
||||
/* CSS */
|
||||
|
@ -156,20 +150,19 @@ int level_picker_event(LevelPicker *level_picker,
|
|||
const Vec2f title_size = wiggly_text_size(&level_picker->wiggly_text);
|
||||
|
||||
const Vec2f selector_size = list_selector_size(
|
||||
level_picker->list_selector,
|
||||
&level_picker->list_selector,
|
||||
font_scale,
|
||||
padding_bottom);
|
||||
|
||||
list_selector_move(
|
||||
level_picker->list_selector,
|
||||
level_picker->list_selector.position =
|
||||
vec((float)width * 0.5f - selector_size.x * 0.5f,
|
||||
TITLE_MARGIN_TOP + title_size.y + TITLE_MARGIN_BOTTOM));
|
||||
TITLE_MARGIN_TOP + title_size.y + TITLE_MARGIN_BOTTOM);
|
||||
} break;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
|
||||
return list_selector_event(level_picker->list_selector, event);
|
||||
return list_selector_event(&level_picker->list_selector, event);
|
||||
}
|
||||
|
||||
int level_picker_input(LevelPicker *level_picker,
|
||||
|
@ -186,20 +179,21 @@ const char *level_picker_selected_level(const LevelPicker *level_picker)
|
|||
{
|
||||
trace_assert(level_picker);
|
||||
|
||||
const int selected_index = list_selector_selected(level_picker->list_selector);
|
||||
if (selected_index < 0) {
|
||||
if (level_picker->list_selector.selected_item < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char **filenames = level_folder_filenames(level_picker->level_folder);
|
||||
LevelMetadata *metadata = dynarray_pointer_at(
|
||||
&level_picker->level_folder.metadatas,
|
||||
(size_t)level_picker->list_selector.selected_item);
|
||||
|
||||
return filenames[selected_index];
|
||||
return metadata->filepath;
|
||||
}
|
||||
|
||||
void level_picker_clean_selection(LevelPicker *level_picker)
|
||||
{
|
||||
trace_assert(level_picker);
|
||||
list_selector_clean_selection(level_picker->list_selector);
|
||||
level_picker->list_selector.selected_item = -1;
|
||||
}
|
||||
|
||||
int level_picker_enter_camera_event(LevelPicker *level_picker,
|
||||
|
|
|
@ -233,7 +233,7 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
const int64_t end_frame_time = (int64_t) SDL_GetTicks();
|
||||
SDL_Delay((unsigned int) max_int64(10, delta_time - (end_frame_time - begin_frame_time)));
|
||||
SDL_Delay((unsigned int) MAX(int64_t, 10, delta_time - (end_frame_time - begin_frame_time)));
|
||||
}
|
||||
|
||||
RETURN_LT(lt, 0);
|
||||
|
|
|
@ -3,25 +3,24 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
// WARNING! Any attempts to "generalize" or "improve" this translation
|
||||
// unit will result in an instantly closed Pull Request without any
|
||||
// further discussion.
|
||||
static inline
|
||||
int64_t max_int64(int64_t a, int64_t b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
#define MAX_INSTANCE(type) \
|
||||
static inline \
|
||||
type max_##type(type a, type b) { \
|
||||
return a > b ? a : b; \
|
||||
} \
|
||||
|
||||
static inline
|
||||
size_t max_size_t(size_t a, size_t b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
MAX_INSTANCE(int64_t)
|
||||
MAX_INSTANCE(size_t)
|
||||
#define MAX(type, a, b) max_##type(a, b)
|
||||
|
||||
static inline
|
||||
size_t min_size_t(size_t a, size_t b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
#define MIN_INSTANCE(type) \
|
||||
static inline \
|
||||
type min_##type(type a, type b) { \
|
||||
return a < b ? a : b; \
|
||||
} \
|
||||
|
||||
MIN_INSTANCE(int64_t)
|
||||
MIN_INSTANCE(size_t)
|
||||
#define MIN(type, a, b) min_##type(a, b)
|
||||
|
||||
#endif // EXTREMA_H_
|
||||
|
|
|
@ -13,49 +13,6 @@
|
|||
|
||||
#include "./list_selector.h"
|
||||
|
||||
struct ListSelector
|
||||
{
|
||||
Lt *lt;
|
||||
const char **items;
|
||||
size_t count;
|
||||
size_t cursor;
|
||||
int selected_item;
|
||||
Vec2f position;
|
||||
Vec2f font_scale;
|
||||
float padding_bottom;
|
||||
};
|
||||
|
||||
ListSelector *create_list_selector(const char *items[],
|
||||
size_t count,
|
||||
Vec2f font_scale,
|
||||
float padding_bottom)
|
||||
{
|
||||
trace_assert(items);
|
||||
|
||||
Lt *lt = create_lt();
|
||||
|
||||
ListSelector *list_selector = PUSH_LT(lt, nth_calloc(1, sizeof(ListSelector)), free);
|
||||
if (list_selector == NULL) {
|
||||
RETURN_LT(lt, NULL);
|
||||
}
|
||||
list_selector->lt = lt;
|
||||
|
||||
list_selector->items = items;
|
||||
list_selector->count = count;
|
||||
list_selector->cursor = 0;
|
||||
list_selector->selected_item = -1;
|
||||
list_selector->position = vec(0.0f, 0.0f);
|
||||
list_selector->font_scale = font_scale;
|
||||
list_selector->padding_bottom = padding_bottom;
|
||||
|
||||
return list_selector;
|
||||
}
|
||||
|
||||
void destroy_list_selector(ListSelector *list_selector)
|
||||
{
|
||||
trace_assert(list_selector);
|
||||
RETURN_LT0(list_selector->lt);
|
||||
}
|
||||
|
||||
int list_selector_render(const Camera *camera,
|
||||
const ListSelector *list_selector)
|
||||
|
@ -63,25 +20,31 @@ int list_selector_render(const Camera *camera,
|
|||
trace_assert(camera);
|
||||
trace_assert(list_selector);
|
||||
|
||||
for (size_t i = 0; i < list_selector->count; ++i) {
|
||||
for (size_t i = 0; i < list_selector->items.count; ++i) {
|
||||
const Vec2f current_position = vec_sum(
|
||||
list_selector->position,
|
||||
vec(0.0f, (float) i * ((float) FONT_CHAR_HEIGHT * list_selector->font_scale.y + list_selector->padding_bottom)));
|
||||
|
||||
const char *item_text =
|
||||
list_selector->list_item_text(
|
||||
dynarray_pointer_at(
|
||||
&list_selector->items,
|
||||
i));
|
||||
|
||||
sprite_font_render_text(
|
||||
&camera->font,
|
||||
camera->renderer,
|
||||
current_position,
|
||||
list_selector->font_scale,
|
||||
rgba(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
list_selector->items[i]);
|
||||
item_text);
|
||||
|
||||
if (i == list_selector->cursor) {
|
||||
SDL_Rect boundary_box = rect_for_sdl(
|
||||
sprite_font_boundary_box(
|
||||
current_position,
|
||||
list_selector->font_scale,
|
||||
strlen(list_selector->items[i])));
|
||||
strlen(item_text)));
|
||||
if (SDL_SetRenderDrawColor(camera->renderer, 255, 255, 255, 255) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -96,18 +59,24 @@ int list_selector_render(const Camera *camera,
|
|||
}
|
||||
|
||||
Vec2f list_selector_size(const ListSelector *list_selector,
|
||||
Vec2f font_scale,
|
||||
float padding_bottom)
|
||||
Vec2f font_scale,
|
||||
float padding_bottom)
|
||||
{
|
||||
trace_assert(list_selector);
|
||||
|
||||
Vec2f result = vec(0.0f, 0.0f);
|
||||
|
||||
for (size_t i = 0; i < list_selector->count; ++i) {
|
||||
for (size_t i = 0; i < list_selector->items.count; ++i) {
|
||||
const char *item_text =
|
||||
list_selector->list_item_text(
|
||||
dynarray_pointer_at(
|
||||
&list_selector->items,
|
||||
i));
|
||||
|
||||
Rect boundary_box = sprite_font_boundary_box(
|
||||
vec(0.0f, 0.0f),
|
||||
font_scale,
|
||||
strlen(list_selector->items[i]));
|
||||
strlen(item_text));
|
||||
|
||||
result.x = fmaxf(result.x, boundary_box.w);
|
||||
result.y += boundary_box.y + padding_bottom;
|
||||
|
@ -116,14 +85,6 @@ Vec2f list_selector_size(const ListSelector *list_selector,
|
|||
return result;
|
||||
}
|
||||
|
||||
int list_selector_update(ListSelector *list_selector, float delta_time)
|
||||
{
|
||||
trace_assert(list_selector);
|
||||
(void) delta_time;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_selector_event(ListSelector *list_selector, const SDL_Event *event)
|
||||
{
|
||||
trace_assert(list_selector);
|
||||
|
@ -138,7 +99,7 @@ int list_selector_event(ListSelector *list_selector, const SDL_Event *event)
|
|||
}
|
||||
break;
|
||||
case SDLK_DOWN:
|
||||
if (list_selector->cursor < list_selector->count - 1) {
|
||||
if (list_selector->cursor < list_selector->items.count - 1) {
|
||||
list_selector->cursor++;
|
||||
}
|
||||
break;
|
||||
|
@ -152,11 +113,17 @@ int list_selector_event(ListSelector *list_selector, const SDL_Event *event)
|
|||
const Vec2f mouse_pos = vec((float) event->motion.x, (float) event->motion.y);
|
||||
Vec2f position = list_selector->position;
|
||||
|
||||
for (size_t i = 0; i < list_selector->count; ++i) {
|
||||
for (size_t i = 0; i < list_selector->items.count; ++i) {
|
||||
const char *item_text =
|
||||
list_selector->list_item_text(
|
||||
dynarray_pointer_at(
|
||||
&list_selector->items,
|
||||
i));
|
||||
|
||||
Rect boundary_box = sprite_font_boundary_box(
|
||||
position,
|
||||
list_selector->font_scale,
|
||||
strlen(list_selector->items[i]));
|
||||
strlen(item_text));
|
||||
|
||||
if (rect_contains_point(boundary_box, mouse_pos)) {
|
||||
list_selector->cursor = i;
|
||||
|
@ -172,23 +139,27 @@ int list_selector_event(ListSelector *list_selector, const SDL_Event *event)
|
|||
// check if the click position was actually inside...
|
||||
// note: make sure there's actually stuff in the list! tsoding likes
|
||||
// to remove all levels and change title to "SMOL BREAK"...
|
||||
if (list_selector->count == 0)
|
||||
if (list_selector->items.count == 0)
|
||||
break;
|
||||
|
||||
// note: this assumes that all list items are the same height!
|
||||
// this is probably a valid assumption as long as we use a sprite font.
|
||||
float single_item_height = sprite_font_boundary_box(
|
||||
list_selector->position,
|
||||
list_selector->font_scale,
|
||||
strlen(list_selector->items[0])).h + list_selector->padding_bottom;
|
||||
float single_item_height =
|
||||
FONT_CHAR_HEIGHT * list_selector->font_scale.y + list_selector->padding_bottom;
|
||||
|
||||
Vec2f position = list_selector->position;
|
||||
vec_add(&position, vec(0.0f, (float) list_selector->cursor * single_item_height));
|
||||
|
||||
const char *item_text =
|
||||
list_selector->list_item_text(
|
||||
dynarray_pointer_at(
|
||||
&list_selector->items,
|
||||
list_selector->cursor));
|
||||
|
||||
Rect boundary_box = sprite_font_boundary_box(
|
||||
position,
|
||||
list_selector->font_scale,
|
||||
strlen(list_selector->items[list_selector->cursor]));
|
||||
strlen(item_text));
|
||||
|
||||
const Vec2f mouse_pos = vec((float) event->motion.x, (float) event->motion.y);
|
||||
if (rect_contains_point(boundary_box, mouse_pos)) {
|
||||
|
@ -201,20 +172,3 @@ int list_selector_event(ListSelector *list_selector, const SDL_Event *event)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_selector_selected(const ListSelector *list_selector)
|
||||
{
|
||||
trace_assert(list_selector);
|
||||
return list_selector->selected_item;
|
||||
}
|
||||
|
||||
void list_selector_clean_selection(ListSelector *list_selector)
|
||||
{
|
||||
trace_assert(list_selector);
|
||||
list_selector->selected_item = -1;
|
||||
}
|
||||
|
||||
void list_selector_move(ListSelector *list_selector, Vec2f position)
|
||||
{
|
||||
list_selector->position = position;
|
||||
}
|
||||
|
|
|
@ -2,27 +2,32 @@
|
|||
#define LIST_SELECTOR_H_
|
||||
|
||||
#include "game/camera.h"
|
||||
#include "dynarray.h"
|
||||
|
||||
typedef struct ListSelector ListSelector;
|
||||
typedef const char *(*ListItemText)(void *element);
|
||||
|
||||
ListSelector *create_list_selector(const char *items[],
|
||||
size_t count,
|
||||
Vec2f font_scale,
|
||||
float padding_bottom);
|
||||
void destroy_list_selector(ListSelector *list_selector);
|
||||
typedef struct {
|
||||
Dynarray items;
|
||||
size_t cursor;
|
||||
int selected_item;
|
||||
Vec2f position;
|
||||
Vec2f font_scale;
|
||||
float padding_bottom;
|
||||
ListItemText list_item_text;
|
||||
} ListSelector;
|
||||
|
||||
int list_selector_render(const Camera *camera,
|
||||
const ListSelector *list_selector);
|
||||
Vec2f list_selector_size(const ListSelector *list_selector,
|
||||
Vec2f font_scale,
|
||||
float padding_bottom);
|
||||
|
||||
int list_selector_update(ListSelector *list_selector, float delta_time);
|
||||
int list_selector_event(ListSelector *list_selector, const SDL_Event *event);
|
||||
|
||||
int list_selector_selected(const ListSelector *list_selector);
|
||||
void list_selector_clean_selection(ListSelector *list_selector);
|
||||
|
||||
void list_selector_move(ListSelector *list_selector, Vec2f position);
|
||||
static inline
|
||||
void list_selector_clean_selection(ListSelector *list_selector)
|
||||
{
|
||||
trace_assert(list_selector);
|
||||
list_selector->selected_item = -1;
|
||||
}
|
||||
|
||||
#endif // LIST_SELECTOR_H_
|
||||
|
|
Loading…
Reference in New Issue