Integrate ZSTD decompression to load level

scene_man
En Yi 2023-08-26 22:17:53 +08:00
parent 3ab442169a
commit 044a5831ff
5 changed files with 158 additions and 1 deletions

View File

@ -5,6 +5,7 @@ cmake_minimum_required(VERSION 3.22.1)
project(${PROJECT_NAME} C) project(${PROJECT_NAME} C)
set(CMAKE_C_STANDARD 99) set(CMAKE_C_STANDARD 99)
set(RAYLIB_DIR /usr/local/lib CACHE FILEPATH "directory to Raylib") set(RAYLIB_DIR /usr/local/lib CACHE FILEPATH "directory to Raylib")
set(LIBZSTD_DIR /usr/local/lib CACHE FILEPATH "directory to zstd")
if (EMSCRIPTEN) if (EMSCRIPTEN)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY")

View File

@ -97,7 +97,8 @@ bool load_from_infofile(const char* file, Assets_t* assets)
break; break;
case LEVELPACK_INFO: case LEVELPACK_INFO:
{ {
if (add_level_pack(assets, name, info_str) == NULL) //if (add_level_pack(assets, name, info_str) == NULL)
if (uncompress_level_pack(assets, name, info_str) == NULL)
{ {
printf("Unable to add level pack at line %lu\n", line_num); printf("Unable to add level pack at line %lu\n", line_num);
break; break;

View File

@ -5,12 +5,16 @@ add_library(lib_engine STATIC
gui.c gui.c
engine.c engine.c
collisions.c collisions.c
${LIBZSTD_DIR}/lib/libzstd.a
) )
target_include_directories(lib_engine target_include_directories(lib_engine
PRIVATE
${LIBZSTD_DIR}/include
PUBLIC PUBLIC
${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}
) )
target_link_libraries(lib_engine target_link_libraries(lib_engine
PUBLIC PUBLIC
lib_EC lib_EC
zstd
) )

View File

@ -1,6 +1,7 @@
#include "assets.h" #include "assets.h"
#include "assert.h" #include "assert.h"
#include "zstd.h"
#include <stdio.h> #include <stdio.h>
#define MAX_TEXTURES 16 #define MAX_TEXTURES 16
@ -45,6 +46,15 @@ static SoundData_t sfx[MAX_SOUNDS];
static SpriteData_t sprites[MAX_SPRITES]; static SpriteData_t sprites[MAX_SPRITES];
static LevelPackData_t levelpacks[MAX_LEVEL_PACK]; static LevelPackData_t levelpacks[MAX_LEVEL_PACK];
#define DECOMPRESSOR_INBUF_LEN 4096
#define DECOMPRESSOR_OUTBUF_LEN 4096
static struct ZstdDecompressor
{
ZSTD_DCtx* ctx;
uint8_t in_buffer[DECOMPRESSOR_INBUF_LEN];
uint8_t out_buffer[DECOMPRESSOR_OUTBUF_LEN];
}level_decompressor;
static void unload_level_pack(LevelPack_t pack) static void unload_level_pack(LevelPack_t pack)
{ {
for (uint8_t i = 0; i < pack.n_levels; ++i) for (uint8_t i = 0; i < pack.n_levels; ++i)
@ -132,6 +142,144 @@ LevelPack_t* add_level_pack(Assets_t* assets, const char* name, const char* path
return &levelpacks[pack_idx].pack; return &levelpacks[pack_idx].pack;
} }
LevelPack_t* uncompress_level_pack(Assets_t* assets, const char* name, const char* path)
{
FILE* file = fopen(path, "rb");
if (file == NULL) return NULL;
LevelPackData_t* pack_info = levelpacks + n_loaded[4];
size_t read = 0;
ZSTD_inBuffer input = { level_decompressor.in_buffer, read, 0 };
ZSTD_outBuffer output = { level_decompressor.out_buffer, 4, 0 };
do
{
if (input.pos == input.size)
{
puts("Read more");
read = fread(level_decompressor.in_buffer, 1, DECOMPRESSOR_INBUF_LEN, file);
if (read == 0) break;
input.size = read;
input.pos = 0;
}
size_t const ret = ZSTD_decompressStream(level_decompressor.ctx, &output , &input);
if (ZSTD_isError(ret))
{
printf("Decompression Error: %s\n", ZSTD_getErrorName(ret));
break;
}
}
while (output.pos == 0);
if (output.pos == 0)
{
perror("Could not read number of levels");
return NULL;
}
// Read number of levels and alloc the memory for the levels
uint32_t n_levels = 0;
uint8_t lvls = 0;
bool err = false;
memcpy(&n_levels, level_decompressor.out_buffer, 4);
pack_info->pack.levels = calloc(n_levels, sizeof(LevelMap_t));
for (lvls = 0; lvls < n_levels; ++lvls)
{
printf("Parsing level %u\n", lvls);
output.size = 36;
output.pos = 0;
do
{
if (input.pos == input.size)
{
read = fread(level_decompressor.in_buffer, 1, DECOMPRESSOR_INBUF_LEN, file);
if (read == 0) break;
input.size = read;
input.pos = 0;
}
size_t const ret = ZSTD_decompressStream(level_decompressor.ctx, &output , &input);
if (ZSTD_isError(ret))
{
printf("Decompression Error: %s\n", ZSTD_getErrorName(ret));
break;
}
printf("Compare %lu to %lu\n", output.pos, output.size);
}
while (output.pos != output.size);
if (output.pos != output.size)
{
perror("Could not read level");
err = true;
goto load_end;
}
memcpy(pack_info->pack.levels[lvls].level_name, level_decompressor.out_buffer, 32);
memcpy(&pack_info->pack.levels[lvls].width, level_decompressor.out_buffer + 32, 2);
memcpy(&pack_info->pack.levels[lvls].height, level_decompressor.out_buffer + 34, 2);
pack_info->pack.levels[lvls].level_name[31] = '\0';
printf("Level name: %s\n", pack_info->pack.levels[lvls].level_name);
printf("WxH: %u %u\n", pack_info->pack.levels[lvls].width, pack_info->pack.levels[lvls].height);
uint32_t n_tiles = pack_info->pack.levels[lvls].width * pack_info->pack.levels[lvls].height;
uint32_t remaining_len = n_tiles * 4;
pack_info->pack.levels[lvls].tiles = calloc(n_tiles, sizeof(LevelTileInfo_t));
output.size = DECOMPRESSOR_OUTBUF_LEN;
output.pos = 0;
uint8_t* data_ptr = (uint8_t*)pack_info->pack.levels[lvls].tiles;
do
{
if (input.pos == input.size)
{
read = fread(level_decompressor.in_buffer, 1, DECOMPRESSOR_INBUF_LEN, file);
if (read == 0) break;
input.size = read;
input.pos = 0;
}
size_t to_read = (remaining_len > DECOMPRESSOR_OUTBUF_LEN) ? DECOMPRESSOR_OUTBUF_LEN : remaining_len;
output.size = to_read;
output.pos = 0;
size_t const ret = ZSTD_decompressStream(level_decompressor.ctx, &output , &input);
if (ZSTD_isError(ret))
{
printf("Decompression Error: %s\n", ZSTD_getErrorName(ret));
break;
}
memcpy(data_ptr, level_decompressor.out_buffer, output.pos);
data_ptr += output.pos;
remaining_len -= output.pos;
}
while (remaining_len > 0);
if (remaining_len > 0)
{
free(pack_info->pack.levels[lvls].tiles);
perror("Could not read level tiles");
err = true;
goto load_end;
}
}
load_end:
fclose(file);
if (err)
{
unload_level_pack(pack_info->pack);
return NULL;
}
pack_info->pack.n_levels = lvls;
uint8_t pack_idx = n_loaded[4];
strncpy(pack_info->name, name, MAX_NAME_LEN);
sc_map_put_s64(&assets->m_levelpacks, levelpacks[pack_idx].name, pack_idx);
n_loaded[4]++;
return &levelpacks[pack_idx].pack;
}
void init_assets(Assets_t* assets) void init_assets(Assets_t* assets)
{ {
sc_map_init_s64(&assets->m_fonts, MAX_FONTS, 0); sc_map_init_s64(&assets->m_fonts, MAX_FONTS, 0);
@ -139,6 +287,7 @@ void init_assets(Assets_t* assets)
sc_map_init_s64(&assets->m_textures, MAX_TEXTURES, 0); sc_map_init_s64(&assets->m_textures, MAX_TEXTURES, 0);
sc_map_init_s64(&assets->m_sounds, MAX_SOUNDS, 0); sc_map_init_s64(&assets->m_sounds, MAX_SOUNDS, 0);
sc_map_init_s64(&assets->m_levelpacks, MAX_LEVEL_PACK, 0); sc_map_init_s64(&assets->m_levelpacks, MAX_LEVEL_PACK, 0);
level_decompressor.ctx = ZSTD_createDCtx();
} }
void free_all_assets(Assets_t* assets) void free_all_assets(Assets_t* assets)
@ -176,6 +325,7 @@ void term_assets(Assets_t* assets)
sc_map_term_s64(&assets->m_sounds); sc_map_term_s64(&assets->m_sounds);
sc_map_term_s64(&assets->m_sprites); sc_map_term_s64(&assets->m_sprites);
sc_map_term_s64(&assets->m_levelpacks); sc_map_term_s64(&assets->m_levelpacks);
ZSTD_freeDCtx(level_decompressor.ctx);
} }
Texture2D* get_texture(Assets_t* assets, const char* name) Texture2D* get_texture(Assets_t* assets, const char* name)

View File

@ -44,6 +44,7 @@ Sprite_t* add_sprite(Assets_t* assets, const char* name, Texture2D* texture);
Sound* add_sound(Assets_t * assets, const char* name, const char* path); Sound* add_sound(Assets_t * assets, const char* name, const char* path);
Font* add_font(Assets_t* assets, const char* name, const char* path); Font* add_font(Assets_t* assets, const char* name, const char* path);
LevelPack_t* add_level_pack(Assets_t* assets, const char* name, const char* path); LevelPack_t* add_level_pack(Assets_t* assets, const char* name, const char* path);
LevelPack_t* uncompress_level_pack(Assets_t* assets, const char* name, const char* path);
Texture2D* get_texture(Assets_t* assets, const char* name); Texture2D* get_texture(Assets_t* assets, const char* name);
Sprite_t* get_sprite(Assets_t* assets, const char* name); Sprite_t* get_sprite(Assets_t* assets, const char* name);