Merge branch 'master' into extraspells

This commit is contained in:
Andrei "Akari" Alexeyev 2017-03-16 10:04:05 +02:00
commit a1a8ea6a61
115 changed files with 1425 additions and 686 deletions

View file

@ -38,6 +38,8 @@ install(DIRECTORY gfx DESTINATION ${DATA_DIR}
FILES_MATCHING PATTERN "*.png")
install(DIRECTORY gfx DESTINATION ${DATA_DIR}
FILES_MATCHING PATTERN "*.ttf")
install(DIRECTORY gfx DESTINATION ${DATA_DIR}
FILES_MATCHING PATTERN "*.ani")
install(DIRECTORY sfx DESTINATION ${DATA_DIR})
install(DIRECTORY bgm DESTINATION ${DATA_DIR})
install(DIRECTORY shader DESTINATION ${DATA_DIR})

View file

@ -28,5 +28,8 @@ public domain or CC0 and were not taken by us. Here are some honorary mentions.
* The mountains in the main menu background are by Luca Zanon.
https://unsplash.com/photos/X0OoHrPvgXE
* the insect wings in Scuttles background are by GLady.
https://pixabay.com/en/morpho-peleides-butterfly-43483/
* For the old ones, sadly I didnt keep a list. You may find them by doing an
image search. Check out the taisei-rawmedia repository for the raw files.

View file

@ -52,21 +52,18 @@ BGM (as well as SFX) may be in `.wav`, `.flac`, or `.ogg` format; additionally
you may try another formats such as `.mp3`, `.aiff`, `.mod`, `.xm`, etc. if
your build of SDL2_mixer supports these formats.
Complete music pack consists of 16 bgm\_\*.(ogg/wav/flac) files, where \* mean:
Complete music pack consists of 16 bgm\_\*.(ogg/wav/flac) files, where \* means:
```
credits BGM for credits screen
ending BGM for ending
gameover BGM for game over screen
menu BGM for menus (excluding in-game menu which pauses BGM)
stageN N=1..6, standard stage theme
stageNboss N=1..6, boss theme for a stage
credits BGM for credits screen
ending BGM for ending
gameover BGM for game over screen
menu BGM for menus (excluding in-game menu which pauses BGM)
stageN N=1..6, standard stage theme
stageNboss N=1..6, boss theme for a stage
```
If you want to specify stage/boss theme names to be shown during gameplay, you
may do it in `bgm/bgm.conf` file. This file contains some lines, each of which
consists of bgm filename (without extension), space of tab, and theme name.
No space/tab allowed either in beginning of line or BGM filenames listed in
this file; theme names may contain them.
may do it by editing the [`bgm/bgm.conf`](bgm/bgm.conf) file.
## Sound problems

View file

@ -1,13 +1,13 @@
bgm_stage1 Generic Stage 1 Theme
bgm_stage2 Generic Stage 2 Theme
bgm_stage3 Generic Stage 3 Theme
bgm_stage4 Generic Stage 4 Theme
bgm_stage5 Generic Stage 5 Theme
bgm_stage6 Generic Stage 6 Theme
bgm_stage1 = Generic Stage 1 Theme
bgm_stage2 = Generic Stage 2 Theme
bgm_stage3 = Generic Stage 3 Theme
bgm_stage4 = Generic Stage 4 Theme
bgm_stage5 = Generic Stage 5 Theme
bgm_stage6 = Generic Stage 6 Theme
bgm_stage1boss Stage 1 Boss Theme
bgm_stage2boss Stage 2 Boss Theme
bgm_stage3boss Stage 3 Boss Theme
bgm_stage4boss Stage 4 Boss Theme
bgm_stage5boss Stage 5 Boss Theme
bgm_stage6boss Stage 6 Boss Theme
bgm_stage1boss = Stage 1 Boss Theme
bgm_stage2boss = Stage 2 Boss Theme
bgm_stage3boss = Stage 3 Boss Theme
bgm_stage4boss = Stage 4 Boss Theme
bgm_stage5boss = Stage 5 Boss Theme
bgm_stage6boss = Stage 6 Boss Theme

3
gfx/bigfairy.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 2
cols = 2
speed = 15

View file

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

3
gfx/cirno.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 1
speed = 10

View file

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 11 KiB

3
gfx/elly.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 1
speed = 10

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

3
gfx/fairy.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 2
cols = 2
speed = 15

View file

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

3
gfx/fire.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 25
speed = 1

View file

Before

Width:  |  Height:  |  Size: 198 KiB

After

Width:  |  Height:  |  Size: 198 KiB

3
gfx/hina.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 1
speed = 10

View file

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

3
gfx/hinabg.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 25
speed = 1

View file

Before

Width:  |  Height:  |  Size: 486 KiB

After

Width:  |  Height:  |  Size: 486 KiB

3
gfx/iku.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 1
speed = 25

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

3
gfx/kurumi.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 1
speed = 10

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

3
gfx/marisa.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 2
cols = 4
speed = 10

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

3
gfx/scuttle.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 1
speed = 10

View file

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 184 KiB

BIN
gfx/stage3/spellbg2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 KiB

3
gfx/wriggle.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 1
speed = 10

View file

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

3
gfx/wriggleex.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 1
cols = 1
speed = 10

View file

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 8.6 KiB

3
gfx/youmu.ani Normal file
View file

