taisei/src/resource/texture.c
2022-01-02 08:28:02 +02:00

192 lines
4.1 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "taisei.h"
#include "texture_loader/texture_loader.h"
#include "global.h"
#include "video.h"
#include "renderer/api.h"
static bool texture_transfer(void *dst, void *src) {
return r_texture_transfer(dst, src);
}
ResourceHandler texture_res_handler = {
.type = RES_TEXTURE,
.typename = "texture",
.subdir = TEX_PATH_PREFIX,
.procs = {
.find = texture_loader_path,
.check = texture_loader_check_path,
.load = texture_loader_stage1,
.unload = texture_loader_unload,
.transfer = texture_transfer,
},
};
static struct draw_texture_state {
bool drawing;
bool texture_matrix_tainted;
} draw_texture_state;
void begin_draw_texture(FloatRect dest, FloatRect frag, Texture *tex) {
assume(!draw_texture_state.drawing);
draw_texture_state.drawing = true;
r_uniform_sampler("tex", tex);
r_mat_mv_push();
uint tw, th;
r_texture_get_size(tex, 0, &tw, &th);
float x = dest.x;
float y = dest.y;
float w = dest.w;
float h = dest.h;
float s = frag.w/tw;
float t = frag.h/th;
if(r_supports(RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN)) {
// FIXME: please somehow abstract this shit away!
frag.y = th - frag.y - frag.h;
}
if(s != 1 || t != 1 || frag.x || frag.y) {
draw_texture_state.texture_matrix_tainted = true;
r_mat_tex_push();
r_mat_tex_scale(1.0/tw, 1.0/th, 1);
if(frag.x || frag.y) {
r_mat_tex_translate(frag.x, frag.y, 0);
}
if(s != 1 || t != 1) {
r_mat_tex_scale(frag.w, frag.h, 1);
}
}
if(x || y) {
r_mat_mv_translate(x, y, 0);
}
if(w != 1 || h != 1) {
r_mat_mv_scale(w, h, 1);
}
}
void end_draw_texture(void) {
assume(draw_texture_state.drawing);
if(draw_texture_state.texture_matrix_tainted) {
draw_texture_state.texture_matrix_tainted = false;
r_mat_tex_pop();
}
r_mat_mv_pop();
draw_texture_state.drawing = false;
}
void fill_viewport(float xoff, float yoff, float ratio, const char *name) {
fill_viewport_p(xoff, yoff, ratio, 1, 0, res_texture(name));
}
void fill_viewport_p(float xoff, float yoff, float ratio, float aspect, float angle, Texture *tex) {
r_uniform_sampler("tex", tex);
float rw, rh;
if(ratio == 0) {
rw = aspect;
rh = 1;
} else {
rw = ratio * aspect;
rh = ratio;
}
if(r_supports(RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN)) {
// FIXME: we should somehow account for this globally if possible...
yoff *= -1;
yoff += (1 - ratio);
}
bool texture_matrix_tainted = false;
if(xoff || yoff || rw != 1 || rh != 1 || angle) {
texture_matrix_tainted = true;
r_mat_tex_push();
if(xoff || yoff) {
r_mat_tex_translate(xoff, yoff, 0);
}
if(rw != 1 || rh != 1) {
r_mat_tex_scale(rw, rh, 1);
}
if(angle) {
r_mat_tex_translate(0.5, 0.5, 0);
r_mat_tex_rotate(angle * DEG2RAD, 0, 0, 1);
r_mat_tex_translate(-0.5, -0.5, 0);
}
}
r_mat_mv_push();
r_mat_mv_translate(VIEWPORT_W*0.5, VIEWPORT_H*0.5, 0);
r_mat_mv_scale(VIEWPORT_W, VIEWPORT_H, 1);
r_draw_quad();
r_mat_mv_pop();
if(texture_matrix_tainted) {
r_mat_tex_pop();
}
}
void fill_screen(const char *name) {
fill_screen_p(res_texture(name));
}
void fill_screen_p(Texture *tex) {
uint tw, th;
r_texture_get_size(tex, 0, &tw, &th);
begin_draw_texture((FloatRect){ SCREEN_W*0.5, SCREEN_H*0.5, SCREEN_W, SCREEN_H }, (FloatRect){ 0, 0, tw, th }, tex);
r_draw_quad();
end_draw_texture();
}
// draws a thin, w-width rectangle from point A to point B with a texture that
// moves along the line.
//
void loop_tex_line_p(cmplx a, cmplx b, float w, float t, Texture *texture) {
cmplx d = b-a;
cmplx c = (b+a)/2;
r_mat_mv_push();
r_mat_mv_translate(creal(c), cimag(c), 0);
r_mat_mv_rotate(carg(d), 0, 0, 1);
r_mat_mv_scale(cabs(d), w, 1);
r_mat_tex_push();
r_mat_tex_translate(t, 0, 0);
r_uniform_sampler("tex", texture);
r_draw_quad();
r_mat_tex_pop();
r_mat_mv_pop();
}
void loop_tex_line(cmplx a, cmplx b, float w, float t, const char *texture) {
loop_tex_line_p(a, b, w, t, res_texture(texture));
}