moved util functions from global to where they make a bit more sense

This commit is contained in:
Andrei "Akari" Alexeyev 2017-03-06 02:25:59 +02:00
parent 0ebf29660f
commit dacbf96427
18 changed files with 455 additions and 445 deletions

View file

@ -21,6 +21,7 @@ endif()
set(SRCs
main.c
util.c
taiseigl.c
random.c
config.c

View file

@ -8,7 +8,7 @@
#ifndef BOSS_H
#define BOSS_H
#include "tscomplex.h"
#include "util.h"
#include "difficulty.h"
#include "resource/animation.h"
#include "color.h"

View file

@ -7,15 +7,10 @@
#ifndef ENEMY_H
#define ENEMY_H
#include "tscomplex.h"
#include "util.h"
#include "projectile.h"
#undef complex
#define complex double _Complex
#include <stdbool.h>
#include <stdarg.h>
typedef struct Enemy Enemy;
typedef int (*EnemyLogicRule)(struct Enemy*, int t);
typedef void (*EnemyDrawRule)(struct Enemy*, int t);

View file

@ -48,7 +48,7 @@ void handle_events(EventHandler handler, EventFlags flags, void *arg) {
handler(E_CharErased, 0, arg);
} else if(!repeat) {
if(scan == config_get_int(CONFIG_KEY_SCREENSHOT)) {
take_screenshot();
video_take_screenshot();
break;
}
@ -137,3 +137,9 @@ void handle_events(EventHandler handler, EventFlags flags, void *arg) {
}
}
}
// Inputdevice-agnostic method of checking whether a game control is pressed.
// ALWAYS use this instead of SDL_GetKeyState if you need it.
bool gamekeypressed(KeyIndex key) {
return SDL_GetKeyboardState(NULL)[config_get_int(KEYIDX_TO_CFGIDX(key))] || gamepad_gamekeypressed(key);
}

View file