@ -0,0 +1,3 @@
rows = 2
cols = 4
speed = 10

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -21,6 +21,7 @@ endif()
set(SRCs
main.c
log.c
util.c
taiseigl.c
random.c
@ -110,10 +111,6 @@ else()
)
endif()
if(WIN32)
set(SRCs ${SRCs} taisei_err.c)
endif()
if(DEFINED TAISEI_DEBUG)
if(TAISEI_DEBUG)
set(CMAKE_BUILD_TYPE "Debug")
@ -130,7 +127,6 @@ endif()
message(STATUS "Build configuration: ${CMAKE_BUILD_TYPE}")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -ggdb -DDEBUG")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
add_definitions(-DPREFIX="${CMAKE_INSTALL_PREFIX}" -Wall -Wno-parentheses -Wtype-limits -std=c11 -pedantic)
@ -146,6 +142,10 @@ if(FATALERRS)
add_definitions(-Wfatal-errors)
endif()
if(WIN32 OR APPLE)
add_definitions(-DLOG_FATAL_MSGBOX)
endif()
set(LIBs ${LIBs}
${SDL2_LIBRARIES}
${SDL2_TTF_LIBRARIES}
@ -196,6 +196,13 @@ if(POSIX)
add_definitions(-D__POSIX__)
endif()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
check_symbol_exists(backtrace "execinfo.h" HAVE_BACKTRACE)
if(HAVE_BACKTRACE)
add_definitions(-DLOG_ENABLE_BACKTRACE)
endif()
endif()
if (CMAKE_GENERATOR STREQUAL "Ninja" AND
((CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9) OR
(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.5)))

2
src/assert.h Normal file
View file

@ -0,0 +1,2 @@
#error Do not include assert.h, Taisei provides its own implementation.

View file

@ -49,12 +49,12 @@ void reset_sounds(void) {
}
Sound* get_sound(const char *name) {
Resource *res = get_resource(RES_SFX, name, 0);
Resource *res = get_resource(RES_SFX, name, RESF_OPTIONAL);
return res ? res->sound : NULL;
}
Music* get_music(const char *name) {
Resource *res = get_resource(RES_BGM, name, 0);
Resource *res = get_resource(RES_BGM, name, RESF_OPTIONAL);
return res ? res->music : NULL;
}
@ -68,42 +68,13 @@ static void bgm_cfg_volume_callback(ConfigIndex idx, ConfigValue v) {
static void load_bgm_descriptions(void) {
char *fullname = strjoin(get_prefix(), "bgm/bgm.conf", NULL);
FILE *fp = fopen(fullname, "rt");
bgm_descriptions = parse_keyvalue_file(fullname, 16);
free(fullname);
bgm_descriptions = hashtable_new_stringkeys(16);
if(fp == NULL) {
return;
}
char line[256];
while(fgets(line, sizeof(line), fp)) {
char *rem;
while((rem = strchr(line,'\n')) != NULL) *rem = '\0';
while((rem = strchr(line,'\r')) != NULL) *rem = '\0';
while((rem = strchr(line,'\t')) != NULL) *rem = ' ';
if((rem = strchr(line,' ' )) == NULL) {
if(strlen(line) > 0)
warnx("load_bgm_description(): illegal string format. See README.");
continue;
}
*(rem++)='\0';
char *value = strjoin("BGM: ", rem, NULL);
hashtable_set_string(bgm_descriptions, line, value);
printf("Music %s is now known as \"%s\".\n", line, value);
}
fclose(fp);
return;
}
static inline char* get_bgm_desc(char *name) {
return (char*)hashtable_get_string(bgm_descriptions, name);
return bgm_descriptions ? (char*)hashtable_get_string(bgm_descriptions, name) : NULL;
}
void resume_bgm(void) {
@ -122,9 +93,9 @@ void stop_bgm(bool force) {
audio_backend_music_pause();
}
printf("BGM stopped.\n");
log_info("BGM stopped");
} else {
printf("stop_bgm(): No BGM was playing.\n");
log_info("No BGM was playing");
}
}
@ -152,7 +123,7 @@ void start_bgm(const char *name) {
stralloc(&current_bgm.name, name);
if((current_bgm.music = get_music(name)) == NULL) {
warnx("start_bgm(): BGM '%s' does not exist", current_bgm.name);
log_warn("BGM '%s' does not exist", current_bgm.name);
stop_bgm(true);
free(current_bgm.name);
current_bgm.name = NULL;
@ -181,7 +152,7 @@ void start_bgm(const char *name) {
current_bgm.started_at = -1;
}
printf("Started %s\n", (current_bgm.title ? current_bgm.title : current_bgm.name));
log_info("Started %s", (current_bgm.title ? current_bgm.title : current_bgm.name));
}
void audio_init(void) {
@ -193,6 +164,9 @@ void audio_init(void) {
void audio_shutdown(void) {
audio_backend_shutdown();
hashtable_foreach(bgm_descriptions, hashtable_iter_free_data, NULL);
hashtable_free(bgm_descriptions);
if(bgm_descriptions) {
hashtable_foreach(bgm_descriptions, hashtable_iter_free_data, NULL);
hashtable_free(bgm_descriptions);
}
}

View file

@ -12,7 +12,6 @@
#include "audio.h"
#include "global.h"
#include "list.h"
#include "taisei_err.h"
#define AUDIO_FREQ 44100
#define AUDIO_FORMAT MIX_DEFAULT_FORMAT
@ -30,7 +29,7 @@ void audio_backend_init(void) {
}
if(SDL_InitSubSystem(SDL_INIT_AUDIO)) {
warnx("audio_backend_init(): SDL_InitSubSystem() failed: %s.\n", SDL_GetError());
log_warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
return;
}
@ -40,21 +39,21 @@ void audio_backend_init(void) {
}
if(Mix_OpenAudio(AUDIO_FREQ, AUDIO_FORMAT, 2, config_get_int(CONFIG_MIXER_CHUNKSIZE)) == -1) {
warnx("audio_backend_init(): Mix_OpenAudio() failed: %s.\n", Mix_GetError());
log_warn("Mix_OpenAudio() failed: %s", Mix_GetError());
Mix_Quit();
return;
}
int channels = Mix_AllocateChannels(AUDIO_CHANNELS);
if(!channels) {
warnx("audio_backend_init(): unable to allocate any channels.\n");
log_warn("Unable to allocate any channels");
Mix_CloseAudio();
Mix_Quit();
return;
}
if(channels < AUDIO_CHANNELS) {
warnx("audio_backend_init(): allocated only %d of %d channels.\n", channels, AUDIO_CHANNELS);
log_warn("Allocated only %d of %d channels", channels, AUDIO_CHANNELS);
}
mixer_loaded = true;
@ -68,13 +67,13 @@ void audio_backend_init(void) {
Mix_QuerySpec(&frequency, &format, &channels);
if(frequency != AUDIO_FREQ || format != AUDIO_FORMAT) {
warnx( "audio_backend_init(): mixer spec doesn't match our request, "
"requested (freq=%i, fmt=%u), got (freq=%i, fmt=%u). "
"Sound may be distorted.",
AUDIO_FREQ, AUDIO_FORMAT, frequency, format);
log_warn( "Mixer spec doesn't match our request, "
"requested (freq=%i, fmt=%u), got (freq=%i, fmt=%u). "
"Sound may be distorted.",
AUDIO_FREQ, AUDIO_FORMAT, frequency, format);
}
printf("audio_backend_init(): audio subsystem initialized (SDL2_Mixer)\n");
log_info("Audio subsystem initialized (SDL2_Mixer)");
}
void audio_backend_shutdown(void) {
@ -83,7 +82,7 @@ void audio_backend_shutdown(void) {
SDL_QuitSubSystem(SDL_INIT_AUDIO);
mixer_loaded = false;
printf("audio_backend_shutdown(): audio subsystem uninitialized (SDL2_Mixer)\n");
log_info("Audio subsystem uninitialized (SDL2_Mixer)");
}
bool audio_backend_initialized(void) {
@ -153,7 +152,7 @@ bool audio_backend_music_play(void *impl) {
bool result = (Mix_PlayMusic((Mix_Music*)impl, -1) != -1);
if(!result) {
warnx("audio_backend_music_play(): Mix_PlayMusic() failed: %s", Mix_GetError());
log_warn("Mix_PlayMusic() failed: %s", Mix_GetError());
}
return result;
@ -166,7 +165,7 @@ bool audio_backend_sound_play(void *impl) {
bool result = (Mix_PlayChannel(-1, (Mix_Chunk*)impl, 0) != -1);
if(!result) {
warnx("audio_backend_sound_play(): Mix_PlayChannel() failed: %s", Mix_GetError());
log_warn("Mix_PlayChannel() failed: %s", Mix_GetError());
}
return result;

View file

@ -289,22 +289,20 @@ void free_attack(Attack *a) {
}
void start_attack(Boss *b, Attack *a) {
#if DEBUG
printf("BOSS start_attack(): %s\n", a->name);
#endif
log_debug("%s", a->name);
if(global.replaymode == REPLAY_RECORD && global.stage->type == STAGE_STORY && !global.plr.continues) {
StageInfo *i = stage_get_by_spellcard(a->info, global.diff);
if(i) {
StageProgress *p = stage_get_progress_from_info(i, global.diff, true);
if(p && !p->unlocked) {
printf("Spellcard unlocked! %s: %s\n", i->title, i->subtitle);
log_info("Spellcard unlocked! %s: %s", i->title, i->subtitle);
p->unlocked = true;
}
}
#if DEBUG
else if(a->type == AT_Spellcard || a->type == AT_ExtraSpell) {
warnx("FIXME: spellcard '%s' is not available in spell practice mode!", a->name);
log_warn("FIXME: spellcard '%s' is not available in spell practice mode!", a->name);
}
#endif
}
@ -325,6 +323,7 @@ void start_attack(Boss *b, Attack *a) {
Attack* boss_add_attack(Boss *boss, AttackType type, char *name, float timeout, int hp, BossRule rule, BossRule draw_rule) {
boss->attacks = realloc(boss->attacks, sizeof(Attack)*(++boss->acount));
Attack *a = &boss->attacks[boss->acount-1];
memset(a, 0, sizeof(Attack));
boss->current = &boss->attacks[0];
@ -362,3 +361,19 @@ Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move) {
a->info = info;
return a;
}
void boss_preload(void) {
preload_resources(RES_SFX, RESF_OPTIONAL,
"charge_generic",
NULL);
preload_resources(RES_TEXTURE, RESF_DEFAULT,
"boss_spellcircle0",
"boss_circle",
"boss_indicator",
NULL);
preload_resources(RES_SHADER, RESF_DEFAULT,
"boss_zoom",
NULL);
}

View file

@ -114,6 +114,8 @@ Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move);
void boss_death(Boss **boss);
void boss_kill_projectiles(void);
void boss_preload(void);
#define BOSS_DEFAULT_SPAWN_POS (VIEWPORT_W * 0.5 - I * VIEWPORT_H * 0.5)
#define BOSS_DEFAULT_GO_POS (VIEWPORT_W * 0.5 + 200.0*I)
#define BOSS_NOMOVE (-3142-39942.0*I)

View file

@ -6,7 +6,6 @@
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include <assert.h>
#include <stdio.h>
#include "color.h"

View file

@ -7,12 +7,10 @@
*/
#include <string.h>
#include <assert.h>
#include "config.h"
#include "global.h"
#include "paths/native.h"
#include "taisei_err.h"
static bool config_initialized = false;
@ -182,11 +180,7 @@ static void config_set_val(ConfigIndex idx, ConfigValue v) {
return;
}
#ifdef DEBUG
#define PRINTVAL(t) printf("config_set_val(): %s:" #t " = %" #t "\n", e->name, e->val.t);
#else
#define PRINTVAL(t)
#endif
#define PRINTVAL(t) log_debug("%s:" #t " = %" #t, e->name, e->val.t);
switch(e->type) {
case CONFIG_TYPE_INT:
@ -269,69 +263,71 @@ static void config_delete_unknown_entries(void) {
delete_all_elements((void**)&unknowndefs, config_delete_unknown_entry);
}
static FILE* config_open(const char *filename, const char *mode) {
char *buf = strjoin(get_config_path(), "/", filename, NULL);
FILE *out = fopen(buf, mode);
static char* config_path(const char *filename) {
return strjoin(get_config_path(), "/", filename, NULL);
}
static SDL_RWops* config_open(const char *filename, const char *mode) {
char *buf = config_path(filename);
SDL_RWops *out = SDL_RWFromFile(buf, mode);
free(buf);
if(!out) {
warnx("config_open(): couldn't open '%s'", filename);
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
}
return out;
}
void config_save(const char *filename) {
FILE *out = config_open(filename, "w");
SDL_RWops *out = config_open(filename, "w");
ConfigEntry *e = configdefs;
if(!out)
return;
fputs("# Generated by taisei\n", out);
SDL_RWprintf(out, "# Generated by taisei\n");
do switch(e->type) {
case CONFIG_TYPE_INT:
fprintf(out, "%s = %i\n", e->name, e->val.i);
SDL_RWprintf(out, "%s = %i\n", e->name, e->val.i);
break;
case CONFIG_TYPE_KEYBINDING:
fprintf(out, "%s = %s\n", e->name, SDL_GetScancodeName(e->val.i));
SDL_RWprintf(out, "%s = %s\n", e->name, SDL_GetScancodeName(e->val.i));
break;
case CONFIG_TYPE_STRING:
fprintf(out, "%s = %s\n", e->name, e->val.s);
SDL_RWprintf(out, "%s = %s\n", e->name, e->val.s);
break;
case CONFIG_TYPE_FLOAT:
fprintf(out, "%s = %f\n", e->name, e->val.f);
SDL_RWprintf(out, "%s = %f\n", e->name, e->val.f);
break;
} while((++e)->name);
if(unknowndefs) {
fputs("# The following options were not recognized by taisei\n", out);
SDL_RWprintf(out, "# The following options were not recognized by taisei\n");
for(ConfigEntryList *l = unknowndefs; l; l = l->next) {
e = &l->entry;
fprintf(out, "%s = %s\n", e->name, e->val.s);
SDL_RWprintf(out, "%s = %s\n", e->name, e->val.s);
}
}
fclose(out);
printf("Saved config '%s'\n", filename);
SDL_RWclose(out);
log_info("Saved config '%s'", filename);
}
#define SYNTAXERROR { warnx("config_load(): syntax error on line %i, aborted! [%s:%i]\n", line, __FILE__, __LINE__); goto end; }
#define BUFFERERROR { warnx("config_load(): string exceed the limit of %i, aborted! [%s:%i]", CONFIG_LOAD_BUFSIZE, __FILE__, __LINE__); goto end; }
#define INTOF(s) ((int)strtol(s, NULL, 10))
#define FLOATOF(s) ((float)strtod(s, NULL))
static void config_set(const char *key, const char *val) {
static void config_set(const char *key, const char *val, void *data) {
ConfigEntry *e = config_find_entry(key);
if(!e) {
warnx("config_set(): unknown setting '%s'", key);
log_warn("Unknown setting '%s'", key);
config_set_unknown(key, val);
return;
}
@ -345,7 +341,7 @@ static void config_set(const char *key, const char *val) {
SDL_Scancode scan = SDL_GetScancodeFromName(val);
if(scan == SDL_SCANCODE_UNKNOWN) {
warnx("config_set(): unknown key '%s'", val);
log_warn("Unknown key '%s'", val);
} else {
e->val.i = scan;
}
@ -367,68 +363,10 @@ static void config_set(const char *key, const char *val) {
#undef FLOATOF
void config_load(const char *filename) {
FILE *in = config_open(filename, "r");
int c, i = 0, found, line = 0;
char buf[CONFIG_LOAD_BUFSIZE];
char key[CONFIG_LOAD_BUFSIZE];
char val[CONFIG_LOAD_BUFSIZE];
char *path = config_path(filename);
config_init();
if(!in) {
return;
if(!parse_keyvalue_file_cb(path, config_set, NULL)) {
log_warn("Errors occured while parsing the configuration file");
}
while((c = fgetc(in)) != EOF) {
if(c == '#' && !i) {
i = 0;
while(fgetc(in) != '\n');
} else if(c == ' ') {
if(!i) SYNTAXERROR
buf[i] = 0;
i = 0;
strcpy(key, buf);
found = 0;
while((c = fgetc(in)) != EOF) {
if(c == '=') {
if(++found > 1) SYNTAXERROR
} else if(c != ' ') {
if(!found || c == '\n') SYNTAXERROR
do {
if(c == '\n') {
if(!i) SYNTAXERROR
buf[i] = 0;
i = 0;
strcpy(val, buf);
found = 0;
++line;
config_set(key, val);
break;
} else {
buf[i++] = c;
if(i == CONFIG_LOAD_BUFSIZE)
BUFFERERROR
}
} while((c = fgetc(in)) != EOF);
break;
}
} if(found) SYNTAXERROR
} else {
buf[i++] = c;
if(i == CONFIG_LOAD_BUFSIZE)
BUFFERERROR
}
}
end:
fclose(in);
free(path);
}
#undef SYNTAXERROR
#undef BUFFERERROR

View file

@ -253,7 +253,18 @@ void credits_free(void) {
free(credits.entries);
}
void credits_preload(void) {
preload_resource(RES_BGM, "bgm_credits", RESF_OPTIONAL);
preload_resource(RES_SHADER, "tower_wall", RESF_DEFAULT);
preload_resources(RES_TEXTURE, RESF_DEFAULT,
"stage6/sky",
"stage6/towerwall",
"yukkureimu",
NULL);
}
void credits_loop(void) {
credits_preload();
credits_init();
while(credits.end) {
handle_events(NULL, 0, NULL);

View file

@ -11,6 +11,7 @@
void credits_loop(void);
void credits_add(char*, int);
void credits_preload(void);
#define CREDITS_ENTRY_FADEIN 200.0
#define CREDITS_ENTRY_FADEOUT 100.0

View file

@ -7,6 +7,7 @@
*/
#include "difficulty.h"
#include "resource/resource.h"
const char* difficulty_name(Difficulty diff) {
switch(diff) {
@ -40,3 +41,9 @@ Color difficulty_color(Difficulty diff) {
default: return rgb(0.5, 0.5, 0.5);
}
}
void difficulty_preload(void) {
for(Difficulty diff = D_Easy; diff < NUM_SELECTABLE_DIFFICULTIES + D_Easy; ++diff) {
preload_resource(RES_TEXTURE, difficulty_tex(diff), RESF_PERMANENT);
}
}

View file

@ -27,5 +27,6 @@ typedef enum {
const char* difficulty_name(Difficulty diff);
const char* difficulty_tex(Difficulty diff);
Color difficulty_color(Difficulty diff);
void difficulty_preload(void);
#endif

View file

@ -121,8 +121,14 @@ void ending_draw(Ending *e) {
draw_and_update_transition();
}
void ending_preload(void) {
preload_resource(RES_BGM, "bgm_ending", RESF_OPTIONAL);
}
void ending_loop(void) {
Ending e;
ending_preload();
create_ending(&e);
global.frames = 0;

View file

@ -38,5 +38,6 @@ void add_ending_entry(Ending *e, int time, char *msg, char *tex);
void create_ending(Ending *e);
void ending_loop(void);
void free_ending(Ending *e);
void ending_preload(void);
#endif

View file

@ -224,3 +224,18 @@ void process_enemies(Enemy **enemies) {
}
}
}
void enemies_preload(void) {
preload_resources(RES_ANIM, RESF_DEFAULT,
"fairy",
"bigfairy",
NULL);
preload_resources(RES_TEXTURE, RESF_DEFAULT,
"swirl",
NULL);
preload_resources(RES_SFX, RESF_OPTIONAL,
"enemydeath",
NULL);
}

View file

@ -64,4 +64,6 @@ void BigFairy(Enemy*, int t);
int enemy_flare(Projectile *p, int t);
void EnemyFlareShrink(Projectile *p, int t);
void enemies_preload(void);
#endif

View file

@ -7,7 +7,6 @@
#include "fbo.h"
#include "global.h"
#include "taisei_err.h"
void init_fbo(FBO *fbo) {
glGenTextures(1, &fbo->tex);

View file

@ -7,7 +7,6 @@
*/
#include "gamepad.h"
#include "taisei_err.h"
#include "config.h"
#include "events.h"
#include "global.h"
@ -28,32 +27,32 @@ void gamepad_init(void) {
return;
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
warnx("gamepad_init(): couldn't initialize SDL joystick subsystem: %s", SDL_GetError());
log_warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
return;
}
int i, cnt = gamepad_devicecount();
printf("gamepad_init(): found %i devices\n", cnt);
log_info("Found %i devices", cnt);
for(i = 0; i < cnt; ++i)
printf("%i: %s\n", i, SDL_JoystickNameForIndex(i));
log_info("Device #%i: %s", i, SDL_JoystickNameForIndex(i));
int dev = config_get_int(CONFIG_GAMEPAD_DEVICE);
if(dev < 0 || dev >= cnt) {
warnx("gamepad_init(): device %i is not available\n", dev);
log_warn("Device #%i is not available", dev);
gamepad_shutdown();
return;
}
gamepad.device = SDL_JoystickOpen(dev);
if(!gamepad.device) {
warnx("gamepad_init(): failed to open device %i [%s]", dev, gamepad_devicename(dev));
log_warn("Failed to open device %i: %s", dev, SDL_GetError());
gamepad_shutdown();
return;
}
gamepad.axis = malloc(SDL_JoystickNumAxes(gamepad.device));
printf("gamepad_init(): using device #%i: %s\n", dev, gamepad_devicename(dev));
log_info("Using device #%i: %s", dev, gamepad_devicename(dev));
SDL_JoystickEventState(SDL_ENABLE);
gamepad.initialized = 1;
}
@ -63,7 +62,7 @@ void gamepad_shutdown(void) {
return;
if(gamepad.initialized != 2)
printf("gamepad_shutdown(): disabled the gamepad subsystem\n");
log_info("Disabled the gamepad subsystem");
if(gamepad.device)
SDL_JoystickClose(gamepad.device);
@ -282,7 +281,7 @@ void gamepad_init_bare(void) {
return;
if(SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) {
warnx("gamepad_init(): couldn't initialize SDL joystick subsystem: %s", SDL_GetError());
log_warn("SDL_InitSubSystem() failed: %s", SDL_GetError());
return;
}

View file

@ -6,14 +6,6 @@
*/
#include "global.h"
#include "video.h"
#include <time.h>
#include <stdio.h>
#include <png.h>
#include "paths/native.h"
#include "resource/resource.h"
#include "taisei_err.h"
#include "replay.h"
Global global;
@ -35,6 +27,6 @@ void init_global(void) {
global.frameskip = INT_MAX;
}
warnx("FPS limiter disabled by environment. Gotta go fast! (frameskip = %i)", global.frameskip);
log_warn("FPS limiter disabled by environment. Gotta go fast! (frameskip = %i)", global.frameskip);
}
}

View file

@ -43,7 +43,6 @@
#include "difficulty.h"
#include "color.h"
#include "audio.h"
#include "taisei_err.h"
#include "rwops/all.h"
#define FILE_PREFIX PREFIX "/share/taisei/"

View file

@ -8,8 +8,8 @@
#include "hashtable.h"
#include "list.h"
#include "util.h"
#include <assert.h>
#include <string.h>
#include <zlib.h>
#include <stdio.h>
@ -301,13 +301,13 @@ void hashtable_print_stringkeys(Hashtable *ht) {
int total = 0;
int collisions = 0;
printf("------ %p:\n", (void*)ht);
log_debug("------ %p:", (void*)ht);
for(size_t i = 0; i < ht->table_size; ++i) {
int elems = 0;
printf("[bucket %lu] %p\n", (unsigned long)i, (void*)ht->table[i]);
log_debug("[bucket %lu] %p", (unsigned long)i, (void*)ht->table[i]);
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
printf(" -- %s (%lu): %p\n", (char*)e->key, (unsigned long)e->hash, e->data);
log_debug(" -- %s (%lu): %p", (char*)e->key, (unsigned long)e->hash, e->data);
++elems;
++total;
}
@ -323,7 +323,7 @@ void hashtable_print_stringkeys(Hashtable *ht) {
}
}
printf("%i total elements, %i unused buckets, %i collisions, max %i elems per bucket, %lu approx overhead\n",
log_debug("%i total elements, %i unused buckets, %i collisions, max %i elems per bucket, %lu approx overhead",
total, free_buckets, collisions, max_elems,
(unsigned long int)hashtable_get_approx_overhead(ht));
}
@ -341,7 +341,7 @@ void hashtable_print_stringkeys(Hashtable *ht) {
static void hashtable_printstrings(Hashtable *ht) {
for(size_t i = 0; i < ht->table_size; ++i) {
for(HashtableElement *e = ht->table[i]; e; e = e->next) {
printf("[HT %lu] %s (%lu): %s\n", (unsigned long)i, (char*)e->key, (unsigned long)e->hash, (char*)e->data);
log_info("[HT %lu] %s (%lu): %s\n", (unsigned long)i, (char*)e->key, (unsigned long)e->hash, (char*)e->data);
}
}
}
@ -365,7 +365,7 @@ int hashtable_test(void) {
}
hashtable_printstrings(ht);
printf("-----\n");
log_info("-----\n");
hashtable_set_string(ht, "12345", "asdfg");
hashtable_unset_string(ht, "test");
hashtable_set_string(ht, "herp", "deeeeeerp");

View file

@ -148,3 +148,17 @@ void spawn_items(complex pos, int point, int power, int bomb, int life) {
for(i = 0; i < life; i++)
spawn_item(pos, Life);
}
void items_preload(void) {
preload_resources(RES_TEXTURE, RESF_PERMANENT,
"items/power",
"items/point",
"items/life",
"items/bomb",
"items/bullet_point",
NULL);
preload_resources(RES_SFX, RESF_OPTIONAL,
"item_generic",
NULL);
}

View file

@ -46,6 +46,8 @@ void process_items(void);
void spawn_item(complex pos, Type type);
void spawn_items(complex pos, int point, int power, int bomb, int life);
void items_preload(void);
#define POWER_VALUE 3
#endif

View file

@ -84,7 +84,7 @@ void delete_all_elements_witharg(void **dest, void (callback)(void **, void *, v
#endif
#ifdef DEBUG_REFS
#define REFLOG(...) fprintf(stderr, __VA_ARGS__);
#define REFLOG(...) log_debug(__VA_ARGS__);
#else
#define REFLOG(...)
#endif
@ -95,7 +95,7 @@ int add_ref(void *ptr) {
for(i = 0; i < global.refs.count; i++) {
if(global.refs.ptrs[i].ptr == ptr) {
global.refs.ptrs[i].refs++;
REFLOG("increased refcount for %p (ref %i): %i\n", ptr, i, global.refs.ptrs[i].refs);
REFLOG("increased refcount for %p (ref %i): %i", ptr, i, global.refs.ptrs[i].refs);
return i;
} else if(firstfree < 0 && global.refs.ptrs[i].ptr == FREEREF) {
firstfree = i;
@ -105,14 +105,14 @@ int add_ref(void *ptr) {
if(firstfree >= 0) {
global.refs.ptrs[firstfree].ptr = ptr;
global.refs.ptrs[firstfree].refs = 1;
REFLOG("found free ref for %p: %i\n", ptr, firstfree);
REFLOG("found free ref for %p: %i", ptr, firstfree);
return firstfree;
}
global.refs.ptrs = realloc(global.refs.ptrs, (++global.refs.count)*sizeof(Reference));
global.refs.ptrs[global.refs.count - 1].ptr = ptr;
global.refs.ptrs[global.refs.count - 1].refs = 1;
REFLOG("new ref for %p: %i\n", ptr, global.refs.count - 1);
REFLOG("new ref for %p: %i", ptr, global.refs.count - 1);
return global.refs.count - 1;
}
@ -130,12 +130,12 @@ void free_ref(int i) {
return;
global.refs.ptrs[i].refs--;
REFLOG("decreased refcount for %p (ref %i): %i\n", global.refs.ptrs[i].ptr, i, global.refs.ptrs[i].refs);
REFLOG("decreased refcount for %p (ref %i): %i", global.refs.ptrs[i].ptr, i, global.refs.ptrs[i].refs);
if(global.refs.ptrs[i].refs <= 0) {
global.refs.ptrs[i].ptr = FREEREF;
global.refs.ptrs[i].refs = 0;
REFLOG("ref %i is now free\n", i);
REFLOG("ref %i is now free", i);
}
}
@ -151,7 +151,7 @@ void free_all_refs(void) {
}
if(inuse) {
warnx("free_all_refs(): %i refs were still in use (%i unique, %i total allocated)", inuse, inuse_unique, global.refs.count);
log_warn("%i refs were still in use (%i unique, %i total allocated)", inuse, inuse_unique, global.refs.count);
}
free(global.refs.ptrs);

226
src/log.c Normal file
View file

@ -0,0 +1,226 @@
#include <SDL_bits.h>
#include <SDL_mutex.h>
#ifdef LOG_ENABLE_BACKTRACE
#include <execinfo.h>
#endif
#include "log.h"
#include "util.h"
#include "list.h"
#ifdef __WINDOWS__
#define LOG_EOL "\r\n"
#else
#define LOG_EOL "\n"
#endif
typedef struct Logger {
struct Logger *next;
struct Logger *prev;
SDL_RWops *out;
unsigned int levels;
} Logger;
static Logger *loggers = NULL;
static unsigned int enabled_log_levels;
static unsigned int backtrace_log_levels;
static SDL_mutex *log_mutex;
// order must much the LogLevel enum after LOG_NONE
static const char *level_prefix_map[] = { "D", "I", "W", "E" };
static const char* level_prefix(LogLevel lvl) {
int idx = SDL_MostSignificantBitIndex32(lvl);
assert_nolog(idx >= 0 && idx < sizeof(level_prefix_map) / sizeof(char*));
return level_prefix_map[idx];
}
static char* format_log_string(LogLevel lvl, const char *funcname, const char *fmt, va_list args) {
const char *pref = level_prefix(lvl);
char *msg = vstrfmt(fmt, args);
char *final = strfmt("%-9d %s: %s(): %s%s", SDL_GetTicks(), pref, funcname, msg, LOG_EOL);
free(msg);
// TODO: maybe convert all \n in the message to LOG_EOL
return final;
}
noreturn static void log_abort(const char *msg) {
#ifdef LOG_FATAL_MSGBOX
if(msg) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Taisei error", msg, NULL);
}
#endif
// abort() doesn't clean up, but it lets us get a backtrace, which is more useful
log_shutdown();
abort();
}
static void log_internal(LogLevel lvl, bool is_backtrace, const char *funcname, const char *fmt, va_list args) {
assert(fmt[strlen(fmt)-1] != '\n');
char *str = NULL;
size_t slen = 0;
lvl &= enabled_log_levels;
if(lvl == LOG_NONE) {
return;
}
for(Logger *l = loggers; l; l = l->next) {
if(l->levels & lvl) {
if(!str) {
str = format_log_string(lvl, funcname, fmt, args);
slen = strlen(str);
}
// log_backtrace locks the mutex by itself, then recursively calls log_internal
if(is_backtrace) {
SDL_RWwrite(l->out, str, 1, slen);
} else {
SDL_LockMutex(log_mutex);
SDL_RWwrite(l->out, str, 1, slen);
SDL_UnlockMutex(log_mutex);
}
}
}
free(str);
if(is_backtrace) {
return;
}
if(lvl & backtrace_log_levels) {
log_backtrace(lvl);
}
if(lvl & LOG_FATAL) {
log_abort(str);
}
}
static char** get_backtrace(int *num) {
#ifdef LOG_ENABLE_BACKTRACE
void *ptrs[*num];
*num = backtrace(ptrs, *num);
return backtrace_symbols(ptrs, *num);
#else
char **dummy = malloc(sizeof(char*));
*num = 1;
*dummy = "[Backtrace support is not available in this build]";
return dummy;
#endif
}
void log_backtrace(LogLevel lvl) {
int num = LOG_BACKTRACE_SIZE;
char **symbols = get_backtrace(&num);
SDL_LockMutex(log_mutex);
_taisei_log(lvl, true, __func__, "*** BACKTRACE ***");
for(int i = 0; i < num; ++i) {
_taisei_log(lvl, true, __func__, "> %s", symbols[i]);
}
_taisei_log(lvl, true, __func__, "*** END OF BACKTRACE ***");
SDL_UnlockMutex(log_mutex);
free(symbols);
}
void _taisei_log(LogLevel lvl, bool is_backtrace, const char *funcname, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
log_internal(lvl, is_backtrace, funcname, fmt, args);
va_end(args);
}
noreturn void _taisei_log_fatal(LogLevel lvl, const char *funcname, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
log_internal(lvl, false, funcname, fmt, args);
va_end(args);
// should usually not get here, log_internal will abort earlier if lvl is LOG_FATAL
// that is unless LOG_FATAL is disabled for some reason
log_abort(NULL);
}
static void delete_logger(void **loggers, void *logger) {
Logger *l = logger;
SDL_RWclose(l->out);
delete_element(loggers, logger);
}
void log_init(LogLevel lvls, LogLevel backtrace_lvls) {
enabled_log_levels = lvls;
backtrace_log_levels = lvls & backtrace_lvls;
log_mutex = SDL_CreateMutex();
}
void log_shutdown(void) {
delete_all_elements((void**)&loggers, delete_logger);
SDL_DestroyMutex(log_mutex);
log_mutex = NULL;
}
bool log_initialized(void) {
return log_mutex;
}
void log_add_output(LogLevel levels, SDL_RWops *output) {
if(!output) {
return;
}
if(!(levels & enabled_log_levels)) {
SDL_RWclose(output);
return;
}
Logger *l = create_element((void**)&loggers, sizeof(Logger));
l->levels = levels;
l->out = output;
}
static LogLevel chr2lvl(char c) {
c = toupper(c);
for(int i = 0; i < sizeof(level_prefix_map) / sizeof(char*); ++i) {
if(c == level_prefix_map[i][0]) {
return (1 << i);
} else if(c == 'A') {
return LOG_ALL;
}
}
return 0;
}
LogLevel log_parse_levels(LogLevel lvls, const char *lvlmod) {
if(!lvlmod) {
return lvls;
}
bool enable = true;
for(const char *c = lvlmod; *c; ++c) {
if(*c == '+') {
enable = true;
} else if(*c == '-') {
enable = false;
} else if(enable) {
lvls |= chr2lvl(*c);
} else {
lvls &= ~chr2lvl(*c);
}
}
return lvls;
}

86
src/log.h Normal file
View file

@ -0,0 +1,86 @@
#ifndef TAISEI_LOG_H
#define TAISEI_LOG_H
#include <stdnoreturn.h>
#include <stdbool.h>
#include <SDL.h>
typedef enum LogLevel {
LOG_NONE = 0,
LOG_DEBUG = 1,
LOG_INFO = 2,
LOG_WARN = 4,
LOG_FATAL = 8,
LOG_SPAM = LOG_DEBUG | LOG_INFO,
LOG_ALERT = LOG_WARN | LOG_FATAL,
LOG_ALL = LOG_SPAM | LOG_ALERT,
} LogLevel;
#ifndef LOG_DEFAULT_LEVELS
#define LOG_DEFAULT_LEVELS LOG_ALL
#endif
#ifndef LOG_DEFAULT_LEVELS_FILE
#define LOG_DEFAULT_LEVELS_FILE LOG_ALL
#endif
#ifndef LOG_DEFAULT_LEVELS_CONSOLE
#ifdef DEBUG
#define LOG_DEFAULT_LEVELS_CONSOLE LOG_ALL
#else
#define LOG_DEFAULT_LEVELS_CONSOLE LOG_ALERT
#endif
#endif
#ifndef LOG_DEFAULT_LEVELS_STDOUT
#define LOG_DEFAULT_LEVELS_STDOUT LOG_SPAM
#endif
#ifndef LOG_DEFAULT_LEVELS_STDERR
#define LOG_DEFAULT_LEVELS_STDERR LOG_ALERT
#endif
#ifndef LOG_DEFAULT_LEVELS_BACKTRACE
#ifdef LOG_ENABLE_BACKTRACE
#define LOG_DEFAULT_LEVELS_BACKTRACE LOG_FATAL
#else
#define LOG_DEFAULT_LEVELS_BACKTRACE LOG_NONE
#endif
#endif
#ifndef LOG_BACKTRACE_SIZE
#define LOG_BACKTRACE_SIZE 32
#endif
void log_init(LogLevel lvls, LogLevel backtrace_lvls);
void log_shutdown(void);
void log_add_output(LogLevel levels, SDL_RWops *output);
void log_backtrace(LogLevel lvl);
LogLevel log_parse_levels(LogLevel lvls, const char *lvlmod);
bool log_initialized(void);
#ifdef DEBUG
#define log_debug(...) _taisei_log(LOG_DEBUG, false, __func__, __VA_ARGS__)
#else
#define log_debug(...)
#endif
#define log_info(...) _taisei_log(LOG_INFO, false, __func__, __VA_ARGS__)
#define log_warn(...) _taisei_log(LOG_WARN, false, __func__, __VA_ARGS__)
#define log_fatal(...) _taisei_log_fatal(LOG_FATAL, __func__, __VA_ARGS__)
#define log_custom(lvl, ...) _taisei_log(lvl, false, __func__, __VA_ARGS__)
//
// don't call these directly, use the macros
//
void _taisei_log(LogLevel lvl, bool is_backtrace, const char *funcname, const char *fmt, ...)
__attribute__((format(printf, 4, 5)));
noreturn void _taisei_log_fatal(LogLevel lvl, const char *funcname, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
#endif

View file

@ -7,7 +7,7 @@
#include <sys/stat.h>
#include <errno.h>
#include "taisei_err.h"
#include <locale.h>
#include "global.h"
#include "video.h"
@ -19,37 +19,44 @@
#include "resource/bgm.h"
#include "progress.h"
#include "hashtable.h"
#include "log.h"
void taisei_shutdown(void) {
log_info("Shutting down");
config_save(CONFIG_FILE);
progress_save();
printf("\nshutdown:\n");
free_all_refs();
free_resources();
free_resources(true);
audio_shutdown();
video_shutdown();
gamepad_shutdown();
stage_free_array();
config_uninit();
log_info("Good bye");
SDL_Quit();
printf("-- Good Bye.\n");
log_shutdown();
}
void init_log(void) {
#if defined(__WINDOWS__) && !defined(__WINDOWS_CONSOLE__)
const char *pref = get_config_path();
char *s;
char *logpath = strfmt("%s/%s", pref, "log.txt");
s = strfmt("%s/%s", pref, "stdout.txt");
freopen(s, "w", stdout);
free(s);
LogLevel lvls_console = log_parse_levels(LOG_DEFAULT_LEVELS_CONSOLE, getenv("TAISEI_LOGLVLS_CONSOLE"));
LogLevel lvls_stdout = lvls_console & log_parse_levels(LOG_DEFAULT_LEVELS_STDOUT, getenv("TAISEI_LOGLVLS_STDOUT"));
LogLevel lvls_stderr = lvls_console & log_parse_levels(LOG_DEFAULT_LEVELS_STDERR, getenv("TAISEI_LOGLVLS_STDERR"));
LogLevel lvls_file = log_parse_levels(LOG_DEFAULT_LEVELS_FILE, getenv("TAISEI_LOGLVLS_FILE"));
LogLevel lvls_backtrace = log_parse_levels(LOG_DEFAULT_LEVELS_BACKTRACE, getenv("TAISEI_LOGLVLS_BACKTRACE"));
s = strfmt("%s/%s", pref, "stderr.txt");
freopen(s, "w", stderr);
free(s);
#endif
log_init(LOG_DEFAULT_LEVELS, lvls_backtrace);
log_add_output(lvls_stdout, SDL_RWFromFP(stdout, false));
log_add_output(lvls_stderr, SDL_RWFromFP(stderr, false));
log_add_output(lvls_file, SDL_RWFromFile(logpath, "w"));
free(logpath);
}
int run_tests(void) {
@ -83,16 +90,14 @@ int run_tests(void) {
#endif
int main(int argc, char **argv) {
if(run_tests()) {
return 0;
}
setlocale(LC_ALL, "C");
#ifdef DEBUG
if(argc >= 2 && argv[1] && !strcmp(argv[1], "dumpstages")) {
stage_init_array();
for(StageInfo *stg = stages; stg->procs; ++stg) {
printf("%i %s: %s\n", stg->id, stg->title, stg->subtitle);
tsfprintf(stdout, "%i %s: %s\n", stg->id, stg->title, stg->subtitle);
}
return 0;
@ -105,7 +110,7 @@ int main(int argc, char **argv) {
if(argc >= 2 && !strcmp(argv[1], "replay")) {
if(argc < 3) {
fprintf(stderr, "Usage: %s replay /path/to/replay.tsr [stage num]\n", argv[0]);
tsfprintf(stderr, "Usage: %s replay /path/to/replay.tsr [stage num]\n", argv[0]);
return 1;
}
@ -123,40 +128,35 @@ int main(int argc, char **argv) {
init_paths();
init_log();
printf("Content path: %s\n", get_prefix());
printf("Userdata path: %s\n", get_config_path());
if(run_tests()) {
return 0;
}
log_info("Content path: %s", get_prefix());
log_info("Userdata path: %s", get_config_path());
MKDIR(get_config_path());
MKDIR(get_screenshots_path());
MKDIR(get_replays_path());
if(chdir(get_prefix())) {
errx(-1, "chdir() failed: %s", strerror(errno));
log_fatal("chdir() failed: %s", strerror(errno));
} else {
char cwd[1024]; // i don't care if this is not enough for you, getcwd is garbage
getcwd(cwd, sizeof(cwd));
printf("Changed working directory to %s\n", cwd);
log_info("Changed working directory to %s", cwd);
}
config_load(CONFIG_FILE);
printf("initialize:\n");
if(SDL_Init(SDL_INIT_VIDEO) < 0)
errx(-1, "Error initializing SDL: %s", SDL_GetError());
printf("-- SDL\n");
log_fatal("SDL_Init() failed: %s", SDL_GetError());
init_global();
video_init();
printf("-- Video and OpenGL\n");
audio_init();
printf("-- Audio\n");
init_resources();
draw_loading_screen();
load_resources();
gamepad_init();
stage_init_array();
@ -164,7 +164,8 @@ int main(int argc, char **argv) {
set_transition(TransLoader, 0, FADE_TIME*2);
printf("initialization complete.\n");
log_info("Initialization complete");
atexit(taisei_shutdown);
if(replay_path) {
@ -180,28 +181,27 @@ int main(int argc, char **argv) {
return 0;
}
printf("** Compiled with DEBUG flag!\n");
log_warn("Compiled with DEBUG flag!");
if(argc >= 2 && argv[1]) {
printf("** Entering stage skip mode: Stage %d\n", atoi(argv[1]));
log_info("Entering stage skip mode: Stage %d", atoi(argv[1]));
StageInfo* stg = stage_get(atoi(argv[1]));
if(!stg) {
errx(-1, "Invalid stage id");
log_fatal("Invalid stage id");
}
global.diff = stg->difficulty;
if(!global.diff) {
if(argc == 3 && argv[2]) {
global.diff = atoi(argv[2]);
log_info("Setting difficulty to %s", difficulty_name(global.diff));
} else if(!global.diff) {
global.diff = D_Easy;
}
if(argc == 3 && argv[2]) {
printf("** Setting difficulty to %d.\n", atoi(argv[2]));
global.diff = atoi(argv[2]);
}
printf("** Entering %s.\n", stg->title);
log_info("Entering %s", stg->title);
do {
global.game_over = 0;

View file

@ -66,6 +66,8 @@ troll2:
goto troll2;
}
free_resources(false);
if(global.replay_stage) {
switch(config_get_int(CONFIG_SAVE_RPY)) {
case 0: break;
@ -91,6 +93,7 @@ troll2:
ending_loop();
start_bgm("bgm_credits");
credits_loop();
free_resources(false);
}
start_bgm("bgm_menu");

View file

@ -54,7 +54,7 @@ void draw_difficulty_menu(MenuData *menu) {
menu->entries[i].drawdata += 0.2 * (30*(i == menu->cursor) - menu->entries[i].drawdata);
glPushMatrix();
glTranslatef(SCREEN_W/2 - (int)menu->entries[i].drawdata+25*i-50, SCREEN_H/3 + 90*(i-0.3*menu->drawdata[0]),0);
glTranslatef(SCREEN_W/2 + SCREEN_W*sign((i&1)-0.5)*(i!=menu->cursor)*menu_fade(menu) - (int)menu->entries[i].drawdata+25*i-50, SCREEN_H/3 + 90*(i-0.3*menu->drawdata[0]),0);
//glColor4f(0,0,0,1);

View file

@ -13,7 +13,7 @@
void continue_game(MenuData *m, void *arg)
{
printf("The game is being continued...\n");
log_info("The game is being continued...");
if(global.replaymode == REPLAY_RECORD) { // actually... I'd be strange if REPLAY_PLAY ever got there
replay_destroy(&global.replay); // 19:39:29 [@ laochailan] no. no fame for continue users >:D

View file

@ -165,7 +165,32 @@ void draw_main_menu(MenuData *menu) {
}
void draw_loading_screen(void) {
preload_resource(RES_TEXTURE, "loading", RESF_PERMANENT);
set_ortho();
draw_texture(SCREEN_W/2, SCREEN_H/2, "loading");
SDL_GL_SwapWindow(video.window);
}
void menu_preload(void) {
difficulty_preload();
preload_resources(RES_TEXTURE, RESF_PERMANENT,
"mainmenu/mainmenubg",
"mainmenu/logo",
"part/smoke",
"part/petal",
"dialog/marisa",
"dialog/youmu",
"charselect_arrow",
NULL);
preload_resources(RES_SFX, RESF_PERMANENT | RESF_OPTIONAL,
"generic_shot",
"shot_special1",
"hit",
NULL);
preload_resources(RES_BGM, RESF_PERMANENT | RESF_OPTIONAL,
"bgm_menu",
NULL);
}

View file

@ -15,5 +15,6 @@ void draw_main_menu_bg(MenuData *m);
void draw_main_menu(MenuData *m);
void main_menu_update_spellpractice(void);
void draw_loading_screen(void);
void menu_preload(void);
#endif

View file

@ -5,7 +5,6 @@
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
*/
#include <assert.h>
#include "menu.h"
#include "global.h"
#include "video.h"

View file

@ -13,7 +13,6 @@
#include "global.h"
#include "video.h"
#include "paths/native.h"
#include "taisei_err.h"
// --- Menu entry <-> config option binding stuff --- //

View file

@ -266,7 +266,7 @@ int fill_replayview_menu(MenuData *m) {
int rpys = 0;
if(!dir) {
printf("Could't read %s\n", get_replays_path());
log_warn("Could't read %s", get_replays_path());
return -1;
}

View file

@ -434,3 +434,26 @@ void player_graze(Player *plr, complex pos, int pts) {
create_particle2c("flare", pos, 0, Shrink, timeout_linear, 5 + 5 * afrand(2), (1+afrand(0)*5)*cexp(I*tsrand_a(1)))->type=PlrProj;
}
}
void player_preload(void) {
const int flags = RESF_DEFAULT;
preload_resources(RES_TEXTURE, flags,
"focus",
"fairy_circle",
"masterspark",
"masterspark_ring",
NULL);
preload_resources(RES_SFX, flags | RESF_OPTIONAL,
"graze",
"death",
"generic_shot",
"masterspark",
NULL);
preload_resources(RES_ANIM, flags,
"youmu",
"marisa",
NULL);
}

View file

@ -110,4 +110,6 @@ void player_event(Player* plr, int type, int key);
void player_applymovement(Player* plr);
void player_input_workaround(Player *plr);
void player_preload(void);
#endif

View file

@ -9,7 +9,6 @@
#include "progress.h"
#include "paths/native.h"
#include "taisei_err.h"
#include "stage.h"
/*
@ -73,18 +72,18 @@ static void progress_read(SDL_RWops *file) {
int64_t filesize = SDL_RWsize(file);
if(filesize < 0) {
warnx("progress_read(): SDL_RWsize() failed: %s", SDL_GetError());
log_warn("SDL_RWsize() failed: %s", SDL_GetError());
return;
}
if(filesize > PROGRESS_MAXFILESIZE) {
warnx("progress_read(): progress file is huge (%i bytes, %i max)", filesize, PROGRESS_MAXFILESIZE);
log_warn("Progress file is huge (%li bytes, %i max)", (long)filesize, PROGRESS_MAXFILESIZE);
return;
}
for(int i = 0; i < sizeof(progress_magic_bytes); ++i) {
if(SDL_ReadU8(file) != progress_magic_bytes[i]) {
warnx("progress_read(): invalid header");
log_warn("Invalid header");
return;
}
}
@ -101,7 +100,7 @@ static void progress_read(SDL_RWops *file) {
uint8_t *buf = malloc(bufsize);
if(!SDL_RWread(file, buf, bufsize, 1)) {
warnx("progress_read(): SDL_RWread() failed: %s", SDL_GetError());
log_warn("SDL_RWread() failed: %s", SDL_GetError());
free(buf);
return;
}
@ -110,7 +109,7 @@ static void progress_read(SDL_RWops *file) {
uint32_t checksum = progress_checksum(buf, bufsize);
if(checksum != checksum_fromfile) {
warnx("progress_read(): bad checksum: %x != %x", checksum, checksum_fromfile);
log_warn("Bad checksum: %x != %x", checksum, checksum_fromfile);
SDL_RWclose(vfile);
free(buf);
return;
@ -152,7 +151,7 @@ static void progress_read(SDL_RWops *file) {
break;
default:
warnx("progress_read(): unknown command %i, skipping %u bytes", cmd, cmdsize);
log_warn("Unknown command %i, skipping %u bytes", cmd, cmdsize);
while(cur++ < cmdsize)
SDL_ReadU8(vfile);
break;
@ -305,7 +304,7 @@ static void progress_write(SDL_RWops *file) {
if(SDL_RWtell(vfile) != bufsize) {
free(buf);
errx(-1, "progress_write(): buffer is inconsistent\n");
log_fatal("Buffer is inconsistent");
return;
}
@ -314,7 +313,7 @@ static void progress_write(SDL_RWops *file) {
SDL_RWwrite(file, &cs, 4, 1);
if(!SDL_RWwrite(file, buf, bufsize, 1)) {
warnx("progress_write(): SDL_RWread() failed: %s", SDL_GetError());
log_fatal("SDL_RWwrite() failed: %s", SDL_GetError());
free(buf);
return;
}
@ -348,7 +347,7 @@ void progress_load(void) {
SDL_RWops *file = SDL_RWFromFile(p, "rb");
if(!file) {
warnx("progress_load(): couldn't open the progress file: %s\n", SDL_GetError());
log_warn("Couldn't open the progress file: %s", SDL_GetError());
free(p);
return;
}
@ -363,7 +362,7 @@ void progress_save(void) {
SDL_RWops *file = SDL_RWFromFile(p, "wb");
if(!file) {
warnx("progress_save(): couldn't open the progress file: %s\n", SDL_GetError());
log_warn("Couldn't open the progress file: %s", SDL_GetError());
free(p);
return;
}

View file

@ -419,3 +419,39 @@ void petal_explosion(int n, complex pos) {
create_particle4c("petal", pos, rgba(0.6,1-afrand(0)*0.4,0.5,1-0.5*afrand(1)), Petal, asymptotic, (3+5*afrand(2))*cexp(I*M_PI*2*afrand(3)), 5, afrand(4) + afrand(5)*I, afrand(6) + 360.0*I*afrand(7));
}
}
void projectiles_preload(void) {
preload_resources(RES_TEXTURE, RESF_PERMANENT,
"part/blast",
"part/boss_shadow",
"part/flare",
"part/lasercurve",
"part/marilaser_part0",
"part/maristar_orbit",
"part/petal",
"part/smoke",
"part/stain",
"part/youmu_slice",
"proj/ball",
"proj/bigball",
"proj/bullet",
"proj/card",
"proj/crystal",
"proj/flea",
"proj/hghost",
"proj/marilaser",
"proj/marisa",
"proj/maristar",
"proj/plainball",
"proj/rice",
"proj/soul",
"proj/thickrice",
"proj/wave",
"proj/youhoming",
"proj/youmu",
NULL);
preload_resources(RES_SHADER, RESF_PERMANENT,
"bullet_color",
NULL);
}

View file

@ -98,4 +98,6 @@ int timeout_linear(Projectile *p, int t);
void Petal(Projectile *p, int t);
void petal_explosion(int n, complex pos);
void projectiles_preload(void);
#endif

View file

@ -11,7 +11,6 @@
#include <time.h>
#include "global.h"
#include "random.h"
#include "taisei_err.h"
/*
* Multiply-with-carry algorithm
@ -36,7 +35,7 @@ void tsrand_seed_p(RandomState *rnd, uint32_t seed) {
uint32_t tsrand_p(RandomState *rnd) {
if(rnd->locked) {
warnx("Attempted to use a locked RNG state!\n");
log_warn("Attempted to use a locked RNG state");
return 0;
}
@ -105,7 +104,7 @@ static uint32_t tsrand_array[TSRAND_ARRAY_LIMIT];
static int tsrand_array_elems;
static uint64_t tsrand_fillflags = 0;
static void tsrand_error(const char *file, unsigned int line, const char *fmt, ...) {
static void tsrand_error(const char *file, const char *func, unsigned int line, const char *fmt, ...) {
char buf[2048] = { 0 };
va_list args;
@ -113,14 +112,14 @@ static void tsrand_error(const char *file, unsigned int line, const char *fmt, .
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
errx(-1, "tsrand error: %s [%s:%u]", buf, file, line);
log_fatal("%s(): %s [%s:%u]", func, buf, file, line);
}
#define TSRANDERR(...) tsrand_error(file, line, __VA_ARGS__)
#define TSRANDERR(...) tsrand_error(file, __func__, line, __VA_ARGS__)
void __tsrand_fill_p(RandomState *rnd, int amount, const char *file, unsigned int line) {
if(tsrand_fillflags) {
TSRANDERR("tsrand_fill_p: some indices left unused from the previous call");
TSRANDERR("Some indices left unused from the previous call");
return;
}
@ -138,7 +137,7 @@ void __tsrand_fill(int amount, const char *file, unsigned int line) {
uint32_t __tsrand_a(int idx, const char *file, unsigned int line) {
if(idx >= tsrand_array_elems || idx < 0) {
TSRANDERR("tsrand_a: index out of range (%i / %i)", idx, tsrand_array_elems);
TSRANDERR("Index out of range (%i / %i)", idx, tsrand_array_elems);
return 0;
}
@ -147,7 +146,7 @@ uint32_t __tsrand_a(int idx, const char *file, unsigned int line) {
return tsrand_array[idx];
}
TSRANDERR("tsrand_a: index %i used multiple times", idx);
TSRANDERR("Index %i used multiple times", idx);
return 0;
}

View file

@ -8,7 +8,6 @@
#include "replay.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
@ -16,14 +15,13 @@
#include "global.h"
#include "paths/native.h"
#include "taisei_err.h"
static uint8_t replay_magic_header[] = REPLAY_MAGIC_HEADER;
void replay_init(Replay *rpy) {
memset(rpy, 0, sizeof(Replay));
stralloc(&rpy->playername, config_get_str(CONFIG_PLAYERNAME));
printf("replay_init(): replay initialized for writting\n");
log_debug("Replay at %p initialized for writing", (void*)rpy);
}
ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t seed, Difficulty diff, uint32_t points, Player *plr) {
@ -52,7 +50,7 @@ ReplayStage* replay_create_stage(Replay *rpy, StageInfo *stage, uint64_t seed, D
s->plr_power = plr->power;
s->plr_inputflags = plr->inputflags;
printf("replay_init_stage(): created a new stage for writting\n");
log_debug("Created a new stage %p in replay %p", (void*)s, (void*)rpy);
return s;
}
@ -103,7 +101,7 @@ void replay_destroy(Replay *rpy) {
free(rpy->playername);
memset(rpy, 0, sizeof(Replay));
printf("Replay destroyed.\n");
log_debug("Replay at %p destroyed", (void*)rpy);
}
void replay_stage_event(ReplayStage *stg, uint32_t frame, uint8_t type, int16_t value) {
@ -119,14 +117,14 @@ void replay_stage_event(ReplayStage *stg, uint32_t frame, uint8_t type, int16_t
s->numevents++;
if(s->numevents >= s->capacity) {
printf("Replay stage reached its capacity of %d, reallocating\n", s->capacity);
log_debug("Replay stage reached its capacity of %d, reallocating", s->capacity);
s->capacity *= 2;
s->events = (ReplayEvent*)realloc(s->events, sizeof(ReplayEvent) * s->capacity);
printf("The new capacity is %d\n", s->capacity);
log_debug("The new capacity is %d", s->capacity);
}
if(type == EV_OVER) {
printf("The replay is OVER\n");
log_debug("The replay is OVER");
}
}
@ -253,12 +251,12 @@ int replay_write(Replay *rpy, SDL_RWops *file, bool compression) {
}
#ifdef REPLAY_LOAD_GARBAGE_TEST
#define PRINTPROP(prop,fmt) printf("replay_read(): " #prop " = %" # fmt " [%li / %li]\n", prop, (long int)SDL_RWtell(file), (long int)filesize)
#define PRINTPROP(prop,fmt) log_debug(#prop " = %" # fmt " [%li / %li]", prop, (long int)SDL_RWtell(file), (long int)filesize)
#else
#define PRINTPROP(prop,fmt) (void)(prop)
#endif
#define CHECKPROP(prop,fmt) PRINTPROP(prop,fmt); if(filesize > 0 && SDL_RWtell(file) == filesize) { warnx("replay_read(): premature EOF"); return false; }
#define CHECKPROP(prop,fmt) PRINTPROP(prop,fmt); if(filesize > 0 && SDL_RWtell(file) == filesize) { log_warn("Premature EOF"); return false; }
static void replay_read_string(SDL_RWops *file, char **ptr) {
size_t len = SDL_ReadLE16(file);
@ -273,7 +271,7 @@ static int replay_read_header(Replay *rpy, SDL_RWops *file, int64_t filesize, si
for(uint8_t *u8_p = replay_magic_header; *u8_p; ++u8_p) {
++(*ofs);
if(SDL_ReadU8(file) != *u8_p) {
warnx("replay_read(): incorrect header");
log_warn("Incorrect header");
return false;
}
}
@ -282,7 +280,7 @@ static int replay_read_header(Replay *rpy, SDL_RWops *file, int64_t filesize, si
(*ofs) += 2;
if((rpy->version & ~REPLAY_VERSION_COMPRESSION_BIT) != REPLAY_STRUCT_VERSION) {
warnx("replay_read(): incorrect version");
log_warn("Incorrect version");
return false;
}
@ -301,7 +299,7 @@ static int replay_read_meta(Replay *rpy, SDL_RWops *file, int64_t filesize) {
CHECKPROP(rpy->numstages = SDL_ReadLE16(file), u);
if(!rpy->numstages) {
warnx("replay_read(): no stages in replay");
log_warn("No stages in replay");
return false;
}
@ -327,7 +325,7 @@ static int replay_read_meta(Replay *rpy, SDL_RWops *file, int64_t filesize) {
CHECKPROP(stg->numevents = SDL_ReadLE16(file), u);
if(replay_calc_stageinfo_checksum(stg) + SDL_ReadLE32(file)) {
warnx("replay_read(): stageinfo is corrupt");
log_warn("Stageinfo is corrupt");
return false;
}
}
@ -340,7 +338,7 @@ static int replay_read_events(Replay *rpy, SDL_RWops *file, int64_t filesize) {
ReplayStage *stg = rpy->stages + i;
if(!stg->numevents) {
warnx("replay_read(): no events in stage");
log_warn("No events in stage");
return false;
}
@ -366,23 +364,22 @@ int replay_read(Replay *rpy, SDL_RWops *file, ReplayReadMode mode) {
mode &= REPLAY_READ_ALL;
if(!mode) {
errx(-1, "replay_read(): called with invalid read mode");
return false;
log_fatal("Called with invalid read mode");
}
filesize = SDL_RWsize(file);
if(filesize < 0) {
warnx("replay_read(): SDL_RWsize() failed: %s", SDL_GetError());
log_warn("SDL_RWsize() failed: %s", SDL_GetError());
} else {
printf("replay_read(): %li bytes\n", (long int)filesize);
log_debug("%li bytes", (long int)filesize);
}
if(mode & REPLAY_READ_META) {
memset(rpy, 0, sizeof(Replay));
if(filesize > 0 && filesize <= sizeof(replay_magic_header) + 2) {
warnx("replay_read(): replay file is too short (%i)", filesize);
log_warn("Replay file is too short (%li)", (long int)filesize);
return false;
}
@ -396,7 +393,7 @@ int replay_read(Replay *rpy, SDL_RWops *file, ReplayReadMode mode) {
if(rpy->version & REPLAY_VERSION_COMPRESSION_BIT) {
if(rpy->fileoffset < SDL_RWtell(file)) {
warnx("replay_read(): invalid offset %li", (long int)rpy->fileoffset);
log_warn("Invalid offset %li", (long int)rpy->fileoffset);
return false;
}
@ -425,20 +422,19 @@ int replay_read(Replay *rpy, SDL_RWops *file, ReplayReadMode mode) {
if(mode & REPLAY_READ_EVENTS) {
if(!(mode & REPLAY_READ_META)) {
if(!rpy->fileoffset) {
errx(-1, "replay_read(): tried to read events before reading metadata");
return false;
log_fatal("Tried to read events before reading metadata");
}
for(int i = 0; i < rpy->numstages; ++i) {
if(rpy->stages[i].events) {
warnx("replay_read(): reading events into a replay that already had events, call replay_destroy_events() if this is intended");
log_warn("Reading events into a replay that already had events, call replay_destroy_events() if this is intended");
replay_destroy_events(rpy);
break;
}
}
if(SDL_RWseek(file, rpy->fileoffset, RW_SEEK_SET) < 0) {
warnx("replay_read(): SDL_RWseek() failed: %s", SDL_GetError());
log_warn("SDL_RWseek() failed: %s", SDL_GetError());
return false;
}
}
@ -488,13 +484,13 @@ char* replay_getpath(const char *name, bool ext) {
int replay_save(Replay *rpy, const char *name) {
char *p = replay_getpath(name, !strendswith(name, REPLAY_EXTENSION));
printf("replay_save(): saving %s\n", p);
log_info("Saving %s", p);
SDL_RWops *file = SDL_RWFromFile(p, "wb");
free(p);
if(!file) {
warnx("replay_save(): SDL_RWFromFile() failed: %s\n", SDL_GetError());
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
return false;
}
@ -512,7 +508,7 @@ int replay_load(Replay *rpy, const char *name, ReplayReadMode mode) {
p = replay_getpath(name, !strendswith(name, REPLAY_EXTENSION));
}
printf("replay_load(): loading %s (mode %i)\n", p, mode);
log_info("replay_load(): loading %s (mode %i)", p, mode);
SDL_RWops *file = SDL_RWFromFile(p, "rb");
@ -521,7 +517,7 @@ int replay_load(Replay *rpy, const char *name, ReplayReadMode mode) {
}
if(!file) {
warnx("replay_save(): SDL_RWFromFile() failed: %s\n", SDL_GetError());
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
return false;
}
@ -569,14 +565,14 @@ void replay_stage_check_desync(ReplayStage *stg, int time, uint16_t check, Repla
if(mode == REPLAY_PLAY) {
if(stg->desync_check && stg->desync_check != check) {
warnx("replay_check_desync(): Replay desync detected! %u != %u\n", stg->desync_check, check);
log_warn("Replay desync detected! %u != %u", stg->desync_check, check);
} else {
printf("replay_check_desync(): %u OK\n", check);
log_debug("%u OK", check);
}
}
#ifdef REPLAY_WRITE_DESYNC_CHECKS
else {
printf("replay_stage_check_desync(): %u\n", check);
log_debug("%u", check);
replay_stage_event(stg, time, EV_CHECK_DESYNC, (int16_t)check);
}
#endif
@ -607,7 +603,7 @@ int replay_test(void) {
SDL_WriteU8(handle, 's');
SDL_WriteU8(handle, 't');
printf("replay_test(): wrote a valid replay header\n");
log_info("Wrote a valid replay header");
RandomState rnd;
tsrand_init(&rnd, time(0));
@ -616,20 +612,20 @@ int replay_test(void) {
SDL_WriteU8(handle, tsrand_p(&rnd) & 0xFF);
}
printf("replay_test(): wrote %i bytes of garbage\n", sz);
log_info("Wrote %i bytes of garbage", sz);
SDL_RWseek(handle, 0, RW_SEEK_SET);
for(int i = 0; i < headsz; ++i) {
printf("%x ", buf[i]);
tsfprintf(stdout, "%x ", buf[i]);
}
printf("\n");
tsfprintf(stdout, "\n");
Replay rpy;
if(replay_read(&rpy, handle, REPLAY_READ_ALL)) {
errx(-1, "Succeeded loading garbage data as a replay... that shouldn't happen");
log_fatal("Succeeded loading garbage data as a replay... that shouldn't happen");
}
replay_destroy(&rpy);
@ -656,7 +652,7 @@ void replay_play(Replay *rpy, int firststage) {
StageInfo *gstg = stage_get(rstg->stage);
if(!gstg) {
printf("replay_play(): Invalid stage %d in replay at %i skipped.\n", rstg->stage, i);
log_warn("Invalid stage %d in replay at %i skipped.\n", rstg->stage, i);
continue;
}
@ -673,6 +669,7 @@ void replay_play(Replay *rpy, int firststage) {
global.replaymode = REPLAY_RECORD;
replay_destroy(&global.replay);
global.replay_stage = NULL;
free_resources(false);
}
void replay_play_path(const char *path, int firststage) {

View file

@ -5,92 +5,56 @@
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
*/
#include <dirent.h>
#include "animation.h"
#include "texture.h"
#include "global.h"
#include "resource.h"
#include "list.h"
#include "taisei_err.h"
char* animation_path(const char *name) {
DIR *dir = opendir("gfx/");
if(dir == NULL)
return NULL;
struct dirent *dp;
while((dp = readdir(dir)) != NULL) {
char *filepath = strjoin("gfx/", dp->d_name, NULL);
char *tmpname = NULL;
if(check_animation_path(filepath)) {
if(!strcmp(tmpname = animation_name(filepath), name)) {
free(tmpname);
return filepath;
}
}
free(filepath);
free(tmpname);
}
return NULL;
return strjoin(ANI_PATH_PREFIX, name, ANI_EXTENSION, NULL);
}
bool check_animation_path(const char *path) {
char *base = strjoin(TEX_PATH_PREFIX, "ani_", NULL);
bool result = strstartswith(path, base) && strendswith(path, TEX_EXTENSION);
free(base);
return result;
return strendswith(path, ANI_EXTENSION);
}
char* animation_name(const char *filename) {
char *name = resource_util_basename(ANI_PATH_PREFIX, filename);
char *c = name, *newname = NULL;
while(c = strchr(c, '_')) {
newname = ++c;
}
newname = strdup(newname);
free(name);
return newname;
}
void* load_animation(const char *filename) {
Animation *ani = malloc(sizeof(Animation));
void* load_animation(const char *filename, unsigned int flags) {
char *basename = resource_util_basename(ANI_PATH_PREFIX, filename);
char name[strlen(basename) + 1];
strcpy(name, basename);
char *tok;
strtok(name, "_");
Hashtable *ht = parse_keyvalue_file(filename, 5);
#define ANIFAIL(what) { warnx("load_animation(): bad '" what "' in filename '%s'", basename); free(basename); return NULL; }
if((tok = strtok(NULL, "_")) == NULL)
ANIFAIL("rows")
ani->rows = atoi(tok);
if((tok = strtok(NULL, "_")) == NULL)
ANIFAIL("cols")
ani->cols = atoi(tok);
if((tok = strtok(NULL, "_")) == NULL)
ANIFAIL("speed")
ani->speed = atoi(tok);
if(ani->speed == 0) {
warnx("load_animation(): animation speed of %s == 0. relativity?", name);
if(!ht) {
log_warn("parse_keyvalue_file() failed");
free(basename);
return NULL;
}
ani->tex = get_tex(basename);
#define ANIFAIL(what) { log_warn("Bad '" what "' in animation '%s'", basename); free(ani); free(basename); return NULL; }
Animation *ani = malloc(sizeof(Animation));
ani->rows = atoi((char*)hashtable_get_string(ht, "rows"));
ani->cols = atoi((char*)hashtable_get_string(ht, "cols"));
ani->speed = atoi((char*)hashtable_get_string(ht, "speed"));
hashtable_foreach(ht, hashtable_iter_free_data, NULL);
hashtable_free(ht);
if(ani->rows < 1) ANIFAIL("rows")
if(ani->cols < 1) ANIFAIL("cols")
if(ani->speed == 0) {
log_warn("Animation speed of %s == 0. relativity?", name);
free(basename);
free(ani);
return NULL;
}
ani->tex = get_resource(RES_TEXTURE, basename, flags)->texture;
if(!ani->tex) {
warnx("load_animation(): couldn't get texture '%s'", basename);
log_warn("Couldn't get texture '%s'", basename);
free(basename);
return NULL;
}
@ -105,7 +69,7 @@ void* load_animation(const char *filename) {
}
Animation *get_ani(const char *name) {
return get_resource(RES_ANIM, name, RESF_REQUIRED)->animation;
return get_resource(RES_ANIM, name, RESF_DEFAULT)->animation;
}
void draw_animation(float x, float y, int row, const char *name) {

View file

@ -26,8 +26,7 @@ typedef struct Animation {
char* animation_path(const char *name);
bool check_animation_path(const char *path);
void* load_animation(const char *filename);
char* animation_name(const char *filename);
void* load_animation(const char *filename, unsigned int flags);
Animation *get_ani(const char *name);
@ -35,5 +34,6 @@ void draw_animation(float x, float y, int row, const char *name);
void draw_animation_p(float x, float y, int row, Animation *ani);
#define ANI_PATH_PREFIX TEX_PATH_PREFIX
#define ANI_EXTENSION ".ani"
#endif

View file

@ -17,7 +17,7 @@ typedef struct Music {
char* music_path(const char *name);
bool check_music_path(const char *path);
void* load_music(const char *path);
void* load_music(const char *path, unsigned int flags);
void unload_music(void *snd);
#define BGM_PATH_PREFIX "bgm/"

View file

@ -22,11 +22,11 @@ bool check_music_path(const char *path) {
return strstartswith(path, BGM_PATH_PREFIX) && audio_mixer_check_sound_path(path, true);
}
void* load_music(const char *path) {
void* load_music(const char *path, unsigned int flags) {
Mix_Music *music = Mix_LoadMUS(path);
if(!music) {
warnx("load_music(): Mix_LoadMUS() failed: %s", Mix_GetError());
log_warn("Mix_LoadMUS() failed: %s", Mix_GetError());
return NULL;
}

View file

@ -4,5 +4,5 @@
char* music_path(const char *name) { return NULL; }
bool check_music_path(const char *path) { return NULL; }
void* load_music(const char *path) { return NULL; }
void* load_music(const char *path, unsigned int flags) { return NULL; }
void unload_music(void *vmus) { }

View file

@ -8,8 +8,6 @@
#include "font.h"
#include "global.h"
#include "paths/native.h"
#include <assert.h>
#include "taisei_err.h"
struct Fonts _fonts;
@ -18,9 +16,9 @@ TTF_Font *load_font(char *name, int size) {
TTF_Font *f = TTF_OpenFont(buf, size);
if(!f)
errx(-1, "failed to load font '%s'", buf);
log_fatal("Failed to load font '%s'", buf);
printf("-- loaded '%s'\n", buf);
log_info("Loaded '%s'", buf);
free(buf);
return f;
@ -68,7 +66,7 @@ void draw_text(Alignment align, float x, float y, const char *text, TTF_Font *fo
x -= tex->w/2;
break;
}
// if textures are odd pixeled, align them for ideal sharpness.
if(tex->w&1)
x += 0.5;

View file

@ -8,15 +8,10 @@
#include "model.h"
#include "list.h"
#include "resource.h"
#include "taisei_err.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void bad_reference_error(const char *filename, const char *aux, int n) {
warnx("load_model():\n!- OBJ file '%s': Index %d: bad %s index reference\n", filename, n, aux);
}
static void parse_obj(const char *filename, ObjFileData *data);
static void free_obj(ObjFileData *data);
@ -28,7 +23,7 @@ bool check_model_path(const char *path) {
return strendswith(path, MDL_EXTENSION);
}
void* load_model(const char *path) {
void* load_model(const char *path, unsigned int flags) {
Model *m = malloc(sizeof(Model));
ObjFileData data;
@ -45,7 +40,7 @@ void* load_model(const char *path) {
verts = calloc(data.icount, sizeof(Vertex));
#define BADREF(...) { bad_reference_error(__VA_ARGS__); free(verts); free_obj(&data); return NULL; }
#define BADREF(filename,aux,n) { log_warn("OBJ file '%s': Index %d: bad %s index reference\n", filename, n, aux); free(verts); free_obj(&data); return NULL; }
memset(verts, 0, data.icount*sizeof(Vertex));
for(i = 0; i < data.icount; i++) {
@ -100,7 +95,12 @@ static void free_obj(ObjFileData *data) {
}
static void parse_obj(const char *filename, ObjFileData *data) {
FILE *fp = fopen(filename, "rb");
SDL_RWops *rw = SDL_RWFromFile(filename, "r");
if(!rw) {
log_warn("SDL_RWFromFile() failed: %s", SDL_GetError());
return;
}
char line[256];
Vector buf;
@ -109,7 +109,7 @@ static void parse_obj(const char *filename, ObjFileData *data) {
memset(data, 0, sizeof(ObjFileData));
while(fgets(line, sizeof(line), fp)) {
while(SDL_RWgets(rw, line, sizeof(line))) {
linen++;
char *first;
@ -175,7 +175,7 @@ static void parse_obj(const char *filename, ObjFileData *data) {
}
if(jj == 0 || jj > 3 || segment[0] == '/')
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: Corrupt face definition\n", filename,linen);
log_fatal("OBJ file '%s:%d': Parsing error: Corrupt face definition", filename,linen);
data->indices = realloc(data->indices, sizeof(IVector)*(++data->icount));
memcpy(data->indices[data->icount-1], ibuf, sizeof(IVector));
@ -185,18 +185,18 @@ static void parse_obj(const char *filename, ObjFileData *data) {
data->fverts = j;
if(data->fverts != j)
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: face vertex count must stay the same in the whole file\n", filename, linen);
log_fatal("OBJ file '%s:%d': Parsing error: face vertex count must stay the same in the whole file", filename, linen);
if(data->fverts != 3 && data->fverts != 4)
errx(-1, "parse_obj():\n!- OBJ file '%s:%d': Parsing error: face vertex count must be either 3 or 4\n", filename, linen);
log_fatal("OBJ file '%s:%d': Parsing error: face vertex count must be either 3 or 4", filename, linen);
}
}
fclose(fp);
SDL_RWclose(rw);
}
Model* get_model(const char *name) {
return get_resource(RES_MODEL, name, RESF_REQUIRED)->model;
return get_resource(RES_MODEL, name, RESF_DEFAULT)->model;
}
void draw_model_p(Model *model) {

View file

@ -37,7 +37,7 @@ typedef struct Model {
char* model_path(const char *name);
bool check_model_path(const char *path);
void* load_model(const char *path);
void* load_model(const char *path, unsigned int flags);
void unload_model(void*); // Does not delete elements from the VBO, so doing this at runtime is leaking VBO space
Model* get_model(const char *name);

View file

@ -5,14 +5,13 @@
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
*/
#include <dirent.h>
#include "resource.h"
#include <sys/types.h>
#include <sys/stat.h>
#include "paths/native.h"
#include "config.h"
#include "taisei_err.h"
#include "video.h"
#include "menu/mainmenu.h"
Resources resources;
@ -65,18 +64,25 @@ Resource* insert_resource(ResourceType type, const char *name, void *data, Resou
Resource *oldres = hashtable_get_string(handler->mapping, name);
Resource *res = malloc(sizeof(Resource));
if(type == RES_MODEL) {
// FIXME: models can't be safely unloaded at runtime
flags |= RESF_PERMANENT;
}
res->type = handler->type;
res->flags = flags;
res->data = data;
if(oldres) {
warnx("insert_resource(): replacing a previously loaded %s '%s'", resource_type_names[type], name);
log_warn("Replacing a previously loaded %s '%s'", resource_type_names[type], name);
unload_resource(oldres);
}
hashtable_set_string(handler->mapping, name, res);
printf("Loaded %s '%s' from '%s'\n", resource_type_names[handler->type], name, source);
log_info("Loaded %s '%s' from '%s' (%s)", resource_type_names[handler->type], name, source,
(flags & RESF_PERMANENT) ? "permanent" : "transient");
return res;
}
@ -102,10 +108,10 @@ static Resource* load_resource(ResourceHandler *handler, const char *path, const
path = allocated_path = handler->find(name);
if(!path) {
if(flags & RESF_REQUIRED) {
errx(-1, "load_resource(): required %s '%s' couldn't be located", typename, name);
if(!(flags & RESF_OPTIONAL)) {
log_fatal("Required %s '%s' couldn't be located", typename, name);
} else {
warnx("load_resource(): failed to locate %s '%s'", typename, name);
log_warn("Failed to locate %s '%s'", typename, name);
}
return NULL;
@ -120,22 +126,22 @@ static Resource* load_resource(ResourceHandler *handler, const char *path, const
res = hashtable_get_string(handler->mapping, name);
if(res) {
warnx("load_resource(): %s '%s' is already loaded", typename, name);
log_warn("%s '%s' is already loaded", typename, name);
free(allocated_name);
return res;
}
}
raw = handler->load(path);
raw = handler->load(path, flags);
if(!raw) {
name = name ? name : "<name unknown>";
path = path ? path : "<path unknown>";
if(flags & RESF_REQUIRED) {
errx(-1, "load_resource(): required %s '%s' couldn't be loaded (%s)", typename, name, path);
if(!(flags & RESF_OPTIONAL)) {
log_fatal("Required %s '%s' couldn't be loaded (%s)", typename, name, path);
} else {
warnx("load_resource(): failed to load %s '%s' (%s)", typename, name, path);
log_warn("Failed to load %s '%s' (%s)", typename, name, path);
}
free(allocated_path);
@ -156,13 +162,43 @@ Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags)
ResourceHandler *handler = get_handler(type);
Resource *res = hashtable_get_string(handler->mapping, name);
if(!res) {
if(!res || flags & RESF_OVERRIDE) {
if(!(flags & (RESF_PRELOAD | RESF_OVERRIDE))) {
log_warn("%s '%s' was not preloaded", resource_type_names[type], name);
if(!(flags & RESF_OPTIONAL) && getenvint("TAISEI_PRELOAD_REQUIRED")) {
log_fatal("Aborting due to TAISEI_PRELOAD_REQUIRED");
}
}
res = load_resource(handler, NULL, name, flags);
}
if(res && flags & RESF_PERMANENT && !(res->flags & RESF_PERMANENT)) {
log_debug("Promoted %s '%s' to permanent", resource_type_names[type], name);
res->flags |= RESF_PERMANENT;
}
return res;
}
void preload_resource(ResourceType type, const char *name, ResourceFlags flags) {
if(!getenvint("TAISEI_NOPRELOAD")) {
get_resource(type, name, flags | RESF_PRELOAD);
}
}
void preload_resources(ResourceType type, ResourceFlags flags, const char *firstname, ...) {
va_list args;
va_start(args, firstname);
for(const char *name = firstname; name; name = va_arg(args, const char*)) {
preload_resource(type, name, flags);
}
va_end(args);
}
void init_resources(void) {
// hashtable sizes were carefully pulled out of my ass to reduce collisions a bit
@ -171,7 +207,7 @@ void init_resources(void) {
);
register_handler(
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, animation_name, animation_path, check_animation_path, 23
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, NULL, animation_path, check_animation_path, 23
);
register_handler(
@ -216,83 +252,21 @@ const char* resource_util_filename(const char *path) {
return path;
}
static void recurse_dir(const char *path) {
DIR *dir = opendir(path);
if(dir == NULL)
errx(-1, "Can't open directory '%s'", path);
struct dirent *dp;
while((dp = readdir(dir)) != NULL) {
char *filepath = strjoin(path, "/", dp->d_name, NULL);
struct stat statbuf;
stat(filepath, &statbuf);
if(S_ISDIR(statbuf.st_mode) && *dp->d_name != '.') {
recurse_dir(filepath);
} else for(int rtype = 0; rtype < RES_NUMTYPES; ++rtype) {
ResourceHandler *handler = get_handler(rtype);
if(handler->check(filepath)) {
load_resource(handler, filepath, NULL, 0);
}
}
free(filepath);
}
closedir(dir);
}
static void recurse_dir_rel(const char *relpath) {
char *path = strdup(relpath);
strip_trailing_slashes(path);
recurse_dir(path);
free(path);
}
static void scan_resources(void) {
ListContainer *visited = NULL;
for(ResourceType type = 0; type < RES_NUMTYPES; ++type) {
ResourceHandler *handler = get_handler(type);
ListContainer *c;
bool skip = false;
for(c = visited; c; c = c->next) {
if(!strcmp((char*)c->data, handler->subdir)) {
skip = true;
break;
}
}
if(!skip) {
recurse_dir_rel(handler->subdir);
create_container(&visited)->data = handler->subdir;
}
}
delete_all_elements((void**)&visited, delete_element);
}
void load_resources(void) {
if(!getenvint("TAISEI_NOSCAN")) {
scan_resources();
}
init_fonts();
if(glext.draw_instanced) {
load_shader_snippets("shader/laser_snippets", "laser_");
load_shader_snippets("shader/laser_snippets", "laser_", RESF_PERMANENT);
}
menu_preload();
init_fbo(&resources.fbg[0]);
init_fbo(&resources.fbg[1]);
init_fbo(&resources.fsec);
}
void free_resources(void) {
void free_resources(bool all) {
for(ResourceType type = 0; type < RES_NUMTYPES; ++type) {
ResourceHandler *handler = get_handler(type);
@ -303,11 +277,29 @@ void free_resources(void) {
Resource *res;
for(HashtableIterator *i = hashtable_iter(handler->mapping); hashtable_iter_next(i, (void**)&name, (void**)&res);) {
if(!all && res->flags & RESF_PERMANENT)
continue;
ResourceFlags flags = res->flags;
unload_resource(res);
printf("Unloaded %s '%s'\n", resource_type_names[type], name);
log_info("Unloaded %s '%s' (%s)", resource_type_names[type], name,
(flags & RESF_PERMANENT) ? "permanent" : "transient"
);
if(!all) {
hashtable_unset_deferred(handler->mapping, name);
}
}
hashtable_free(handler->mapping);
if(all) {
hashtable_free(handler->mapping);
} else {
hashtable_unset_deferred_now(handler->mapping);
}
}
if(!all) {
return;
}
delete_vbo(&_vbo);

View file

@ -18,7 +18,6 @@
#include "font.h"
#include "model.h"
#include "hashtable.h"
#include "assert.h"
#include "paths/native.h"
typedef enum ResourceType {
@ -32,11 +31,14 @@ typedef enum ResourceType {
} ResourceType;
typedef enum ResourceFlags {
RESF_REQUIRED = 1,
RESF_OVERRIDE = 2,
// RESF_PERMANENT = 4;
RESF_OVERRIDE = 1,
RESF_OPTIONAL = 2,
RESF_PERMANENT = 4,
RESF_PRELOAD = 8,
} ResourceFlags;
#define RESF_DEFAULT 0
// All paths are relative to the current working directory, which can assumed to be the resources directory,
// unless mentioned otherwise.
@ -56,7 +58,7 @@ typedef bool (*ResourceCheckFunc)(const char *path);
// Loads a resource at path and returns a pointer to it.
// Must return NULL and not crash the program on failure.
typedef void* (*ResourceLoadFunc)(const char *path);
typedef void* (*ResourceLoadFunc)(const char *path, unsigned int flags);
// Unloads a resource, freeing all allocated to it memory.
typedef void (*ResourceUnloadFunc)(void *res);
@ -97,10 +99,12 @@ extern Resources resources;
void init_resources(void);
void load_resources(void);
void free_resources(void);
void free_resources(bool all);
Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags);
Resource* insert_resource(ResourceType type, const char *name, void *data, ResourceFlags flags, const char *source);
void preload_resource(ResourceType type, const char *name, ResourceFlags flags);
void preload_resources(ResourceType type, ResourceFlags flags, const char *firstname, ...) __attribute__((sentinel));
void resource_util_strip_ext(char *path);
char* resource_util_basename(const char *prefix, const char *path);

View file

@ -17,7 +17,7 @@ typedef struct Sound {
char* sound_path(const char *name);
bool check_sound_path(const char *path);
void* load_sound(const char *path);
void* load_sound(const char *path, unsigned int flags);
void unload_sound(void *snd);
#define SFX_PATH_PREFIX "sfx/"

View file

@ -22,11 +22,11 @@ bool check_sound_path(const char *path) {
return strstartswith(path, SFX_PATH_PREFIX) && audio_mixer_check_sound_path(path, false);
}
void* load_sound(const char *path) {
void* load_sound(const char *path, unsigned int flags) {
Mix_Chunk *sound = Mix_LoadWAV(path);
if(!sound) {
warnx("load_sound(): Mix_LoadWAV() failed: %s", Mix_GetError());
log_warn("Mix_LoadWAV() failed: %s", Mix_GetError());
return NULL;
}

View file

@ -4,5 +4,5 @@
char* sound_path(const char *name) { return NULL; }
bool check_sound_path(const char *path) { return NULL; }
void* load_sound(const char *path) { return NULL; }
void* load_sound(const char *path, unsigned int flags) { return NULL; }
void unload_sound(void *vmus) { }

View file

@ -12,7 +12,6 @@
#include "resource.h"
#include "config.h"
#include "list.h"
#include "taisei_err.h"
static char snippet_header_EXT_draw_instanced[] =
"#version 120\n"
@ -39,7 +38,7 @@ bool check_shader_path(const char *path) {
static Shader* load_shader(const char *vheader, const char *fheader, const char *vtext, const char *ftext);
void* load_shader_file(const char *path) {
void* load_shader_file(const char *path, unsigned int flags) {
char *text, *vtext, *ftext, *delim;
text = read_all(path, NULL);
@ -48,7 +47,7 @@ void* load_shader_file(const char *path) {
delim = strstr(text, SHA_DELIM);
if(delim == NULL) {
warnx("load_shader_file(): expected '%s' delimiter.", SHA_DELIM);
log_warn("Expected '%s' delimiter.", SHA_DELIM);
free(text);
return NULL;
}
@ -81,14 +80,14 @@ static char* get_snippet_header(void) {
}
}
void load_shader_snippets(const char *filename, const char *prefix) {
void load_shader_snippets(const char *filename, const char *prefix, unsigned int flags) {
int size, vhsize = 0, vfsize = 0, fhsize = 0, ffsize = 0, ssize, prefixlen;
char *text, *vhead, *vfoot, *fhead, *ffoot;
char *sec, *name, *nend, *send;
char *vtext = NULL, *ftext = NULL;
char *nbuf;
printf("-- loading snippet file '%s'\n", filename);
log_info("Loading snippet file '%s' with prefix '%s'", filename, prefix);
prefixlen = strlen(prefix);
@ -103,9 +102,9 @@ void load_shader_snippets(const char *filename, const char *prefix) {
ffoot = copy_segment(text, "%%FSHADER-FOOT%%", &ffsize);
if(!vhead || !fhead)
errx(-1, "Syntax Error: missing HEAD section(s).");
log_fatal("Syntax Error: missing HEAD section(s)");
if((vfoot == NULL) + (ffoot == NULL) != 1)
errx(-1, "Syntax Error: must contain exactly 1 FOOT section");
log_fatal("Syntax Error: must contain exactly 1 FOOT section");
while((sec = strstr(sec, "%%"))) {
sec += 2;
@ -113,7 +112,7 @@ void load_shader_snippets(const char *filename, const char *prefix) {
name = sec;
nend = strstr(name, "%%");
if(!nend)
errx(-1, "Syntax Error: expected '%%'");
log_fatal("Syntax Error: expected '%%'");
sec = nend + 2;
@ -160,7 +159,7 @@ void load_shader_snippets(const char *filename, const char *prefix) {
nbuf[nend-name+prefixlen] = 0;
Shader *sha = load_shader(get_snippet_header(), NULL, vtext, ftext);
insert_resource(RES_SHADER, nbuf, sha, 0, filename);
insert_resource(RES_SHADER, nbuf, sha, flags, filename);
free(nbuf);
free(vtext);
@ -179,12 +178,12 @@ static void print_info_log(GLuint shader, tsglGetShaderiv_ptr lenfunc, tsglGetSh
lenfunc(shader, GL_INFO_LOG_LENGTH, &len);
if(len > 1) {
printf(" == GLSL %s info log (%u) ==\n", type, shader);
char log[len];
memset(log, 0, len);
logfunc(shader, len, &alen, log);
printf("%s\n", log);
printf("\n == End of GLSL %s info log (%u) ==\n", type, shader);
log_warn("\n == GLSL %s info log (%u) ==\n%s\n == End of GLSL %s info log (%u) ==",
type, shader, log, type, shader);
}
}
@ -265,5 +264,5 @@ int uniloc(Shader *sha, const char *name) {
}
Shader* get_shader(const char *name) {
return get_resource(RES_SHADER, name, RESF_REQUIRED)->shader;
return get_resource(RES_SHADER, name, RESF_DEFAULT)->shader;
}

View file

@ -19,10 +19,10 @@ typedef struct Shader {
char* shader_path(const char *name);
bool check_shader_path(const char *path);
void* load_shader_file(const char *path);
void* load_shader_file(const char *path, unsigned int flags);
void unload_shader(void *vsha);
void load_shader_snippets(const char *filename, const char *prefix);
void load_shader_snippets(const char *filename, const char *prefix, unsigned int flags);
Shader* get_shader(const char *name);
int uniloc(Shader *sha, const char *name);

View file

@ -6,13 +6,11 @@
*/
#include <png.h>
#include <assert.h>
#include "texture.h"
#include "resource.h"
#include "global.h"
#include "paths/native.h"
#include "taisei_err.h"
#include "vbo.h"
static SDL_Surface* load_png(const char *filename);
@ -25,7 +23,7 @@ bool check_texture_path(const char *path) {
return strendswith(path, TEX_EXTENSION);
}
void* load_texture(const char *path) {
void* load_texture(const char *path, unsigned int flags) {
SDL_Surface *surface = load_png(path);
if(surface == NULL) {
@ -42,7 +40,7 @@ void* load_texture(const char *path) {
}
Texture* get_tex(const char *name) {
return get_resource(RES_TEXTURE, name, RESF_REQUIRED)->texture;
return get_resource(RES_TEXTURE, name, RESF_DEFAULT)->texture;
}
Texture* prefix_get_tex(const char *name, const char *prefix) {
@ -52,48 +50,61 @@ Texture* prefix_get_tex(const char *name, const char *prefix) {
return tex;
}
static SDL_Surface* load_png(const char *filename) {
#define PNGFAIL(msg) { warnx("load_png(): couldn't load '%s': %s", filename, msg); return NULL; }
FILE *fp = fopen(filename, "rb");
if(!fp) {
PNGFAIL("fopen() failed")
static SDL_Surface* load_png_p(const char *filename, SDL_RWops *rwops) {
#define PNGFAIL(msg) { log_warn("Couldn't load '%s': %s", filename, msg); return NULL; }
if(!rwops) {
PNGFAIL(SDL_GetError())
}
png_structp png_ptr;
if(!(png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) {
fclose(fp);
PNGFAIL("png_create_read_struct() failed")
}
png_setup_error_handlers(png_ptr);
png_infop info_ptr;
if(!(info_ptr = png_create_info_struct(png_ptr))) {
fclose(fp);
png_destroy_read_struct(&png_ptr, NULL, NULL);
PNGFAIL("png_create_info_struct() failed")
}
png_infop end_info;
if(!(end_info = png_create_info_struct(png_ptr))) {
fclose(fp);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
PNGFAIL("png_create_info_struct() failed")
}
png_init_io(png_ptr, fp);
png_read_png(png_ptr, info_ptr, 0, NULL);
png_init_rwops_read(png_ptr, rwops);
png_read_info(png_ptr, info_ptr);
int colortype = png_get_color_type(png_ptr,info_ptr);
if(colortype == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png_ptr);
if (colortype == PNG_COLOR_TYPE_GRAY ||
colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png_ptr);
if(!(colortype & PNG_COLOR_MASK_ALPHA))
png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
png_read_update_info(png_ptr, info_ptr);
int width = png_get_image_width(png_ptr, info_ptr);
int height = png_get_image_height(png_ptr, info_ptr);
int depth = png_get_bit_depth(png_ptr, info_ptr);
png_bytep *row_pointers = png_get_rows(png_ptr, info_ptr);
png_bytep row_pointers[height];
Uint32 *pixels = malloc(sizeof(Uint32)*width*height);
for(int i = 0; i < height; i++)
memcpy(&pixels[i*width], row_pointers[i], sizeof(Uint32)*width);
row_pointers[i] = (png_bytep)(pixels+i*width);
png_read_image(png_ptr, row_pointers);
png_read_end(png_ptr, end_info);
Uint32 rmask, gmask, bmask, amask;
@ -112,17 +123,22 @@ static SDL_Surface* load_png(const char *filename) {
SDL_Surface *res = SDL_CreateRGBSurfaceFrom(pixels, width, height, depth*4, 0, rmask, gmask, bmask, amask);
if(!res) {
fclose(fp);
PNGFAIL(SDL_GetError())
}
fclose(fp);
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return res;
#undef PNGFAIL
}
static SDL_Surface* load_png(const char *filename) {
SDL_RWops *rwops = SDL_RWFromFile(filename, "r");
SDL_Surface *surf = load_png_p(filename, rwops);
SDL_RWclose(rwops);
return surf;
}
void load_sdl_surf(SDL_Surface *surface, Texture *texture) {
glGenTextures(1, &texture->gltex);
glBindTexture(GL_TEXTURE_2D, texture->gltex);

View file

@ -21,7 +21,7 @@ struct Texture {
};
char* texture_path(const char *name);
void* load_texture(const char *path);
void* load_texture(const char *path, unsigned int flags);
bool check_texture_path(const char *path);
void load_sdl_surf(SDL_Surface *surface, Texture *texture);

View file

@ -1,8 +1,7 @@
#include <assert.h>
#include <stdbool.h>
#include "rwops_segment.h"
#include "taisei_err.h"
#include "util.h"
typedef struct Segment {
SDL_RWops *wrapped;
@ -104,7 +103,7 @@ static size_t segment_readwrite(SDL_RWops *rw, void *ptr, size_t size, size_t ma
size_t onum;
if(pos < 0) {
warnx("segment_readwrite: SDL_RWtell failed (%i): %s", (int)pos, SDL_GetError());
log_debug("SDL_RWtell failed (%i): %s", (int)pos, SDL_GetError());
SDL_SetError("segment_readwrite: SDL_RWtell failed (%i) %s", (int)pos, SDL_GetError());
// this could be a non-seekable stream, like /dev/stdin...
@ -114,7 +113,7 @@ static size_t segment_readwrite(SDL_RWops *rw, void *ptr, size_t size, size_t ma
}
if(pos < s->start || pos > s->end) {
warnx("segment_readwrite: segment range violation");
log_warn("Segment range violation");
SDL_SetError("segment_readwrite: segment range violation");
return 0;
}

View file

@ -2,8 +2,8 @@
#include <SDL.h>
#include <stdint.h>
#include <zlib.h>
#include <assert.h>
#include "rwops_zlib.h"
#include "util.h"
#define MIN_CHUNK_SIZE 8
@ -18,7 +18,7 @@
#endif
#ifdef DEBUG_ZRWOPS
#define PRINT(...) printf(__VA_ARGS__)
#define PRINT(...) tsfprintf(stdout, __VA_ARGS__)
#else
#define PRINT(...)
#endif
@ -130,11 +130,11 @@ static SDL_RWops* common_alloc(SDL_RWops *wrapped, size_t bufsize, bool autoclos
#ifdef DEBUG_ZRWOPS
static void printbuf(void *buf, size_t size) {
printf("[ ");
tsfprintf(stdout, "[ ");
for(unsigned int i = 0; i < size; ++i) {
printf("%02x ", ((uint8_t*)buf)[i]);
tsfprintf(stdout, "%02x ", ((uint8_t*)buf)[i]);
}
printf("]\n");
tsfprintf(stdout, "]\n");
}
#else
#define printbuf(buf,size)
@ -336,7 +336,7 @@ int zrwops_test(void) {
printbuf(buffer1, sizeof(buffer1));
printbuf(buffer2, sizeof(buffer2));
printf("%lu %s\n", x, buffer2);
log_info("%lu %s\n", x, buffer2);
assert(!memcmp(data, buffer2, sizeof(data)));
return 1;

View file

@ -5,8 +5,6 @@
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
*/
#include <assert.h>
#include "util.h"
#include "stage.h"
@ -19,8 +17,8 @@
#include "player.h"
#include "menu/ingamemenu.h"
#include "menu/gameovermenu.h"
#include "taisei_err.h"
#include "audio.h"
#include "log.h"
static size_t numstages = 0;
StageInfo *stages = NULL;
@ -43,7 +41,7 @@ static void add_stage(uint16_t id, StageProcs *procs, StageType type, const char
#ifdef DEBUG
if(title && subtitle) {
fprintf(stderr, "Added stage 0x%04x: %s: %s\n", id, title, subtitle);
log_debug("Added stage 0x%04x: %s: %s", id, title, subtitle);
}
#endif
}
@ -111,12 +109,12 @@ void stage_init_array(void) {
#ifdef DEBUG
for(int i = 0; stages[i].procs; ++i) {
if(stages[i].type == STAGE_SPELL && !(stages[i].id & STAGE_SPELL_BIT)) {
errx(-1, "Spell stage has an ID without the spell bit set: 0x%04x", stages[i].id);
log_fatal("Spell stage has an ID without the spell bit set: 0x%04x", stages[i].id);
}
for(int j = 0; stages[j].procs; ++j) {
if(i != j && stages[i].id == stages[j].id) {
errx(-1, "Duplicate ID 0x%04x in stages array, indices: %i, %i", stages[i].id, i, j);
log_fatal("Duplicate ID 0x%04x in stages array, indices: %i, %i", stages[i].id, i, j);
}
}
}
@ -177,9 +175,8 @@ StageProgress* stage_get_progress_from_info(StageInfo *stage, Difficulty diff, b
size_t allocsize = sizeof(StageProgress) * (fixed_diff ? 1 : NUM_SELECTABLE_DIFFICULTIES);
stage->progress = malloc(allocsize);
memset(stage->progress, 0, allocsize);
#ifdef DEBUG
printf("stage_get_progress_from_info(): allocated %lu bytes for stage %u (%s: %s)\n", (unsigned long int)allocsize, stage->id, stage->title, stage->subtitle);
#endif
log_debug("Allocated %lu bytes for stage %u (%s: %s)", (unsigned long int)allocsize, stage->id, stage->title, stage->subtitle);
}
return stage->progress + (fixed_diff ? 0 : diff - D_Easy);
@ -450,7 +447,7 @@ static void stage_draw(StageInfo *stage) {
if(config_get_int(CONFIG_NO_STAGEBG) == 2 && global.fps.stagebg_fps < config_get_int(CONFIG_NO_STAGEBG_FPSLIMIT)
&& !global.nostagebg) {
printf("stage_draw(): !- Stage background has been switched off due to low frame rate. You can change that in the options.\n");
log_warn("Stage background has been switched off due to low frame rate. You can change that in the options.");
global.nostagebg = true;
}
@ -691,9 +688,34 @@ void stage_finish(int gameover) {
set_transition_callback(TransFadeBlack, FADE_TIME, FADE_TIME*2, stage_finalize, (void*)(intptr_t)gameover);
}
static void stage_preload(void) {
difficulty_preload();
projectiles_preload();
player_preload();
items_preload();
boss_preload();
if(global.stage->type != STAGE_SPELL)
enemies_preload();
global.stage->procs->preload();
preload_resources(RES_TEXTURE, RESF_PERMANENT,
"hud",
"star",
"titletransition",
NULL);
preload_resources(RES_SHADER, RESF_PERMANENT,
"stagetitle",
"ingame_menu",
NULL);
}
void stage_loop(StageInfo *stage) {
assert(stage);
assert(stage->procs);
assert(stage->procs->preload);
assert(stage->procs->begin);
assert(stage->procs->end);
assert(stage->procs->draw);
@ -709,6 +731,8 @@ void stage_loop(StageInfo *stage) {
// I really want to separate all of the game state from the global struct sometime
global.stage = stage;
stage_preload();
uint32_t seed = (uint32_t)time(0);
tsrand_switch(&global.rand_game);
tsrand_seed_p(&global.rand_game, seed);
@ -725,18 +749,18 @@ void stage_loop(StageInfo *stage) {
global.replay_stage = NULL;
}
printf("Random seed: %u\n", seed);
log_debug("Random seed: %u", seed);
} else {
if(!global.replay_stage) {
errx(-1, "Attemped to replay a NULL stage");
log_fatal("Attemped to replay a NULL stage");
return;
}
ReplayStage *stg = global.replay_stage;
printf("REPLAY_PLAY mode: %d events, stage: \"%s\"\n", stg->numevents, stage_get(stg->stage)->title);
log_debug("REPLAY_PLAY mode: %d events, stage: \"%s\"", stg->numevents, stage_get(stg->stage)->title);
tsrand_seed_p(&global.rand_game, stg->seed);
printf("Random seed: %u\n", stg->seed);
log_debug("Random seed: %u", stg->seed);
global.diff = stg->diff;
init_player(&global.plr);

Some files were not shown because too many files have changed in this diff Show more