diff --git a/resources/shader/graph.frag.glsl b/resources/shader/graph.frag.glsl index 5e22fa05..dad1ec9c 100644 --- a/resources/shader/graph.frag.glsl +++ b/resources/shader/graph.frag.glsl @@ -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; diff --git a/resources/shader/lib/defs.glslh b/resources/shader/lib/defs.glslh index c5402393..daf63f1a 100644 --- a/resources/shader/lib/defs.glslh +++ b/resources/shader/lib/defs.glslh @@ -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 diff --git a/resources/shader/lib/util.glslh b/resources/shader/lib/util.glslh index c0ba3983..c8f86316 100644 --- a/resources/shader/lib/util.glslh +++ b/resources/shader/lib/util.glslh @@ -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 diff --git a/resources/shader/maristar_bombbg.frag.glsl b/resources/shader/maristar_bombbg.frag.glsl index 6411f890..d8ad8a11 100644 --- a/resources/shader/maristar_bombbg.frag.glsl +++ b/resources/shader/maristar_bombbg.frag.glsl @@ -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; diff --git a/resources/shader/masterspark.frag.glsl b/resources/shader/masterspark.frag.glsl index 582086c6..ee6fa8c7 100644 --- a/resources/shader/masterspark.frag.glsl +++ b/resources/shader/masterspark.frag.glsl @@ -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); diff --git a/resources/shader/reimu_bomb_bg.frag.glsl b/resources/shader/reimu_bomb_bg.frag.glsl index 59f8f9a6..d4ecce5b 100644 --- a/resources/shader/reimu_bomb_bg.frag.glsl +++ b/resources/shader/reimu_bomb_bg.frag.glsl @@ -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; diff --git a/resources/shader/spellcard_walloftext.frag.glsl b/resources/shader/spellcard_walloftext.frag.glsl index 83f86f8c..294eace8 100644 --- a/resources/shader/spellcard_walloftext.frag.glsl +++ b/resources/shader/spellcard_walloftext.frag.glsl @@ -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 don’t 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); diff --git a/resources/shader/sprite_circleclipped_indicator.frag.glsl b/resources/shader/sprite_circleclipped_indicator.frag.glsl index eb4a27b7..a3a31223 100644 --- a/resources/shader/sprite_circleclipped_indicator.frag.glsl +++ b/resources/shader/sprite_circleclipped_indicator.frag.glsl @@ -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; } diff --git a/resources/shader/text_hud.frag.glsl b/resources/shader/text_hud.frag.glsl index 98412504..7a2313da 100644 --- a/resources/shader/text_hud.frag.glsl +++ b/resources/shader/text_hud.frag.glsl @@ -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; } diff --git a/resources/shader/text_stagetext.frag.glsl b/resources/shader/text_stagetext.frag.glsl index f1821c70..93a7f0e2 100644 --- a/resources/shader/text_stagetext.frag.glsl +++ b/resources/shader/text_stagetext.frag.glsl @@ -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)); diff --git a/src/renderer/api.h b/src/renderer/api.h index 9cee39b5..26143d24 100644 --- a/src/renderer/api.h +++ b/src/renderer/api.h @@ -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; diff --git a/src/renderer/common/models.c b/src/renderer/common/models.c index c777dbd4..64871ef6 100644 --- a/src/renderer/common/models.c +++ b/src/renderer/common/models.c @@ -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); } diff --git a/src/renderer/gl33/core.c b/src/renderer/gl33/core.c index 01a08c51..87b1d398 100644 --- a/src/renderer/gl33/core.c +++ b/src/renderer/gl33/core.c @@ -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) { diff --git a/src/resource/font.c b/src/resource/font.c index e1e47d7e..6215d19e 100644 --- a/src/resource/font.c +++ b/src/resource/font.c @@ -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(); diff --git a/src/resource/sprite.c b/src/resource/sprite.c index ae9c7115..e2992943 100644 --- a/src/resource/sprite.c +++ b/src/resource/sprite.c @@ -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; } diff --git a/src/resource/texture.c b/src/resource/texture.c index ffd1d42e..729e98b7 100644 --- a/src/resource/texture.c +++ b/src/resource/texture.c @@ -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); diff --git a/src/stagedraw.c b/src/stagedraw.c index ca27b3f6..87478f80 100644 --- a/src/stagedraw.c +++ b/src/stagedraw.c @@ -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(); diff --git a/src/util/graphics.c b/src/util/graphics.c index d4b58b01..9a204330 100644 --- a/src/util/graphics.c +++ b/src/util/graphics.c @@ -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); + } +} diff --git a/src/util/graphics.h b/src/util/graphics.h index afe361d9..0df29a49 100644 --- a/src/util/graphics.h +++ b/src/util/graphics.h @@ -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);