@ -9,6 +9,8 @@
#ifndef EVENTS_H
#define EVENTS_H
#include "config.h"
typedef enum {
EF_Keyboard = 1,
EF_Text = 2,
@ -52,5 +54,6 @@ typedef enum {
typedef void(*EventHandler)(EventType, int, void*);
void handle_events(EventHandler handler, EventFlags flags, void *arg);
bool gamekeypressed(KeyIndex key);
#endif

View file

@ -17,16 +17,6 @@
Global global;
int getenvint(const char *v) {
char *e = getenv(v);
if(e) {
return atoi(e);
}
return 0;
}
void init_global(void) {
memset(&global, 0, sizeof(global));
@ -48,322 +38,3 @@ void init_global(void) {
warnx("FPS limiter disabled by environment. Gotta go fast! (frameskip = %i)", global.frameskip);
}
}
void print_state_checksum(void) {
int plr, spos = 0, smisc = 0, sargs = 0, proj = 0;
Player *p = &global.plr;
Enemy *s;
Projectile *pr;
plr = creal(p->pos)+cimag(p->pos)+p->focus+p->fire+p->power+p->lifes+p->bombs+p->recovery+p->deathtime+p->continues+p->moveflags;
for(s = global.plr.slaves; s; s = s->next) {
spos += creal(s->pos + s->pos0) + cimag(s->pos + s->pos0);
smisc += s->birthtime + s->hp + s->unbombable + s->alpha;
sargs += cabs(s->args[0]) + cabs(s->args[1]) + cabs(s->args[2]) + cabs(s->args[3]) + s->alpha;
}
for(pr = global.projs; pr; pr = pr->next)
proj += cabs(pr->pos + pr->pos0) + pr->birthtime + pr->angle + pr->type + cabs(pr->args[0]) + cabs(pr->args[1]) + cabs(pr->args[2]) + cabs(pr->args[3]);
printf("[%05d] %d\t(%d\t%d\t%d)\t%d\n", global.frames, plr, spos, smisc, sargs, proj);
}
void frame_rate(int *lasttime) {
if(global.frameskip) {
return;
}
int t = *lasttime + 1000.0/FPS - SDL_GetTicks();
if(t > 0)
SDL_Delay(t);
*lasttime = SDL_GetTicks();
}
double approach(double v, double t, double d) {
if(v < t) {
v += d;
if(v > t)
return t;
} else if(v > t) {
v -= d;
if(v < t)
return t;
}
return v;
}
void calc_fps(FPSCounter *fps) {
if(!fps->stagebg_fps)
fps->stagebg_fps = FPS;
if(SDL_GetTicks() > fps->fpstime+1000) {
fps->show_fps = fps->fps;
fps->fps = 0;
fps->fpstime = SDL_GetTicks();
} else {
fps->fps++;
}
fps->stagebg_fps = approach(fps->stagebg_fps, fps->show_fps, 0.1);
}
void set_ortho(void) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, SCREEN_W, SCREEN_H, 0, -100, 100);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
}
void colorfill(float r, float g, float b, float a) {
if(a <= 0) return;
glColor4f(r,g,b,a);
glPushMatrix();
glScalef(SCREEN_W,SCREEN_H,1);
glTranslatef(0.5,0.5,0);
draw_quad();
glPopMatrix();
glColor4f(1,1,1,1);
}
void fade_out(float f) {
colorfill(0, 0, 0, f);
}
double psin(double x) {
return 0.5 + 0.5 * sin(x);
}
double max(double a, double b) {
return (a > b)? a : b;
}
double min(double a, double b) {
return (a < b)? a : b;
}
double clamp(double f, double lower, double upper) {
if(f < lower)
return lower;
if(f > upper)
return upper;
return f;
}
void take_screenshot(void)
{
FILE *out;
char *data;
char outfile[128], *outpath;
time_t rawtime;
struct tm * timeinfo;
int w, h, rw, rh;
w = video.current.width;
h = video.current.height;
rw = video.real.width;
rh = video.real.height;
data = malloc(3 * rw * rh);
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(outfile, 128, "/taisei_%Y%m%d_%H-%M-%S_%Z.png", timeinfo);
outpath = strjoin(get_screenshots_path(), outfile, NULL);
printf("Saving screenshot as %s\n", outpath);
out = fopen(outpath, "wb");
free(outpath);
if(!out) {
perror("fopen");
free(data);
return;
}
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, rw, rh, GL_RGB, GL_UNSIGNED_BYTE, data);
png_structp png_ptr;
png_infop info_ptr;
png_byte **row_pointers;
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info_ptr = png_create_info_struct (png_ptr);
png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
row_pointers = png_malloc(png_ptr, h*sizeof(png_byte *));
for(int y = 0; y < h; y++) {
row_pointers[y] = png_malloc(png_ptr, 8*3*w);
memcpy(row_pointers[y], data + rw*3*(h-1-y), w*3);
}
png_init_io(png_ptr, out);
png_set_rows(png_ptr, info_ptr, row_pointers);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
for(int y = 0; y < h; y++)
png_free(png_ptr, row_pointers[y]);
png_free(png_ptr, row_pointers);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(data);
fclose(out);
}
bool strendswith(const char *s, const char *e) {
int ls = strlen(s);
int le = strlen(e);
if(le > ls)
return false;
int i; for(i = 0; i < le; ++i)
if(s[ls-i-1] != e[le-i-1])
return false;
return true;
}
bool strstartswith(const char *s, const char *p) {
int ls = strlen(s);
int lp = strlen(p);
if(ls < lp)
return false;
return !strncmp(s, p, lp);
}
bool strendswith_any(const char *s, const char **earray) {
for(const char **e = earray; *e; ++e) {
if(strendswith(s, *e)) {
return true;
}
}
return false;
}
void stralloc(char **dest, const char *src) {
free(*dest);
if(src) {
*dest = malloc(strlen(src)+1);
strcpy(*dest, src);
} else {
*dest = NULL;
}
}
char* strjoin(const char *first, ...) {
va_list args;
size_t size = strlen(first) + 1;
char *str = malloc(size);
strcpy(str, first);
va_start(args, first);
for(;;) {
char *next = va_arg(args, char*);
if(!next) {
break;
}
size += strlen(next);
str = realloc(str, size);
strcat(str, next);
}
va_end(args);
return str;
}
char* strfmt(const char *fmt, ...) {
size_t written = 0;
size_t fmtlen = strlen(fmt);
size_t asize = 1;
char *out = NULL;
while(asize * 2 <= fmtlen)
asize *= 2;
do {
asize *= 2;
out = realloc(out, asize);
va_list args;
va_start(args, fmt);
written = vsnprintf(out, asize, fmt, args);
va_end(args);
} while(written >= asize);
return realloc(out, strlen(out) + 1);
}
char* read_all(const char *filename, int *outsize) {
char *text;
size_t size;
FILE *file = fopen(filename, "r");
if(file == NULL)
errx(-1, "Error opening '%s'", filename);
fseek(file, 0, SEEK_END);
size = ftell(file);
fseek(file, 0, SEEK_SET);
text = malloc(size+1);
fread(text, size, 1, file);
text[size] = 0;
fclose(file);
if(outsize) {
*outsize = size;
}
return text;
}
char* copy_segment(const char *text, const char *delim, int *size) {
char *seg, *beg, *end;
beg = strstr(text, delim);
if(!beg)
return NULL;
beg += strlen(delim);
end = strstr(beg, "%%");
if(!end)
return NULL;
*size = end-beg;
seg = malloc(*size+1);
strlcpy(seg, beg, *size+1);
return seg;
}
// Inputdevice-agnostic method of checking whether a game control is pressed.
// ALWAYS use this instead of SDL_GetKeyState if you need it.
bool gamekeypressed(KeyIndex key) {
return SDL_GetKeyboardState(NULL)[config_get_int(KEYIDX_TO_CFGIDX(key))] || gamepad_gamekeypressed(key);
}

