///|
let image_material_fragment_shader : String =
#|#version 330
#|in vec2 fragTexCoord;
#|in vec4 fragColor;
#|uniform sampler2D texture0;
#|uniform vec4 effect;
#|uniform vec4 shadowColor;
#|uniform vec4 shadowData;
#|uniform vec4 uvBounds;
#|out vec4 finalColor;
#|bool insideBounds(vec2 uv) {
#| return all(greaterThanEqual(uv, uvBounds.xy)) &&
#| all(lessThanEqual(uv, uvBounds.zw));
#|}
#|float sourceAlpha(vec2 uv) {
#| return insideBounds(uv) ? texture(texture0, uv).a : 0.0;
#|}
#|void main() {
#| float shadowAlpha = 0.0;
#| if (effect.w > 0.5) {
#| vec2 center = fragTexCoord - shadowData.xy;
#| for (int y = -2; y <= 2; y++) {
#| for (int x = -2; x <= 2; x++) {
#| vec2 delta = vec2(float(x), float(y)) * shadowData.zw * 0.5;
#| shadowAlpha += sourceAlpha(center + delta);
#| }
#| }
#| shadowAlpha *= 0.04 * shadowColor.a * effect.x * fragColor.a;
#| }
#| vec4 source = vec4(0.0);
#| if (insideBounds(fragTexCoord)) {
#| source = texture(texture0, fragTexCoord) * fragColor;
#| float luma = dot(source.rgb, vec3(0.2126, 0.7152, 0.0722));
#| source.rgb = mix(vec3(luma), source.rgb, effect.z) * effect.y;
#| source.a *= effect.x;
#| }
#| vec4 shadow = vec4(shadowColor.rgb, shadowAlpha);
#| float outAlpha = source.a + shadow.a * (1.0 - source.a);
#| vec3 outRgb = outAlpha > 0.000001
#| ? (source.rgb * source.a + shadow.rgb * shadow.a * (1.0 - source.a)) / outAlpha
#| : vec3(0.0);
#| finalColor = vec4(outRgb, outAlpha);
#|}
///|
fn get_image_material_shader_state() -> ImageMaterialShaderState {
if backend.image_material_shader is Some(state) {
return state
}
let shader = @raylib.load_shader_from_memory(
"", image_material_fragment_shader,
)
let state : ImageMaterialShaderState = {
shader,
effect_loc: @raylib.get_shader_location(shader, "effect"),
shadow_color_loc: @raylib.get_shader_location(shader, "shadowColor"),
shadow_data_loc: @raylib.get_shader_location(shader, "shadowData"),
uv_bounds_loc: @raylib.get_shader_location(shader, "uvBounds"),
}
backend.image_material_shader = Some(state)
state
}
///|
fn image_material_vec4(
x : Double,
y : Double,
z : Double,
w : Double,
) -> @raylib.ShaderUniformData {
Vec4(@raylib.Vector4::new(to_float(x), to_float(y), to_float(z), to_float(w)))
}
///|
fn draw_image_material_quad(
texture : @raylib.Texture,
command : @render2d_types.ImageMaterialDrawCommand2D,
flip_y : Bool,
) -> Unit {
let image = command.image
let texture_width = @raylib.get_texture_width(texture).to_double()
let texture_height = @raylib.get_texture_height(texture).to_double()
let (src_x, src_y, src_w, src_h) = match image.source {
Some(source) =>
(source.position[X], source.position[Y], source.size[X], source.size[Y])
None => (0.0, 0.0, texture_width, texture_height)
}
let dest_w = image.destination.size[X]
let dest_h = image.destination.size[Y]
if src_w <= 0.0 || src_h <= 0.0 || dest_w <= 0.0 || dest_h <= 0.0 {
return
}
let shadow = command.drop_shadow
let offset = shadow
.map(fn(value) { value.offset })
.unwrap_or(@smath.Vec2::zero())
let blur = shadow.map(fn(value) { value.blur_radius }).unwrap_or(0.0)
let left = blur * 2.0 + (-offset[X]).max(0.0)
let top = blur * 2.0 + (-offset[Y]).max(0.0)
let right = blur * 2.0 + offset[X].max(0.0)
let bottom = blur * 2.0 + offset[Y].max(0.0)
let u0 = src_x / texture_width
let raw_v0 = src_y / texture_height
let u1 = (src_x + src_w) / texture_width
let raw_v1 = (src_y + src_h) / texture_height
let (v0, v1) = if flip_y {
(1.0 - raw_v0, 1.0 - raw_v1)
} else {
(raw_v0, raw_v1)
}
let uv_width = u1 - u0
let uv_height = v1 - v0
let eu0 = u0 - left / dest_w * uv_width
let ev0 = v0 - top / dest_h * uv_height
let eu1 = u1 + right / dest_w * uv_width
let ev1 = v1 + bottom / dest_h * uv_height
let (bu0, bv0) = transform_uv_point(image.uv_transform, u0, v0)
let (bu1, bv1) = transform_uv_point(image.uv_transform, u1, v1)
let uv00 = transform_uv_point(image.uv_transform, eu0, ev0)
let uv10 = transform_uv_point(image.uv_transform, eu1, ev0)
let uv11 = transform_uv_point(image.uv_transform, eu1, ev1)
let uv01 = transform_uv_point(image.uv_transform, eu0, ev1)
let state = get_image_material_shader_state()
set_shader_uniform(
state.shader,
state.effect_loc,
image_material_vec4(
command.opacity,
command.brightness,
command.saturation,
if shadow is Some(_) {
1.0
} else {
0.0
},
),
)
set_shader_uniform(
state.shader,
state.shadow_color_loc,
shadow
.map(fn(value) { uniform_color4(value.color) })
.unwrap_or(image_material_vec4(0.0, 0.0, 0.0, 0.0)),
)
set_shader_uniform(
state.shader,
state.shadow_data_loc,
image_material_vec4(
offset[X] / dest_w * uv_width,
offset[Y] / dest_h * uv_height,
blur / dest_w * uv_width,
blur / dest_h * uv_height,
),
)
set_shader_uniform(
state.shader,
state.uv_bounds_loc,
image_material_vec4(
bu0.to_double().min(bu1.to_double()),
bv0.to_double().min(bv1.to_double()),
bu0.to_double().max(bu1.to_double()),
bv0.to_double().max(bv1.to_double()),
),
)
state.shader.begin_mode()
draw_affine_textured_quad(
texture,
uv00,
uv10,
uv11,
uv01,
-left,
-top,
dest_w + right,
dest_h + bottom,
image.destination.position[X],
image.destination.position[Y],
image.transform,
image.color,
)
@raylib.end_shader_mode()
}