diff --git a/shaders/parts.f.glsl b/shaders/parts.f.glsl index 8969328..952a5fb 100644 --- a/shaders/parts.f.glsl +++ b/shaders/parts.f.glsl @@ -21,7 +21,11 @@ uniform vec2 top_right; uniform vec3 add_color; uniform vec3 multiply_color; +uniform int use_clipper; +uniform sampler2D clipper_tex; + in vec2 tex_coord; +in vec2 clip_coord; out vec4 frag_color; float point_in_rect(vec2 p, vec2 bot_left, vec2 top_right) { @@ -36,5 +40,11 @@ void main() { vec4 tex_color = texture(tex, tex_coord); vec3 mod_color = (tex_color.rgb + add_color) * multiply_color; - frag_color = vec4(mod_color, tex_color.a * blend_rate) * point_in_rect(tex_coord, bl, tr); + + float alpha = tex_color.a * blend_rate; + if (use_clipper != 0) { + alpha *= texture(clipper_tex, clip_coord).a * point_in_rect(clip_coord, vec2(0.0), vec2(1.0)); + } + + frag_color = vec4(mod_color, alpha) * point_in_rect(tex_coord, bl, tr); } diff --git a/shaders/parts.v.glsl b/shaders/parts.v.glsl new file mode 100644 index 0000000..b8175fc --- /dev/null +++ b/shaders/parts.v.glsl @@ -0,0 +1,31 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +uniform mat4 world_transform; +uniform mat4 view_transform; +uniform mat4 inv_clipper_transform; + +in vec4 vertex_pos; +in vec2 vertex_uv; +out vec2 tex_coord; +out vec2 clip_coord; + +void main() { + vec4 world_pos = world_transform * vertex_pos; + gl_Position = view_transform * world_pos; + tex_coord = vertex_uv; + clip_coord = (inv_clipper_transform * world_pos).xy; +} diff --git a/src/parts/debug.c b/src/parts/debug.c index c2985ba..d2dd0ad 100644 --- a/src/parts/debug.c +++ b/src/parts/debug.c @@ -373,6 +373,7 @@ cJSON *parts_to_json(struct parts *parts, bool recursive, bool verbose) cJSON_AddNumberToObject(obj, "linked_from", parts->linked_from); cJSON_AddNumberToObject(obj, "draw_filter", parts->draw_filter); cJSON_AddBoolToObject(obj, "message_window", parts->message_window); + cJSON_AddNumberToObject(obj, "alpha_clipper_parts_no", parts->alpha_clipper_parts_no); cJSON_AddItemToObjectCS(obj, "motions", motions = cJSON_CreateArray()); struct parts_motion *motion; diff --git a/src/parts/parts.c b/src/parts/parts.c index 800c953..4e33c48 100644 --- a/src/parts/parts.c +++ b/src/parts/parts.c @@ -1769,7 +1769,9 @@ float PE_GetPartsRotateZ(int parts_no) void PE_SetPartsAlphaClipperPartsNumber(int parts_no, int alpha_clipper_parts_no) { - UNIMPLEMENTED("(%d, %d)", parts_no, alpha_clipper_parts_no); + struct parts *parts = parts_get(parts_no); + parts->alpha_clipper_parts_no = alpha_clipper_parts_no; + parts_dirty(parts); } void PE_SetPartsPixelDecide(int parts_no, bool pixel_decide) diff --git a/src/parts/parts_internal.h b/src/parts/parts_internal.h index cf9a244..0f546f7 100644 --- a/src/parts/parts_internal.h +++ b/src/parts/parts_internal.h @@ -334,6 +334,7 @@ struct parts { int linked_from; int draw_filter; bool message_window; + int alpha_clipper_parts_no; struct parts_motion_list motion; }; diff --git a/src/parts/render.c b/src/parts/render.c index 56f8358..f8859c3 100644 --- a/src/parts/render.c +++ b/src/parts/render.c @@ -43,31 +43,12 @@ static struct { GLint top_right; GLint add_color; GLint multiply_color; + GLint use_clipper; + GLint clipper_tex; + GLint inv_clipper_transform; } parts_shader; -static void parts_render_text(struct parts *parts, struct parts_text *t) -{ - int x = parts->global.pos.x + t->common.origin_offset.x; - int y = parts->global.pos.y + t->common.origin_offset.y; - for (int i = 0; i < t->nr_lines; i++) { - struct parts_text_line *line = &t->lines[i]; - for (int j = 0; j < line->nr_chars; j++) { - struct parts_text_char *ch = &line->chars[j]; - Rectangle rect = { - .x = x, - .y = y, - .w = ch->t.w, - .h = ch->t.h - }; - gfx_render_texture(&ch->t, &rect); - x += ch->advance; - } - x = parts->global.pos.x + t->common.origin_offset.x; - y += line->height; - } -} - -static void parts_render_texture(struct texture *texture, mat4 mw_transform, Rectangle *rect, float blend_rate, vec3 add_color, vec3 multiply_color) +static void parts_render_texture(struct texture *texture, mat4 mw_transform, Rectangle *rect, float blend_rate, vec3 add_color, vec3 multiply_color, int alpha_clipper) { mat4 wv_transform = WV_TRANSFORM(config.view_width, config.view_height); @@ -86,9 +67,65 @@ static void parts_render_texture(struct texture *texture, mat4 mw_transform, Rec glUniform2f(parts_shader.top_right, rect->x + rect->w, rect->y + rect->h); glUniform3fv(parts_shader.add_color, 1, add_color); glUniform3fv(parts_shader.multiply_color, 1, multiply_color); + + struct parts *clipper = alpha_clipper ? parts_try_get(alpha_clipper) : NULL; + if (clipper) { + struct parts_common *c_common = &clipper->states[clipper->state].common; + + // Calculate the inverse of the clipper's world matrix. + mat4 clip_mw = GLM_MAT4_IDENTITY_INIT; + glm_translate(clip_mw, (vec3) { clipper->global.pos.x, clipper->global.pos.y, 0 }); + glm_rotate_z(clip_mw, clipper->local.rotation.z * (M_PI/180.0), clip_mw); + glm_scale(clip_mw, (vec3){ clipper->global.scale.x, clipper->global.scale.y, 1.0 }); + glm_translate(clip_mw, (vec3){ c_common->origin_offset.x, c_common->origin_offset.y, 0 }); + glm_scale(clip_mw, (vec3){ c_common->w, c_common->h, 1.0 }); + mat4 clip_inv; + glm_mat4_inv(clip_mw, clip_inv); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, c_common->texture.handle); + glActiveTexture(GL_TEXTURE0); + + glUniform1i(parts_shader.use_clipper, 1); + glUniform1i(parts_shader.clipper_tex, 1); + glUniformMatrix4fv(parts_shader.inv_clipper_transform, 1, GL_FALSE, clip_inv[0]); + } else { + glUniform1i(parts_shader.use_clipper, 0); + } + gfx_run_job(&job); } +static void parts_render_text(struct parts *parts, struct parts_text *t) +{ + vec3 add_color = { + parts->global.add_color.r / 255.0f, + parts->global.add_color.g / 255.0f, + parts->global.add_color.b / 255.0f + }; + vec3 multiply_color = { + parts->global.multiply_color.r / 255.0f, + parts->global.multiply_color.g / 255.0f, + parts->global.multiply_color.b / 255.0f, + }; + float blend_rate = parts->global.alpha / 255.0; + + int x = parts->global.pos.x + t->common.origin_offset.x; + int y = parts->global.pos.y + t->common.origin_offset.y; + for (int i = 0; i < t->nr_lines; i++) { + struct parts_text_line *line = &t->lines[i]; + for (int j = 0; j < line->nr_chars; j++) { + struct parts_text_char *ch = &line->chars[j]; + mat4 mw_transform = WORLD_TRANSFORM(ch->t.w, ch->t.h, x, y); + Rectangle r = { 0, 0, ch->t.w, ch->t.h }; + parts_render_texture(&ch->t, mw_transform, &r, blend_rate, add_color, multiply_color, parts->alpha_clipper_parts_no); + x += ch->advance; + } + x = parts->global.pos.x + t->common.origin_offset.x; + y += line->height; + } +} + static void parts_render_cg(struct parts *parts, struct parts_common *common) { switch (parts->draw_filter) { @@ -124,7 +161,7 @@ static void parts_render_cg(struct parts *parts, struct parts_common *common) parts->global.multiply_color.g / 255.0f, parts->global.multiply_color.b / 255.0f, }; - parts_render_texture(&common->texture, mw_transform, &r, parts->global.alpha / 255.0, add_color, multiply_color); + parts_render_texture(&common->texture, mw_transform, &r, parts->global.alpha / 255.0, add_color, multiply_color, parts->alpha_clipper_parts_no); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); } @@ -165,7 +202,7 @@ static void parts_render_flash_shape(struct parts *parts, struct parts_flash *f, (parts->global.multiply_color.g / 255.0f) * fixed16_to_float(obj->color_transform.mult_terms[1]), (parts->global.multiply_color.b / 255.0f) * fixed16_to_float(obj->color_transform.mult_terms[2]) }; - parts_render_texture(src, mw_transform, &r, blend_rate, add_color, multiply_color); + parts_render_texture(src, mw_transform, &r, blend_rate, add_color, multiply_color, parts->alpha_clipper_parts_no); } static void parts_render_flash_sprite(struct parts *parts, struct parts_flash *f, struct parts_flash_object *obj, struct swf_tag_define_sprite *tag) @@ -326,10 +363,13 @@ void parts_dirty(possibly_unused struct parts *parts) void parts_render_init(void) { - gfx_load_shader(&parts_shader.shader, "shaders/render.v.glsl", "shaders/parts.f.glsl"); + gfx_load_shader(&parts_shader.shader, "shaders/parts.v.glsl", "shaders/parts.f.glsl"); parts_shader.blend_rate = glGetUniformLocation(parts_shader.shader.program, "blend_rate"); parts_shader.bot_left = glGetUniformLocation(parts_shader.shader.program, "bot_left"); parts_shader.top_right = glGetUniformLocation(parts_shader.shader.program, "top_right"); parts_shader.add_color = glGetUniformLocation(parts_shader.shader.program, "add_color"); parts_shader.multiply_color = glGetUniformLocation(parts_shader.shader.program, "multiply_color"); + parts_shader.use_clipper = glGetUniformLocation(parts_shader.shader.program, "use_clipper"); + parts_shader.clipper_tex = glGetUniformLocation(parts_shader.shader.program, "clipper_tex"); + parts_shader.inv_clipper_transform = glGetUniformLocation(parts_shader.shader.program, "inv_clipper_transform"); } diff --git a/src/parts/save.c b/src/parts/save.c index cf26b64..6b94166 100644 --- a/src/parts/save.c +++ b/src/parts/save.c @@ -22,7 +22,7 @@ #include "parts_internal.h" #include "../hll/iarray.h" -#define CURRENT_SAVE_VERSION 2 +#define CURRENT_SAVE_VERSION 3 static void save_parts_params(struct iarray_writer *w, struct parts_params *params) { @@ -503,6 +503,7 @@ static void save_parts(struct iarray_writer *w, struct parts *parts) iarray_write(w, parts->linked_from); iarray_write(w, parts->draw_filter); iarray_write(w, parts->message_window); + iarray_write(w, parts->alpha_clipper_parts_no); unsigned motion_count_pos = iarray_writer_pos(w); iarray_write(w, 0); // size of motion list @@ -540,6 +541,8 @@ static void load_parts(struct iarray_reader *r, int version) parts->draw_filter = iarray_read(r); if (version > 0) parts->message_window = iarray_read(r); + if (version > 2) + parts->alpha_clipper_parts_no = iarray_read(r); int motion_count = iarray_read(r); for (int i = 0; i < motion_count; i++) {