Fix textures being internally Y-flipped (#142)

* WIP: upload textures with the bottom-left-origin convention, as OpenGL expects

* unflip: fix spellcard_walloftext, text_hud

* unflip: fix reimu's and marisa's bombs

* unflip: fix stagetext

* unflip: fix graph.frag.glsl

* fix sprite_circleclipped_indicator
This commit is contained in:
Andrei Alexeyev 2018-08-28 11:25:54 +03:00 committed by GitHub
parent 4e9ec77c91
commit e4f49310ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 159 additions and 48 deletions

View file

@ -29,9 +29,9 @@ float get_sample(float x) {
void main(void) {
vec4 c = vec4(1.0);
vec2 coord = vec2(texCoord.x, 1.0 - texCoord.y); // TODO: move to vertex shader
vec2 coord = flip_native_to_bottomleft(texCoord); // TODO: move to vertex shader
float s = get_sample(coord.x);
c.a = float(coord.y <= s);
c.a *= (0.2 + 0.8 * s);
c.a = 0.05 + 0.95 * c.a;

View file

@ -29,4 +29,8 @@
#define ATTRIBUTE(l) LOC(l) in
#endif
#if !defined(NATIVE_ORIGIN_TOPLEFT) && !defined(NATIVE_ORIGIN_BOTTOMLEFT)
#define NATIVE_ORIGIN_BOTTOMLEFT
#endif
#endif

View file

@ -77,4 +77,56 @@ vec3 hsv2rgb(vec3 c) {
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
float flip_topleft_to_native(float x) {
#ifdef NATIVE_ORIGIN_BOTTOMLEFT
return 1 - x;
#else
return x;
#endif
}
vec2 flip_topleft_to_native(vec2 v) {
v.y = flip_topleft_to_native(v.y);
return v;
}
float flip_bottomleft_to_native(float x) {
#ifdef NATIVE_ORIGIN_TOPLEFT
return 1 - x;
#else
return x;
#endif
}
vec2 flip_bottomleft_to_native(vec2 v) {
v.y = flip_bottomleft_to_native(v.y);
return v;
}
float flip_native_to_topleft(float x) {
#ifdef NATIVE_ORIGIN_TOPLEFT
return x;
#else
return 1 - x;
#endif
}
vec2 flip_native_to_topleft(vec2 v) {
v.y = flip_native_to_topleft(v.y);
return v;
}
float flip_native_to_bottomleft(float x) {
#ifdef NATIVE_ORIGIN_BOTTOMLEFT
return x;
#else
return 1 - x;
#endif
}
vec2 flip_native_to_bottomleft(vec2 v) {
v.y = flip_native_to_bottomleft(v.y);
return v;
}
#endif

View file

@ -12,14 +12,14 @@ void main(void) {
// This thing is supposed to produce a swirly texture centered
// around plrpos. To do it we have to map to polar coordinates
vec2 x = texCoordRaw-plrpos;
vec2 x = flip_native_to_topleft(texCoordRaw) - plrpos;
float r = length(x) - 2 * t * (1 + decay *t);
float phi = atan(x.y, x.x) / pi * 4;
// give the angle some juicy r dependent offset to twist the swirl.
phi += (1 + r) * t * 5 * decay;
vec4 texel = texture(tex, vec2(phi,r));
vec4 texel = texture(tex, vec2(phi, flip_topleft_to_native(r)));
float fade = 0.7 * min(1,t) * (1 - t * decay) * 4;
fragColor = texel * r_color * fade;

View file

@ -12,7 +12,7 @@ float smootherstep(float x, float width) {
}
void main(void) {
vec2 r = vec2(texCoord.x - 0.5, 1.0 - texCoord.y);
vec2 r = vec2(texCoord.x - 0.5, flip_native_to_bottomleft(texCoord.y));
// globally distort the coordinate system a little bit for a more interesting/dynamic shape
r.x -= 0.005 * sin(r.y * 13.32 - t * 0.53);

View file

@ -67,7 +67,7 @@ void main(void) {
vec2 uv = texCoord;
float ld, dd;
float yy = yinyang_spin(uv, aspect * zoom, -time, ld, dd);
float yy = yinyang_spin(flip_native_to_topleft(uv), aspect * zoom, -time, ld, dd);
vec2 uv_r = uv;
vec2 uv_g = uv;
@ -115,10 +115,10 @@ void main(void) {
vec2 runes_uv = (uv - 0.5) * rot(pi * 0.5) + 0.5;
float line = floor(runes_uv.y * rune_lines);
runes_uv.x += 0.931223 * line + time * 0.1 * cos(pi * line);
runes_uv.y *= -rune_lines;
runes_uv.y *= rune_lines;
runes_uv = runes_transform_uv(runes_uv);
float rune_factor = texture(runes, runes_uv).r;
float rune_factor = texture(runes, flip_bottomleft_to_native(runes_uv)).r;
fragColor.rgb = pow(fragColor.rgb, vec3(1 + (1 - 2 * rune_factor) * 0.1));
// fragColor = mix(fragColor, 0.9 * fragColor + vec4(0.1), rune_factor * r_color);
fragColor += r_color * rune_factor * 0.1;

View file

@ -6,13 +6,13 @@
void main(void) {
float n = 10; // rough number of rings of text
vec2 pos = (vec2(texCoordRaw) - origin * vec2(ratio, 1.0)) * n;
vec2 pos = (vec2(flip_native_to_topleft(texCoordRaw)) - origin * vec2(ratio, 1.0)) * n;
pos.x /= ratio;
// Slightly distorted mapping to polar coordinates. I wrote this
// shortly after hearing a general relativity lecture...
pos = vec2(atan(pos.x,pos.y), length(pos) + n * t * 0.1);
pos = vec2(atan(pos.x, pos.y), length(pos) + n * t * 0.1);
// The idea is (apart from the aspect factors) to map the
// (phi, angle) coordinates to something that loops several
@ -22,14 +22,15 @@ void main(void) {
// Simplified example:
// f(x) = x for 0 < x < 2
// mod(f(x),1) then goes from 0 to 1 and from 0 to 1 again.
//
//
// If you use it as a texcoord you get two copies of the texture.
//
// The complicated example I dont understand either:
pos.x *= h/w;
pos.x += t * 0.5 * float(2 * int(mod(pos.y, 2)) - 1);
pos = mod(pos, vec2(1 + 0.01 / w, 1));
pos = flip_topleft_to_native(pos);
pos *= vec2(w,h);
vec4 texel = texture(tex, pos);

View file

@ -7,9 +7,8 @@ UNIFORM(1) vec4 back_color;
void main(void) {
float fill = customParams.r;
vec2 tc = texCoord;
vec4 texel = texture(tex, tc);
tc = texCoordRaw - vec2(0.5);
texel *= mix(back_color, color, float(atan(tc.x,-tc.y) < pi*(2.0*fill-1.0)));
vec4 texel = texture(tex, texCoord);
vec2 tc = flip_native_to_bottomleft(texCoordRaw) - vec2(0.5);
texel *= mix(back_color, color, float(atan(tc.x, tc.y) < pi*(2.0*fill-1.0)));
fragColor = texel;
}

View file

@ -1,11 +1,12 @@
#version 330 core
#include "lib/render_context.glslh"
#include "lib/util.glslh"
#include "interface/sprite.glslh"
void main(void) {
vec4 texel = texture(tex, texCoord);
float gradient = mix(1.0, 0.8, texCoordOverlay.y);
float gradient = 0.8 + 0.2 * flip_native_to_bottomleft(texCoordOverlay.y);
fragColor = color * texel.r * gradient;
fragColor.rgb *= gradient;
}

View file

@ -10,7 +10,7 @@ float tc_mask(vec2 tc) {
void main(void) {
float t = customParams.r;
vec2 tc = texCoord;
vec2 tc = flip_native_to_topleft(texCoord);
vec2 tc_overlay = texCoordOverlay;
tc *= dimensions;
@ -19,12 +19,12 @@ void main(void) {
tc /= dimensions;
float a = tc_mask(tc);
vec4 textfrag = color * texture(tex, uv_to_region(texRegion, tc)).r * a;
vec4 textfrag = color * texture(tex, uv_to_region(texRegion, flip_topleft_to_native(tc))).r * a;
tc -= vec2(1) / dimensions;
a = tc_mask(tc);
vec4 shadowfrag = vec4(vec3(0), color.a) * texture(tex, uv_to_region(texRegion, tc)).r * a;
vec4 shadowfrag = vec4(vec3(0), color.a) * texture(tex, uv_to_region(texRegion, flip_topleft_to_native(tc))).r * a;
fragColor = textfrag;
fragColor = mix(shadowfrag, textfrag, sqrt(textfrag.a));

View file

@ -22,6 +22,7 @@ typedef enum RendererFeature {
RFEAT_DRAW_INSTANCED_BASE_INSTANCE,
RFEAT_DEPTH_TEXTURE,
RFEAT_FRAMEBUFFER_MULTIPLE_OUTPUTS,
RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN,
NUM_RFEATS,
} RendererFeature;

View file

@ -26,10 +26,10 @@ void _r_models_init(void) {
}, fmt, 0);
GenericModelVertex quad[4] = {
{ { -0.5, -0.5, 0.0 }, { 0, 0, 1 }, { 0, 0 } },
{ { -0.5, 0.5, 0.0 }, { 0, 0, 1 }, { 0, 1 } },
{ { 0.5, 0.5, 0.0 }, { 0, 0, 1 }, { 1, 1 } },
{ { 0.5, -0.5, 0.0 }, { 0, 0, 1 }, { 1, 0 } },
{ { -0.5, -0.5, 0.0 }, { 0, 0, 1 }, { 0, 1 } },
{ { -0.5, 0.5, 0.0 }, { 0, 0, 1 }, { 0, 0 } },
{ { 0.5, 0.5, 0.0 }, { 0, 0, 1 }, { 1, 0 } },
{ { 0.5, -0.5, 0.0 }, { 0, 0, 1 }, { 1, 1 } },
};
r_vertex_buffer_create(&_r_models.vbuf, 8192 * sizeof(GenericModelVertex), NULL);
@ -72,11 +72,6 @@ void r_draw_quad_instanced(uint instances) {
void r_draw_model_ptr(Model *model) {
VertexArray *varr_saved = r_vertex_array_current();
r_vertex_array(&_r_models.varr);
r_mat_mode(MM_TEXTURE);
r_mat_push();
r_mat_scale(1, -1, 1); // XXX: flipped texture workaround. can we get rid of this somehow?
r_draw(PRIM_TRIANGLES, 0, model->icount, model->indices, 0, 0);
r_mat_pop();
r_mat_mode(MM_MODELVIEW);
r_vertex_array(varr_saved);
}

View file

@ -240,6 +240,8 @@ static void gl33_init_context(SDL_Window *window) {
if(glext.draw_buffers) {
R.features |= r_feature_bit(RFEAT_FRAMEBUFFER_MULTIPLE_OUTPUTS);
}
R.features |= r_feature_bit(RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN);
}
static void gl33_apply_capability(RendererCapability cap, bool value) {

View file

@ -14,6 +14,7 @@
#include "font.h"
#include "util.h"
#include "util/rectpack.h"
#include "util/graphics.h"
#include "config.h"
#include "video.h"
#include "events.h"
@ -375,15 +376,30 @@ static bool add_glyph_to_spritesheet(Font *font, Glyph *glyph, FT_Bitmap bitmap,
sprite_pos.bottom_right += ofs;
sprite_pos.top_left += ofs;
r_texture_fill_region(
&ss->tex,
0,
rect_x(sprite_pos),
rect_y(sprite_pos),
bitmap.width,
bitmap.rows,
bitmap.buffer
);
if(r_supports(RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN)) {
char buffer[bitmap.width * bitmap.rows];
flip_bitmap_copy(buffer, (char*)bitmap.buffer, bitmap.rows, bitmap.width);
r_texture_fill_region(
&ss->tex,
0,
rect_x(sprite_pos),
rect_y(sprite_pos),
bitmap.width,
bitmap.rows,
buffer
);
} else {
r_texture_fill_region(
&ss->tex,
0,
rect_x(sprite_pos),
rect_y(sprite_pos),
bitmap.width,
bitmap.rows,
bitmap.buffer
);
}
glyph->sprite.tex = &ss->tex;
glyph->sprite.w = glyph->metrics.width; // bitmap.width / font->scale;
@ -862,6 +878,15 @@ static double _text_draw(Font *font, const char *text, const TextParams *params)
r_mat_scale(1/bbox_w, 1/bbox_h, 1.0);
r_mat_translate(-bbox.x.min - (x - x_orig), -bbox.y.min + font->metrics.descent, 0);
// FIXME: is there a better way?
float texmat_offset_sign;
if(r_supports(RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN)) {
texmat_offset_sign = -1;
} else {
texmat_offset_sign = 1;
}
bool keming = FT_HAS_KERNING(font->face);
uint prev_glyph_idx = 0;
const char *tptr = text;
@ -899,7 +924,7 @@ static double _text_draw(Font *font, const char *text, const TextParams *params)
sp.scale.both = font->metrics.scale;
r_mat_push();
r_mat_translate(sp.pos.x - x_orig, sp.pos.y, 0);
r_mat_translate(sp.pos.x - x_orig, sp.pos.y * texmat_offset_sign, 0);
r_mat_scale(w_saved, h_saved, 1.0);
r_mat_translate(-0.5, -0.5, 0);
@ -981,7 +1006,7 @@ void text_render(const char *text, Font *font, Sprite *out_sprite, BBox *out_bbo
r_blend(BLEND_PREMUL_ALPHA);
r_enable(RCAP_CULL_FACE);
r_cull(CULL_FRONT);
r_cull(CULL_BACK);
r_disable(RCAP_DEPTH_TEST);
r_mat_mode(MM_MODELVIEW);
@ -991,8 +1016,7 @@ void text_render(const char *text, Font *font, Sprite *out_sprite, BBox *out_bbo
r_mat_mode(MM_PROJECTION);
r_mat_push();
r_mat_identity();
// XXX: y-flipped because that's how our textures are...
r_mat_ortho(0, tex->w, 0, tex->h, -100, 100);
r_mat_ortho(0, tex->w, tex->h, 0, -100, 100);
r_mat_mode(MM_TEXTURE);
r_mat_push();

View file

@ -131,6 +131,11 @@ void* load_sprite_end(void *opaque, const char *path, uint flags) {
}
}
// FIXME: is there a better way?
if(r_supports(RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN)) {
spr->tex_area.y = tex_h_flt - spr->tex_area.y - spr->tex_area.h;
}
free(basename);
return spr;
}

View file

@ -292,6 +292,12 @@ static void* load_texture_begin(const char *path, uint flags) {
return NULL;
}
if(r_supports(RFEAT_TEXTURE_BOTTOMLEFT_ORIGIN)) {
SDL_LockSurface(converted_surf);
flip_bitmap(converted_surf->pixels, converted_surf->h, converted_surf->w * 4);
SDL_UnlockSurface(converted_surf);
}
if(ld.params.mipmaps == 0) {
ld.params.mipmaps = TEX_MIPMAPS_MAX;
}
@ -334,7 +340,6 @@ static void texture_post_load(Texture *tex) {
r_mat_mode(MM_MODELVIEW);
r_mat_scale(tex->w, tex->h, 1);
r_mat_translate(0.5, 0.5, 0);
r_mat_scale(1, -1, 1);
r_framebuffer_create(&fb);
r_framebuffer_attach(&fb, &fbo_tex, 0, FRAMEBUFFER_ATTACH_COLOR0);
r_framebuffer_viewport(&fb, 0, 0, tex->w, tex->h);

View file

@ -410,7 +410,11 @@ static void draw_wall_of_text(float f, const char *txt) {
Sprite spr;
BBox bbox;
text_render(txt, get_font("standard"), &spr, &bbox);
char buf[strlen(txt) + 4];
memcpy(buf, txt, sizeof(buf) - 4);
memcpy(buf + sizeof(buf) - 4, " ~ ", 4);
text_render(buf, get_font("standard"), &spr, &bbox);
// FIXME: The shader currently assumes that the sprite takes up the entire texture.
// If it could handle any arbitrary sprite, then text_render wouldn't have to resize // the texture per every new string of text.
@ -427,7 +431,7 @@ static void draw_wall_of_text(float f, const char *txt) {
r_uniform_float("w", spr.tex_area.w/spr.tex->w);
r_uniform_float("h", spr.tex_area.h/spr.tex->h);
r_uniform_float("ratio", h/w);
r_uniform_vec2("origin", creal(global.boss->pos)/h, cimag(global.boss->pos)/w);
r_uniform_vec2("origin", creal(global.boss->pos)/h, cimag(global.boss->pos)/w); // what the fuck?
r_uniform_float("t", f);
r_texture_ptr(0, spr.tex);
r_draw_quad();

View file

@ -102,13 +102,12 @@ void draw_stars(int x, int y, int numstars, int numfrags, int maxstars, int maxf
void draw_framebuffer_attachment(Framebuffer *fb, double width, double height, FramebufferAttachment attachment) {
CullFaceMode cull_saved = r_cull_current();
r_cull(CULL_FRONT);
r_cull(CULL_BACK);
r_mat_push();
r_texture_ptr(0, r_framebuffer_get_attachment(fb, attachment));
r_mat_scale(width, height, 1);
r_mat_translate(0.5, 0.5, 0);
r_mat_scale(1, -1, 1);
r_draw_quad();
r_mat_pop();
@ -163,3 +162,19 @@ void init_blur_shader(ShaderProgram *prog, size_t kernel_size, float sigma) {
gaussian_kernel_1d(kernel_size, sigma, kernel);
r_uniform_ptr(r_shader_uniform(prog, "blur_kernel[0]"), kernel_size, kernel);
}
void flip_bitmap(char *data, size_t rows, size_t row_length) {
char swap_buffer[row_length];
for(size_t row = 0; row < rows / 2; ++row) {
memcpy(swap_buffer, data + row * row_length, row_length);
memcpy(data + row * row_length, data + (rows - row - 1) * row_length, row_length);
memcpy(data + (rows - row - 1) * row_length, swap_buffer, row_length);
}
}
void flip_bitmap_copy(char *dst, const char *src, size_t rows, size_t row_length) {
for(size_t row = 0, irow = rows - 1; row < rows; ++row, --irow) {
memcpy(dst + irow * row_length, src + row * row_length, row_length);
}
}

View file

@ -23,3 +23,6 @@ void fbutil_destroy_attachments(Framebuffer *fb);
void fbutil_resize_attachment(Framebuffer *fb, FramebufferAttachment attachment, uint width, uint height);
void init_blur_shader(ShaderProgram *prog, size_t kernel_size, float sigma);
void flip_bitmap(char *data, size_t rows, size_t row_length);
void flip_bitmap_copy(char *dst, const char *src, size_t rows, size_t row_length);