/usr/share/perl5/Dizzy/TextureSwitcher/Blend.pm is in dizzy 0.3-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | package Dizzy::TextureSwitcher::Blend;
use strict;
use warnings;
use OpenGL qw(:all);
use Math::Trig;
use Time::HiRes qw(time);
use Dizzy::TextureGenerator;
use Dizzy::Handlers;
use Dizzy::GLFeatures;
my $blend_params = undef; # parameters of original texture_switch request
my $blend_start; # time at which current blend was started
my $blend_texture; # texture ID used for intermediate textures
my $blend_duration = 0;
# saved parameters
my $shader_prog;
# blend function to use
my $func_init;
my $func_blend;
sub handler_init_switch {
my %args = @_;
# check here if we are currently blending. if we are, STOP.
if (defined($blend_params)) {
print "*** Cannot switch to different texture, because Dizzy is blending right now.\n";
return Dizzy::Handlers::STOP;
}
# else:
$blend_params = \%args;
$blend_start = time;
Dizzy::Handlers::STOP;
}
# ******************************* SOFTWARE ***********************************
sub software_init {
$blend_texture = Dizzy::TextureGenerator::create_texture();
}
# software blend two textures into a third one
sub software_blend {
my ($tex_a, $tex_b, $ratio) = @_;
# $tex_a = first GL texture ID
# $tex_b = second GL texture ID
# $ratio = 0.0 .. 1.0 (0.0 = 100% A 0% B, 1.0 = 0% A 100% B)
# retrieve the two textures to be blended
my (@data_a, @data_b);
glBindTexture(GL_TEXTURE_2D, $tex_a);
@data_a = glGetTexImage_p(GL_TEXTURE_2D, 0, GL_LUMINANCE, GL_FLOAT);
glBindTexture(GL_TEXTURE_2D, $tex_b);
@data_b = glGetTexImage_p(GL_TEXTURE_2D, 0, GL_LUMINANCE, GL_FLOAT);
# also retrieve their dimensions (as the program always uses squares, one
# dimension suffices)
my $res = glGetTexLevelParameteriv_p(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH);
# blend the two textures
my $target_data;
while (@data_a > 0) {
$target_data .= pack("f", shift(@data_a) * (1 - $ratio) + shift(@data_b) * $ratio);
}
# now load the blended image into the intermediate texture
glBindTexture(GL_TEXTURE_2D, $blend_texture);
glTexImage2D_s(
GL_TEXTURE_2D,
0,
GL_LUMINANCE,
$res, $res,
0,
GL_LUMINANCE,
GL_FLOAT,
$target_data
);
}
# ********************************** GLSL ************************************
sub glsl_init {
my $fragment_id = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
glShaderSourceARB_p($fragment_id, << "__END_SHADER__");
uniform sampler2D Texture0;
uniform sampler2D Texture1;
uniform float BlendFactor;
void main() {
vec4 texel0 = texture2D(Texture0, gl_TexCoord[0].xy);
vec4 texel1 = texture2D(Texture1, gl_TexCoord[1].xy);
gl_FragColor.rgb = gl_Color.rgb * mix(texel0, texel1, BlendFactor).r;
gl_FragColor.a = 1.0;
}
__END_SHADER__
glCompileShaderARB($fragment_id);
if (!glGetObjectParameterivARB_p($fragment_id, GL_OBJECT_COMPILE_STATUS_ARB)) {
my $stat = glGetInfoLogARB_p($fragment_id);
die("Shader compilation failed: $stat - dying");
}
$shader_prog = glCreateProgramObjectARB();
glAttachObjectARB($shader_prog, $fragment_id);
glLinkProgramARB($shader_prog);
if (!glGetObjectParameterivARB_p($shader_prog, GL_OBJECT_LINK_STATUS_ARB)) {
my $stat = glGetInfoLogARB_p($shader_prog);
die("Failed to link shader program: $stat - dying");
}
glUseProgramObjectARB($shader_prog);
glUniform1iARB(glGetUniformLocationARB_p($shader_prog, "Texture0"), 0);
glUniform1iARB(glGetUniformLocationARB_p($shader_prog, "Texture1"), 1);
}
sub glsl_blend {
my ($tex_a, $tex_b, $ratio) = @_;
# activate shader (in case it didn't happen already)
glUseProgramObjectARB($shader_prog);
# load the textures
glActiveTextureARB(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, $tex_a);
glActiveTextureARB(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, $tex_b);
# set the blend factor
glUniform1fARB(glGetUniformLocationARB_p($shader_prog, "BlendFactor"), $ratio);
}
# ******************************** HANDLERS **********************************
# this routine generates and activates intermediate textures
# if there is a blend in progress right now.
# it also sets off necessary events once the blend is finished.
sub handler_render {
if (defined($blend_params)) {
# blend the texture. calculate the ratio first
my $ratio = (time() - $blend_start) / $blend_duration;
# decide if we are done, or if we need to generate an intermediate image
# (assert we are done if the source and target match, so we don't block
# on program start)
if ($ratio < 1.0 and $blend_params->{old_gl_texture} != $blend_params->{gl_texture}) {
$func_blend->(
$blend_params->{old_gl_texture},
$blend_params->{gl_texture},
$ratio,
);
} else {
glBindTexture(GL_TEXTURE_2D, $blend_params->{gl_texture});
Dizzy::Handlers::invoke("texture_switched", %{$blend_params});
$blend_params = undef;
}
}
Dizzy::Handlers::GO_ON;
}
sub select_render_path {
if (Dizzy::GLFeatures::supports("glsl")) {
print "TexBlend: will use fast GLSL shaders for blending :-)\n";
$func_init = \&glsl_init;
$func_blend = \&glsl_blend;
} else {
print "TexBlend: GLSL not supported, falling back to slow software blending :-(\n";
$func_init = \&software_init;
$func_blend = \&software_blend;
}
}
sub init {
my %args = @_;
$blend_duration = $args{duration} || 2;
# allocate a texture for blends
$blend_texture = Dizzy::TextureGenerator::create_texture();
# select and initialize render path
select_render_path();
$func_init->();
Dizzy::Handlers::register(
texture_switch => \&handler_init_switch,
render => \&handler_render,
);
}
1;
|