#!/usr/bin/perl
our
$VERSION
=
'0.1.0'
;
my
$width
= 1000;
my
$height
= 1000;
my
(
$frames
,
$start
);
my
(
$window
,
$teapot
);
my
(
$shader
,
$shader_enabled
);
go();
sub
go {
print
"Press 'Q' or 'Esc' to exit, or any other key to toggle shader.\n"
;
glutInit;
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(
$width
,
$height
);
$window
= glutCreateWindow(
'Shader Test'
);
glutIdleFunc (\
&cb_draw
);
glutDisplayFunc (\
&cb_draw
);
glutKeyboardFunc(\
&cb_keyboard
);
$shader
= new OpenGL::Shader(
'GLSL'
);
die
"This program requires support for GLSL shaders.\n"
unless
$shader
;
my
$fragment
= fragment_shader();
my
$vertex
= vertex_shader();
my
$info
=
$shader
->Load(
$fragment
,
$vertex
);
print
$info
if
$info
;
toggle_shader();
$teapot
= glGenLists(1);
glNewList(
$teapot
, GL_COMPILE);
glutSolidTeapot(1);
glEndList;
glViewport(0, 0,
$width
,
$height
);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluPerspective(90,
$width
/
$height
, 1, 10);
glMatrixMode(GL_MODELVIEW);
glShadeModel(GL_SMOOTH);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glLightfv_p(GL_LIGHT0, GL_POSITION, 4, 4, 4, 1);
glMaterialfv_p(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, 1, .7, .7, 1);
glMaterialfv_p(GL_FRONT_AND_BACK, GL_SPECULAR, 1, 1, 1, 1);
glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 50 );
$start
=
time
;
glutMainLoop;
}
sub
cb_draw {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity;
glTranslatef(0, 0, -3);
my
$slow_time
=
time
/ 5;
my
$frac_time
=
$slow_time
-
int
$slow_time
;
my
$angle
=
$frac_time
* 360;
glRotatef(
$angle
, 0, 1, 0);
glRotatef(30, 1, 0, 0);
glCallList(
$teapot
);
glutSwapBuffers;
$frames
++;
}
sub
cb_keyboard {
my
$key
=
shift
;
my
$chr
=
lc
chr
$key
;
if
(
$key
== 27 or
$chr
eq
'q'
) {
my
$time
=
time
-
$start
;
my
$fps
=
$frames
/
$time
;
printf
"%.3f FPS\n"
,
$fps
;
glutDestroyWindow(
$window
);
exit
(0);
}
else
{
toggle_shader();
}
}
sub
toggle_shader {
$shader_enabled
= !
$shader_enabled
;
$shader_enabled
?
$shader
->Enable :
$shader
->Disable;
}
sub
vertex_shader {
return
<<'VERTEX';
varying vec3 Normal;
varying vec3 Position;
void main(void) {
gl_Position = ftransform();
Position = vec3(gl_ModelViewMatrix * gl_Vertex);
Normal = gl_NormalMatrix * gl_Normal;
}
VERTEX
}
sub
fragment_shader {
return
<<'FRAGMENT';
varying vec3 Position;
varying vec3 Normal;
void main(void) {
vec3 normal = normalize(Normal);
vec3 reflected = normalize(reflect(Position, normal));
vec3 light_dir = normalize(vec3(gl_LightSource[0].position) - Position);
float diffuse = max (dot(light_dir, normal ), 0.0);
float spec = clamp(dot(light_dir, reflected), 0.0, 1.0);
spec = pow (spec, gl_FrontMaterial.shininess);
gl_FragColor = gl_FrontLightModelProduct.sceneColor
+ gl_FrontLightProduct[0].ambient
+ diffuse * gl_FrontLightProduct[0].diffuse
+ spec * gl_FrontLightProduct[0].specular;
}
FRAGMENT
}