Merge pull request #336 from kichikuou/draw_filter

Parts: support and fix multiply/screen draw_filter
This commit is contained in:
Nunuhara Cabbage
2026-05-03 07:54:48 -07:00
committed by GitHub
4 changed files with 59 additions and 37 deletions
+24 -9
View File
@@ -20,6 +20,7 @@ uniform vec2 bot_left;
uniform vec2 top_right;
uniform vec3 add_color;
uniform vec3 multiply_color;
uniform int draw_filter;
uniform int use_clipper;
uniform sampler2D clipper_tex;
@@ -28,23 +29,37 @@ in vec2 tex_coord;
in vec2 clip_coord;
out vec4 frag_color;
float point_in_rect(vec2 p, vec2 bot_left, vec2 top_right) {
vec2 s = step(bot_left, p) - step(top_right, p);
return s.x * s.y;
const int DRAW_FILTER_MULTIPLY = 2;
const int DRAW_FILTER_SCREEN = 3;
bool inside_rect(vec2 p, vec2 bl, vec2 tr) {
return all(greaterThanEqual(p, bl)) && all(lessThan(p, tr));
}
void main() {
vec2 size = vec2(textureSize(tex, 0));
vec2 bl = bot_left / size;
vec2 tr = top_right / size;
vec2 size = vec2(textureSize(tex, 0));
if (!inside_rect(tex_coord, bot_left / size, top_right / size))
discard;
vec4 tex_color = texture(tex, tex_coord);
vec3 mod_color = (tex_color.rgb + add_color) * multiply_color;
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));
if (!inside_rect(clip_coord, vec2(0.0), vec2(1.0)))
discard;
alpha *= texture(clipper_tex, clip_coord).a;
}
frag_color = vec4(mod_color, alpha) * point_in_rect(tex_coord, bl, tr);
if (draw_filter == DRAW_FILTER_MULTIPLY) {
// result = mix(dst, mod_color*dst, alpha), used with (GL_DST_COLOR, GL_ZERO)
frag_color = vec4(mix(vec3(1.0), mod_color, alpha), 1.0);
} else if (draw_filter == DRAW_FILTER_SCREEN) {
// result = mod_color*alpha + (1 - mod_color*alpha)*dst,
// used with (GL_ONE, GL_ONE_MINUS_SRC_COLOR)
frag_color = vec4(mod_color * alpha, 1.0);
} else {
// normal or additive — blend func handles alpha
frag_color = vec4(mod_color, alpha);
}
}
-2
View File
@@ -1728,8 +1728,6 @@ void PE_SetAlpha(int parts_no, int alpha)
void PE_SetPartsDrawFilter(int parts_no, int draw_filter)
{
if (draw_filter && draw_filter != 1)
UNIMPLEMENTED("(%d, %d)", parts_no, draw_filter);
parts_get(parts_no)->draw_filter = draw_filter;
}
+7
View File
@@ -265,6 +265,13 @@ enum parts_flash_blend_mode {
PARTS_FLASH_BLEND_HARDLIGHT = 14,
};
enum parts_draw_filter {
PARTS_DRAW_FILTER_NORMAL = 0,
PARTS_DRAW_FILTER_ADDITIVE = 1,
PARTS_DRAW_FILTER_MULTIPLY = 2,
PARTS_DRAW_FILTER_SCREEN = 3,
};
struct parts_flash_object {
TAILQ_ENTRY(parts_flash_object) entry;
uint16_t depth;
+28 -26
View File
@@ -46,12 +46,30 @@ static struct {
GLint top_right;
GLint add_color;
GLint multiply_color;
GLint draw_filter;
GLint use_clipper;
GLint clipper_tex;
GLint inv_clipper_transform;
} parts_shader;
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)
static void set_draw_filter_blend_func(int draw_filter)
{
switch (draw_filter) {
case PARTS_DRAW_FILTER_ADDITIVE:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
case PARTS_DRAW_FILTER_MULTIPLY:
glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
break;
case PARTS_DRAW_FILTER_SCREEN:
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
break;
default:
break;
}
}
static void parts_render_texture(struct texture *texture, mat4 mw_transform, Rectangle *rect, float blend_rate, vec3 add_color, vec3 multiply_color, int draw_filter, int alpha_clipper)
{
mat4 wv_transform = WV_TRANSFORM(config.view_width, config.view_height);
@@ -70,6 +88,7 @@ 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);
glUniform1i(parts_shader.draw_filter, draw_filter);
struct parts *clipper = alpha_clipper ? parts_try_get(alpha_clipper) : NULL;
if (clipper) {
@@ -121,7 +140,7 @@ static void parts_render_text(struct parts *parts, struct parts_text *t)
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);
parts_render_texture(&ch->t, mw_transform, &r, blend_rate, add_color, multiply_color, 0, parts->alpha_clipper_parts_no);
x += ch->advance;
}
x = parts->global.pos.x + t->common.origin_offset.x;
@@ -131,13 +150,7 @@ static void parts_render_text(struct parts *parts, struct parts_text *t)
static void parts_render_cg(struct parts *parts, struct parts_common *common)
{
switch (parts->draw_filter) {
case 1:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
default:
break;
}
set_draw_filter_blend_func(parts->draw_filter);
mat4 mw_transform = GLM_MAT4_IDENTITY_INIT;
glm_translate(mw_transform, (vec3) { parts->global.pos.x, parts->global.pos.y, 0 });
@@ -164,7 +177,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->alpha_clipper_parts_no);
parts_render_texture(&common->texture, mw_transform, &r, parts->global.alpha / 255.0, add_color, multiply_color, parts->draw_filter, parts->alpha_clipper_parts_no);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
}
@@ -206,19 +219,7 @@ static void render_flat_item(struct parts *parts, struct parts_flat *f,
return;
Texture *tex = &f->textures[lib_idx];
switch (key->draw_filter) {
case 1: // additive
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
case 2: // multiply
glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
break;
case 3: // screen
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
break;
default:
break;
}
set_draw_filter_blend_func(key->draw_filter);
mat4 render_m;
glm_mat4_copy(combined, render_m);
@@ -234,9 +235,9 @@ static void render_flat_item(struct parts *parts, struct parts_flat *f,
vec3 add_color = { key->add_r / 255.0f, key->add_g / 255.0f, key->add_b / 255.0f };
vec3 mul_color = { key->mul_r / 255.0f, key->mul_g / 255.0f, key->mul_b / 255.0f };
parts_render_texture(tex, render_m, &rect, alpha, add_color, mul_color,
parts->alpha_clipper_parts_no);
key->draw_filter, parts->alpha_clipper_parts_no);
if (key->draw_filter != 0)
if (key->draw_filter != PARTS_DRAW_FILTER_NORMAL)
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
break;
}
@@ -329,7 +330,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->alpha_clipper_parts_no);
parts_render_texture(src, mw_transform, &r, blend_rate, add_color, multiply_color, 0, 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)
@@ -502,6 +503,7 @@ void parts_render_init(void)
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.draw_filter = glGetUniformLocation(parts_shader.shader.program, "draw_filter");
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");