View file

@ -13,7 +13,7 @@
#include <stdbool.h>
#include <math.h>
#include "tscomplex.h"
#include "util.h"
#include "color.h"
#include "resource/sfx.h"
@ -43,7 +43,6 @@
#include "difficulty.h"
#include "color.h"
#include "audio.h"
#include "taisei_err.h"
#include "rwops/all.h"
@ -88,13 +87,6 @@ enum {
GAMEOVER_TRANSITIONING = -1,
};
typedef struct {
int fpstime; // frame counter
int fps;
int show_fps;
double stagebg_fps;
} FPSCounter;
typedef struct {
Difficulty diff;
Player plr;
@ -137,74 +129,6 @@ typedef struct {
extern Global global;
void print_state_checksum(void);
void init_global(void);
void frame_rate(int *lasttime);
void calc_fps(FPSCounter *fps);
void set_ortho(void);
void colorfill(float r, float g, float b, float a);
void fade_out(float f);
void take_screenshot(void);
// needed for mingw compatibility:
#undef min
#undef max
// NOTE: do NOT convert these to macros please.
// max(frand(), 0.5);
// min(huge_costly_expression, another_huge_costly_expression)
double min(double, double);
double max(double, double);
double clamp(double, double, double);
double approach(double v, double t, double d);
double psin(double);
bool strendswith(const char *s, const char *e);
bool strstartswith(const char *s, const char *p);
bool strendswith_any(const char *s, const char **earray);
void stralloc(char **dest, const char *src);
char* strjoin(const char *first, ...);
char* strfmt(const char *fmt, ...);
#undef strdup
#define strdup(s) strjoin(s, NULL)
bool gamekeypressed(KeyIndex key);
int getenvint(const char *v);
char* read_all(const char *filename, int *size);
char* copy_segment(const char *text, const char *delim, int *size);
#define SIGN(x) ((x > 0) - (x < 0))
// this is used by both player and replay code
enum {
EV_PRESS,
EV_RELEASE,
EV_OVER, // replay-only
EV_AXIS_LR,
EV_AXIS_UD,
EV_CHECK_DESYNC, // replay-only
};
#undef strlcat
#undef strlcpy
#define strlcat SDL_strlcat
#define strlcpy SDL_strlcpy
#undef strncat
#undef strncpy
#define strncat DO_NOT_USE_strncat_USE_strlcat
#define strncpy DO_NOT_USE_strncpy_USE_strlcpy
#endif
//
// These definitions are common but non-standard, so we provide our own
//
#undef M_PI
#undef M_PI_2
#define M_PI 3.14159265358979323846
#define M_PI_2 1.57079632679489661923

View file

@ -9,7 +9,7 @@
#ifndef ITEM_H
#define ITEM_H
#include "tscomplex.h"
#include "util.h"
typedef struct Item Item;

View file

@ -8,7 +8,7 @@
#ifndef LASER_H
#define LASER_H
#include "tscomplex.h"
#include "util.h"
#include "projectile.h"
#include "resource/shader.h"

View file

@ -8,9 +8,7 @@
#ifndef PLAYER_H
#define PLAYER_H
#include <stdbool.h>
#include "tscomplex.h"
#include "util.h"
#include "enemy.h"
#include "gamepad.h"
#include "resource/animation.h"
@ -74,6 +72,16 @@ typedef struct {
char iddqd;
} Player;
// this is used by both player and replay code
enum {
EV_PRESS,
EV_RELEASE,
EV_OVER, // replay-only
EV_AXIS_LR,
EV_AXIS_UD,
EV_CHECK_DESYNC, // replay-only
};
void init_player(Player*);
void prepare_player_for_next_stage(Player*);

View file

@ -8,7 +8,7 @@
#ifndef PROJECTILE
#define PROJECTILE
#include "tscomplex.h"
#include "util.h"
#include "resource/texture.h"
#include "color.h"

View file

@ -29,7 +29,7 @@ bool check_animation_path(const char *path) {
char* animation_name(const char *filename) {
char *name = resource_util_basename(ANI_PATH_PREFIX, filename);
char *c = name, *newname;
char *c = name, *newname = NULL;
while(c = strchr(c, '_')) {
newname = ++c;

View file

@ -7,8 +7,8 @@
#include <assert.h>
#include "util.h"
#include "stage.h"
#include "tscomplex.h"
#include <time.h>
#include "global.h"

View file

@ -1,22 +0,0 @@
/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (C) 2011, Lukas Weber <laochailan@web.de>
*/
#ifndef TSCOMPLEX_H
#define TSCOMPLEX_H
#include <complex.h>
// This is a workaround to properly specify the type of our "complex" variables...
// Taisei code always uses just "complex" when it actually means "complex double", which is not really correct...
// gcc doesn't seem to care, other compilers do (e.g. clang)
#ifdef complex
#undef complex
#define complex _Complex double
#endif
#endif

258
src/util.c Normal file
View file

@ -0,0 +1,258 @@
#include "util.h"
#include "global.h"
//
// string utils
//
bool strendswith(const char *s, const char *e) {
int ls = strlen(s);
int le = strlen(e);
if(le > ls)
return false;
int i; for(i = 0; i < le; ++i)
if(s[ls-i-1] != e[le-i-1])
return false;
return true;
}
bool strstartswith(const char *s, const char *p) {
int ls = strlen(s);
int lp = strlen(p);
if(ls < lp)
return false;
return !strncmp(s, p, lp);
}
bool strendswith_any(const char *s, const char **earray) {
for(const char **e = earray; *e; ++e) {
if(strendswith(s, *e)) {
return true;
}
}
return false;
}
void stralloc(char **dest, const char *src) {
free(*dest);
if(src) {
*dest = malloc(strlen(src)+1);
strcpy(*dest, src);
} else {
*dest = NULL;
}
}
char* strjoin(const char *first, ...) {
va_list args;
size_t size = strlen(first) + 1;
char *str = malloc(size);
strcpy(str, first);
va_start(args, first);
for(;;) {
char *next = va_arg(args, char*);
if(!next) {
break;
}
size += strlen(next);
str = realloc(str, size);
strcat(str, next);
}
va_end(args);
return str;
}
char* strfmt(const char *fmt, ...) {
size_t written = 0;
size_t fmtlen = strlen(fmt);
size_t asize = 1;
char *out = NULL;
while(asize * 2 <= fmtlen)
asize *= 2;
do {
asize *= 2;
out = realloc(out, asize);
va_list args;
va_start(args, fmt);
written = vsnprintf(out, asize, fmt, args);
va_end(args);
} while(written >= asize);
return realloc(out, strlen(out) + 1);
}
char* copy_segment(const char *text, const char *delim, int *size) {
char *seg, *beg, *end;
beg = strstr(text, delim);
if(!beg)
return NULL;
beg += strlen(delim);
end = strstr(beg, "%%");
if(!end)
return NULL;
*size = end-beg;
seg = malloc(*size+1);
strlcpy(seg, beg, *size+1);
return seg;
}
//
// math utils
//
double approach(double v, double t, double d) {
if(v < t) {
v += d;
if(v > t)
return t;
} else if(v > t) {
v -= d;
if(v < t)
return t;
}
return v;
}
double psin(double x) {
return 0.5 + 0.5 * sin(x);
}
double max(double a, double b) {
return (a > b)? a : b;
}
double min(double a, double b) {
return (a < b)? a : b;
}
double clamp(double f, double lower, double upper) {
if(f < lower)
return lower;
if(f > upper)
return upper;
return f;
}
//
// gl/video utils
//
void frame_rate(int *lasttime) {
if(global.frameskip) {
return;
}
int t = *lasttime + 1000.0/FPS - SDL_GetTicks();
if(t > 0)
SDL_Delay(t);
*lasttime = SDL_GetTicks();
}
void calc_fps(FPSCounter *fps) {
if(!fps->stagebg_fps)
fps->stagebg_fps = FPS;
if(SDL_GetTicks() > fps->fpstime+1000) {
fps->show_fps = fps->fps;
fps->fps = 0;
fps->fpstime = SDL_GetTicks();
} else {
fps->fps++;
}
fps->stagebg_fps = approach(fps->stagebg_fps, fps->show_fps, 0.1);
}
void set_ortho(void) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, SCREEN_W, SCREEN_H, 0, -100, 100);
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
}
void colorfill(float r, float g, float b, float a) {
if(a <= 0) return;
glColor4f(r,g,b,a);
glPushMatrix();
glScalef(SCREEN_W,SCREEN_H,1);
glTranslatef(0.5,0.5,0);
draw_quad();
glPopMatrix();
glColor4f(1,1,1,1);
}
void fade_out(float f) {
colorfill(0, 0, 0, f);
}
//
// i/o uitls
//
char* read_all(const char *filename, int *outsize) {
char *text;
size_t size;
FILE *file = fopen(filename, "r");
if(file == NULL)
errx(-1, "Error opening '%s'", filename);
fseek(file, 0, SEEK_END);
size = ftell(file);
fseek(file, 0, SEEK_SET);
text = malloc(size+1);
fread(text, size, 1, file);
text[size] = 0;
fclose(file);
if(outsize) {
*outsize = size;
}
return text;
}
//
// misc utils
//
int getenvint(const char *v) {
char *e = getenv(v);
if(e) {
return atoi(e);
}
return 0;
}

95
src/util.h Normal file
View file

@ -0,0 +1,95 @@
#ifndef TSUTIL_H
#define TSUTIL_H
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <zlib.h> // compiling under mingw may fail without this...
//
// string utils
//
#undef strlcat
#undef strlcpy
#define strlcat SDL_strlcat
#define strlcpy SDL_strlcpy
#undef strncat
#undef strncpy
#define strncat DO_NOT_USE_strncat_USE_strlcat
#define strncpy DO_NOT_USE_strncpy_USE_strlcpy
char* copy_segment(const char *text, const char *delim, int *size);
bool strendswith(const char *s, const char *e);
bool strstartswith(const char *s, const char *p);
bool strendswith_any(const char *s, const char **earray);
void stralloc(char **dest, const char *src);
char* strjoin(const char *first, ...);
char* strfmt(const char *fmt, ...);
#undef strdup
#define strdup SDL_strdup
//
// math utils
//
#include <complex.h>
// These definitions are common but non-standard, so we provide our own
#undef M_PI
#undef M_PI_2
#define M_PI 3.14159265358979323846
#define M_PI_2 1.57079632679489661923
// This is a workaround to properly specify the type of our "complex" variables...
// Taisei code always uses just "complex" when it actually means "complex double", which is not really correct...
// gcc doesn't seem to care, other compilers do (e.g. clang)
#ifdef complex
#undef complex
#define complex _Complex double
#endif
// needed for mingw compatibility:
#undef min
#undef max
double min(double, double);
double max(double, double);
double clamp(double, double, double);
double approach(double v, double t, double d);
double psin(double);
#define SIGN(x) ((x > 0) - (x < 0))
//
// gl/video utils
//
typedef struct {
int fpstime; // frame counter
int fps;
int show_fps;
double stagebg_fps;
} FPSCounter;
void frame_rate(int *lasttime);
void calc_fps(FPSCounter *fps);
void set_ortho(void);
void colorfill(float r, float g, float b, float a);
void fade_out(float f);
//
// i/o utils
//
char* read_all(const char *filename, int *size);
//
// misc utils
//
int getenvint(const char *v);
#endif

View file

@ -6,6 +6,8 @@
* Copyright (C) 2012, Alexeyew Andrew <http://akari.thebadasschoobs.org/>
*/
#include <png.h>
#include "global.h"
#include "video.h"
#include "taisei_err.h"
@ -219,6 +221,74 @@ void video_setmode(int w, int h, bool fs, bool resizable) {
_video_setmode(w, h, flags, false);
}
void video_take_screenshot(void) {
FILE *out;
char *data;
char outfile[128], *outpath;
time_t rawtime;
struct tm * timeinfo;
int w, h, rw, rh;
w = video.current.width;
h = video.current.height;
rw = video.real.width;
rh = video.real.height;
data = malloc(3 * rw * rh);
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(outfile, 128, "/taisei_%Y%m%d_%H-%M-%S_%Z.png", timeinfo);
outpath = strjoin(get_screenshots_path(), outfile, NULL);
printf("Saving screenshot as %s\n", outpath);
out = fopen(outpath, "wb");
free(outpath);
if(!out) {
perror("fopen");
free(data);
return;
}
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, rw, rh, GL_RGB, GL_UNSIGNED_BYTE, data);
png_structp png_ptr;
png_infop info_ptr;
png_byte **row_pointers;
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info_ptr = png_create_info_struct (png_ptr);
png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
row_pointers = png_malloc(png_ptr, h*sizeof(png_byte *));
for(int y = 0; y < h; y++) {
row_pointers[y] = png_malloc(png_ptr, 8*3*w);
memcpy(row_pointers[y], data + rw*3*(h-1-y), w*3);
}
png_init_io(png_ptr, out);
png_set_rows(png_ptr, info_ptr, row_pointers);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
for(int y = 0; y < h; y++)
png_free(png_ptr, row_pointers[y]);
png_free(png_ptr, row_pointers);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(data);
fclose(out);
}
bool video_isresizable(void) {
return SDL_GetWindowFlags(video.window) & SDL_WINDOW_RESIZABLE;
}

View file

@ -42,5 +42,6 @@ void video_set_fullscreen(bool);
void video_toggle_fullscreen(void);
void video_resize(int w, int h);
void video_update_vsync(void);
void video_take_screenshot(void);
#endif