taisei/src/resource/sprite.c

178 lines
4.4 KiB
C

/*
* This software is licensed under the terms of the MIT-License
* See COPYING for further information.
* ---
* Copyright (c) 2011-2018, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2018, Andrei Alexeyev <akari@alienslab.net>.
*/
#include "taisei.h"
#include "sprite.h"
#include "resource.h"
#include "video.h"
char* sprite_path(const char *name) {
char *path = strjoin(SPRITE_PATH_PREFIX, name, SPRITE_EXTENSION, NULL);
VFSInfo pinfo = vfs_query(path);
if(!pinfo.exists) {
free(path);
return texture_path(name);
}
return path;
}
bool check_sprite_path(const char *path) {
return strendswith(path, SPRITE_EXTENSION) || check_texture_path(path);
}
struct sprite_load_state {
Sprite *spr;
unsigned int flags;
char *texture_name;
};
void* load_sprite_begin(const char *path, unsigned int flags) {
Sprite *spr = calloc(1, sizeof(Sprite));
struct sprite_load_state *state = calloc(1, sizeof(struct sprite_load_state));
state->spr = spr;
state->flags = flags;
if(check_texture_path(path)) {
state->texture_name = resource_util_basename(TEX_PATH_PREFIX, path);
return state;
}
if(!parse_keyvalue_file_with_spec(path, (KVSpec[]){
{ "texture", .out_str = &state->texture_name },
{ "region_x", .out_float = &spr->tex_area.x },
{ "region_y", .out_float = &spr->tex_area.y },
{ "region_w", .out_float = &spr->tex_area.w },
{ "region_h", .out_float = &spr->tex_area.h },
{ "w", .out_float = &spr->w },
{ "h", .out_float = &spr->h },
{ NULL }
})) {
free(spr);
free(state->texture_name);
free(state);
log_warn("Failed to parse sprite file '%s'", path);
return NULL;
}
if(!state->texture_name) {
state->texture_name = resource_util_basename(TEX_PATH_PREFIX, path);
log_warn("%s: inferred texture name from sprite name", state->texture_name);
}
return state;
}
void* load_sprite_end(void *opaque, const char *path, unsigned int flags) {
struct sprite_load_state *state = opaque;
if(!state) {
return NULL;
}
Sprite *spr = state->spr;
Resource *res = get_resource(RES_TEXTURE, state->texture_name, flags);
free(state->texture_name);
free(state);
if(res == NULL) {
free(spr);
return NULL;
}
spr->tex = res->texture;
float tex_w_flt = spr->tex->w;
float tex_h_flt = spr->tex->h;
struct infermap {
const char *dstname;
float *dst;
const char *srcname;
float *src;
} infermap[] = {
{ "region width", &spr->tex_area.w, "texture width", &tex_w_flt },
{ "region height", &spr->tex_area.h, "texture height", &tex_h_flt },
{ "sprite width", &spr->w, "region width", &spr->tex_area.w },
{ "sprite height", &spr->h, "region height", &spr->tex_area.h },
{ NULL },
};
char *basename = resource_util_basename(SPRITE_PATH_PREFIX, path);
for(struct infermap *m = infermap; m->dst; ++m) {
if(*m->dst <= 0) {
*m->dst = *m->src;
log_warn("%s: inferred %s from %s (%f)", basename, m->dstname, m->srcname, *m->src);
}
}
free(basename);
return spr;
}
Sprite* get_sprite(const char *name) {
return get_resource(RES_SPRITE, name, RESF_DEFAULT | RESF_UNSAFE)->sprite;
}
Sprite* prefix_get_sprite(const char *name, const char *prefix) {
char *full = strjoin(prefix, name, NULL);
Sprite *spr = get_sprite(full);
free(full);
return spr;
}
void draw_sprite(float x, float y, const char *name) {
draw_sprite_p(x, y, get_sprite(name));
}
void draw_sprite_p(float x, float y, Sprite *spr) {
draw_sprite_ex(x, y, 1, 1, true, spr);
}
void draw_sprite_unaligned(float x, float y, const char *name) {
draw_sprite_unaligned_p(x, y, get_sprite(name));
}
void draw_sprite_unaligned_p(float x, float y, Sprite *spr) {
draw_sprite_ex(x, y, 1, 1, false, spr);
}
void begin_draw_sprite(float x, float y, float scale_x, float scale_y, bool align, Sprite *spr) {
/*
if(align) {
// pixel-"perfect" alignment hack
// doesn't take viewport quality setting into account,
// but i assume that if you have it below 100%, you don't care anyway.
float q = video.quality_factor;
x = floor(x*q+0.5)/q;
y = floor(y*q+0.5)/q;
}
*/
begin_draw_texture(
(FloatRect){ x, y, spr->w * scale_x, spr->h * scale_y },
(FloatRect){ spr->tex_area.x, spr->tex_area.y, spr->tex_area.w, spr->tex_area.h },
spr->tex
);
}
void end_draw_sprite(void) {
end_draw_texture();
}
void draw_sprite_ex(float x, float y, float scale_x, float scale_y, bool align, Sprite *spr) {
begin_draw_sprite(x, y, scale_x, scale_y, align, spr);
draw_quad();
end_draw_texture();
}