moved util functions from global to where they make a bit more sense
This commit is contained in:
parent
0ebf29660f
commit
dacbf96427
18 changed files with 455 additions and 445 deletions
|
@ -21,6 +21,7 @@ endif()
|
|||
|
||||
set(SRCs
|
||||
main.c
|
||||
util.c
|
||||
taiseigl.c
|
||||
random.c
|
||||
config.c
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
329
src/global.c
329
src/global.c
|
@ -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);
|
||||
}
|
||||
|
|
78
src/global.h
78
src/global.h
|
@ -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
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#ifndef ITEM_H
|
||||
#define ITEM_H
|
||||
|
||||
#include "tscomplex.h"
|
||||
#include "util.h"
|
||||
|
||||
typedef struct Item Item;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#ifndef LASER_H
|
||||
#define LASER_H
|
||||
|
||||
#include "tscomplex.h"
|
||||
#include "util.h"
|
||||
#include "projectile.h"
|
||||
#include "resource/shader.h"
|
||||
|
||||
|
|
14
src/player.h
14
src/player.h
|
@ -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*);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#ifndef PROJECTILE
|
||||
#define PROJECTILE
|
||||
|
||||
#include "tscomplex.h"
|
||||
#include "util.h"
|
||||
#include "resource/texture.h"
|
||||
#include "color.h"
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "stage.h"
|
||||
#include "tscomplex.h"
|
||||
|
||||
#include <time.h>
|
||||
#include "global.h"
|
||||
|
|
|
@ -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
258
src/util.c
Normal 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
95
src/util.h
Normal 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
|
70
src/video.c
70
src/video.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue