371 lines
8.7 KiB
C
371 lines
8.7 KiB
C
enum {WALL_COUNT = 64};
|
|
enum {TILE_COUNT = 32};
|
|
|
|
typedef struct data {
|
|
struct {
|
|
transform_t* coins;
|
|
transform_t* eyeballs;
|
|
transform_t* pedestals;
|
|
int coin_count;
|
|
int eyeball_count;
|
|
int pedestal_count;
|
|
} items;
|
|
struct {
|
|
transform_t hundreds;
|
|
transform_t tens;
|
|
transform_t ones;
|
|
transform_t coin;
|
|
aabb_t collider;
|
|
} score;
|
|
size_t wall_count;
|
|
aabb_t walls[WALL_COUNT];
|
|
uint32_t tiles[TILE_COUNT];
|
|
} data_t;
|
|
|
|
mesh_t
|
|
mesh_load(SDL_RWops* ops)
|
|
{
|
|
struct vertex {
|
|
vec3 position;
|
|
vec3 normal;
|
|
vec2 texcoord;
|
|
};
|
|
|
|
uint16_t material_idx;
|
|
{
|
|
SDL_RWread(ops, &material_idx, sizeof(material_idx), 1);
|
|
}
|
|
|
|
GLuint ebo;
|
|
uint16_t index_count;
|
|
{
|
|
SDL_RWread(ops, &index_count, sizeof(index_count), 1);
|
|
uint16_t* indices = scratch_mem_alloc(index_count, sizeof(*indices));
|
|
SDL_RWread(ops, indices, sizeof(*indices), index_count);
|
|
|
|
glGenBuffers(1, &ebo);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
|
glBufferData(
|
|
GL_ELEMENT_ARRAY_BUFFER,
|
|
index_count * sizeof(*indices),
|
|
indices,
|
|
GL_STATIC_DRAW);
|
|
}
|
|
|
|
GLuint vbo;
|
|
{
|
|
uint16_t vertex_count;
|
|
SDL_RWread(ops, &vertex_count, sizeof(vertex_count), 1);
|
|
|
|
struct vertex* vertices = scratch_mem_alloc(vertex_count, sizeof(*vertices));
|
|
SDL_RWread(ops, vertices, sizeof(*vertices), vertex_count);
|
|
|
|
glGenBuffers(1, &vbo);
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
glBufferData(
|
|
GL_ARRAY_BUFFER,
|
|
vertex_count * sizeof(*vertices),
|
|
vertices,
|
|
GL_STATIC_DRAW);
|
|
}
|
|
|
|
GLuint vao;
|
|
{
|
|
glGenVertexArrays(1, &vao);
|
|
glBindVertexArray(vao);
|
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
|
|
|
glEnableVertexAttribArray(0);
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, position));
|
|
|
|
glEnableVertexAttribArray(1);
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, normal));
|
|
|
|
glEnableVertexAttribArray(2);
|
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, texcoord));
|
|
|
|
glBindVertexArray(0);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
mesh_t result = {
|
|
.vao = vao,
|
|
.vbo = vbo,
|
|
.ebo = ebo,
|
|
.index_count = index_count,
|
|
.material = material_idx};
|
|
|
|
return result;
|
|
}
|
|
|
|
material_t
|
|
material_load(SDL_RWops* ops)
|
|
{
|
|
GLuint texture;
|
|
{
|
|
uint16_t width;
|
|
SDL_RWread(ops, &width, sizeof(width), 1);
|
|
|
|
uint16_t height;
|
|
SDL_RWread(ops, &height, sizeof(height), 1);
|
|
|
|
uint8_t channel_count;
|
|
SDL_RWread(ops, &channel_count, sizeof(channel_count), 1);
|
|
|
|
uint8_t* data = scratch_mem_alloc(width * height * channel_count, sizeof(*data));
|
|
SDL_RWread(ops, data, sizeof(*data), width * height * channel_count);
|
|
|
|
glGenTextures(1, &texture);
|
|
glBindTexture(GL_TEXTURE_2D, texture);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
|
}
|
|
|
|
material_t result = {
|
|
.texture = texture};
|
|
|
|
return result;
|
|
}
|
|
|
|
wav_t
|
|
wav_load(SDL_RWops* ops)
|
|
{
|
|
uint32_t length;
|
|
SDL_RWread(ops, &length, sizeof(length), 1);
|
|
|
|
uint32_t sample_rate;
|
|
SDL_RWread(ops, &sample_rate, sizeof(sample_rate), 1);
|
|
|
|
uint8_t channel_count;
|
|
SDL_RWread(ops, &channel_count, sizeof(channel_count), 1);
|
|
|
|
float volume;
|
|
SDL_RWread(ops, &volume, sizeof(volume), 1);
|
|
|
|
bool is_looping;
|
|
SDL_RWread(ops, &is_looping, sizeof(is_looping), 1);
|
|
|
|
size_t size = length * channel_count;
|
|
float* wav_data = engine_mem_alloc(size, sizeof(*wav_data));
|
|
SDL_RWread(ops, wav_data, sizeof(*wav_data), size);
|
|
|
|
int byte_count = length * channel_count * sizeof(*wav_data);
|
|
|
|
wav_t result = {
|
|
.data = wav_data,
|
|
.byte_count = byte_count,
|
|
.sample_rate = sample_rate,
|
|
.volume = volume};
|
|
|
|
return result;
|
|
}
|
|
|
|
data_t
|
|
data_load(const char* path)
|
|
{
|
|
SDL_RWops* ops = SDL_RWFromFile(path, "rb");
|
|
if (ops == NULL)
|
|
{
|
|
LOG_ERROR("Error opening file %s: %s", path, SDL_GetError());
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
{
|
|
char magic[4];
|
|
SDL_RWread(ops, magic, sizeof(magic), 1);
|
|
if (magic[0] != 'A' || magic[1] != 'J' || magic[2] != 'M' || magic[3] != '\0') {
|
|
LOG_ERROR("%s has an invalid format", path);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
data_t result = {0};
|
|
|
|
{
|
|
uint16_t count;
|
|
SDL_RWread(ops, &count, sizeof(count), 1);
|
|
LOG_DEBUG("Load %d meshes", count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
uint16_t name_length;
|
|
SDL_RWread(ops, &name_length, sizeof(name_length), 1);
|
|
|
|
char* name = scratch_mem_alloc(name_length, sizeof(*name));
|
|
SDL_RWread(ops, name, sizeof(*name), name_length);
|
|
LOG_ASSERT(name_length < MAX_NAME_LENGTH, "Name of mesh is too long: %s", name);
|
|
|
|
mesh_t mesh = mesh_load(ops);
|
|
strncpy(mesh.name, name, name_length);
|
|
insert_mesh(mesh);
|
|
}
|
|
}
|
|
|
|
{
|
|
uint16_t count;
|
|
SDL_RWread(ops, &count, sizeof(count), 1);
|
|
LOG_DEBUG("Load %d materials", count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
uint16_t name_length;
|
|
SDL_RWread(ops, &name_length, sizeof(name_length), 1);
|
|
|
|
char* name = scratch_mem_alloc(name_length, sizeof(*name));
|
|
SDL_RWread(ops, name, sizeof(*name), name_length);
|
|
LOG_ASSERT(name_length < MAX_NAME_LENGTH, "Name of material is too long: %s", name);
|
|
|
|
material_t material = material_load(ops);
|
|
strncpy(material.name, name, name_length);
|
|
insert_material(material);
|
|
}
|
|
}
|
|
|
|
// Coins
|
|
{
|
|
transform_t* data = NULL;
|
|
uint16_t count;
|
|
SDL_RWread(ops, &count, sizeof(count), 1);
|
|
|
|
LOG_DEBUG("Load %d coins", count);
|
|
|
|
data = game_mem_alloc(count, sizeof(*data));
|
|
SDL_RWread(ops, data, sizeof(*data), count);
|
|
|
|
result.items.coins = data;
|
|
result.items.coin_count = count;
|
|
}
|
|
|
|
// Eyeballs
|
|
{
|
|
transform_t* data = NULL;
|
|
uint16_t count;
|
|
SDL_RWread(ops, &count, sizeof(count), 1);
|
|
|
|
LOG_DEBUG("Load %d eyeballs", count);
|
|
|
|
data = game_mem_alloc(count, sizeof(*data));
|
|
SDL_RWread(ops, data, sizeof(*data), count);
|
|
|
|
result.items.eyeballs = data;
|
|
result.items.eyeball_count = count;
|
|
}
|
|
|
|
// Pedestals
|
|
{
|
|
transform_t* data = NULL;
|
|
uint16_t count;
|
|
SDL_RWread(ops, &count, sizeof(count), 1);
|
|
|
|
LOG_DEBUG("Load %d pedestals", count);
|
|
|
|
data = game_mem_alloc(count, sizeof(*data));
|
|
SDL_RWread(ops, data, sizeof(*data), count);
|
|
|
|
result.items.pedestals = data;
|
|
result.items.pedestal_count = count;
|
|
}
|
|
|
|
// Score
|
|
{
|
|
transform_t hundreds;
|
|
transform_t tens;
|
|
transform_t ones;
|
|
transform_t coin;
|
|
aabb_t collider;
|
|
|
|
SDL_RWread(ops, &hundreds, sizeof(hundreds), 1);
|
|
SDL_RWread(ops, &tens, sizeof(tens), 1);
|
|
SDL_RWread(ops, &ones, sizeof(ones), 1);
|
|
SDL_RWread(ops, &coin, sizeof(coin), 1);
|
|
SDL_RWread(ops, &collider, sizeof(collider), 1);
|
|
|
|
result.score.hundreds = hundreds;
|
|
result.score.tens = tens;
|
|
result.score.ones = ones;
|
|
result.score.coin = coin;
|
|
result.score.collider = collider;
|
|
}
|
|
|
|
{
|
|
aabb_t* walls = NULL;
|
|
uint16_t wall_count;
|
|
SDL_RWread(ops, &wall_count, sizeof(wall_count), 1);
|
|
LOG_ASSERT(wall_count <= WALL_COUNT, "Too many walls");
|
|
|
|
LOG_DEBUG("Load %d walls", wall_count);
|
|
|
|
walls = scratch_mem_alloc(wall_count, sizeof(*walls));
|
|
SDL_RWread(ops, walls, sizeof(*walls), wall_count);
|
|
|
|
memcpy(&result.walls, walls, sizeof(*walls) * wall_count);
|
|
|
|
result.wall_count = wall_count;
|
|
}
|
|
|
|
{
|
|
uint32_t* tiles;
|
|
uint8_t tile_count;
|
|
SDL_RWread(ops, &tile_count, sizeof(tile_count), 1);
|
|
LOG_ASSERT(tile_count == TILE_COUNT, "Incorrect number of tiles");
|
|
|
|
LOG_DEBUG("Load %d tiles", tile_count);
|
|
|
|
tiles = scratch_mem_alloc(tile_count, sizeof(*tiles));
|
|
SDL_RWread(ops, tiles, sizeof(*tiles), TILE_COUNT);
|
|
|
|
memcpy(&result.tiles, tiles, sizeof(*tiles) * tile_count);
|
|
}
|
|
|
|
{
|
|
uint16_t count;
|
|
SDL_RWread(ops, &count, sizeof(count), 1);
|
|
LOG_DEBUG("Load %d songs", count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
uint16_t name_length;
|
|
SDL_RWread(ops, &name_length, sizeof(name_length), 1);
|
|
|
|
char* name = scratch_mem_alloc(name_length, sizeof(*name));
|
|
SDL_RWread(ops, name, sizeof(*name), name_length);
|
|
LOG_ASSERT(name_length < MAX_NAME_LENGTH, "Name of music is too long: %s", name);
|
|
|
|
wav_t music = wav_load(ops);
|
|
strncpy(music.name, name, name_length);
|
|
insert_music(music);
|
|
}
|
|
}
|
|
|
|
{
|
|
uint16_t count;
|
|
SDL_RWread(ops, &count, sizeof(count), 1);
|
|
LOG_DEBUG("Load %d SFX", count);
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
uint16_t name_length;
|
|
SDL_RWread(ops, &name_length, sizeof(name_length), 1);
|
|
|
|
char* name = scratch_mem_alloc(name_length, sizeof(*name));
|
|
SDL_RWread(ops, name, sizeof(*name), name_length);
|
|
LOG_ASSERT(name_length < MAX_NAME_LENGTH, "Name of SFX is too long: %s", name);
|
|
|
|
wav_t sfx = wav_load(ops);
|
|
strncpy(sfx.name, name, name_length);
|
|
insert_sfx(sfx);
|
|
}
|
|
}
|
|
|
|
int ret = SDL_RWclose(ops);
|
|
if (ret != 0) {
|
|
LOG_ERROR("Error closing file %s: %s", path, SDL_GetError());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|