Acme-MITHALDU-BleedingOpenGL
view release on metacpan or search on metacpan
0.005, 0.005,
-0.5, -0.5,
1.5, -0.5,
1.5, 1.5,
-0.5, 1.5,
0.005, 0.005,
0.995, 0.005,
0.995, 0.995,
0.005, 0.995
);
my $texcoords = OpenGL::Array->new_list(GL_FLOAT,@texcoords);
my @indices = (0..23);
my $indices = OpenGL::Array->new_list(GL_UNSIGNED_INT,@indices);
my @xform =
(
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
);
my $xform = OpenGL::Array->new_list(GL_FLOAT,@xform);
# ------
# Frames per second (FPS) statistic variables and routine.
use constant CLOCKS_PER_SEC => $hasHires ? 1000 : 1;
use constant FRAME_RATE_SAMPLES => 50;
my $FrameCount = 0;
my $FrameRate = 0;
my $last=0;
sub ourDoFPS
{
if (++$FrameCount >= FRAME_RATE_SAMPLES)
{
my $now = $hasHires ? gettimeofday() : time(); # clock();
my $delta= ($now - $last);
$last = $now;
$FrameRate = FRAME_RATE_SAMPLES / ($delta || 1);
$FrameCount = 0;
}
}
# ------
# String rendering routine; leverages on GLUT routine.
sub ourPrintString
{
my ($font, $str) = @_;
my @c = split '', $str;
for(@c)
{
glutBitmapCharacter($font, ord $_);
}
}
# ------
# Does everything needed before losing control to the main
# OpenGL event loop.
sub ourInitVertexBuffers
{
# Set initial colors for rainbow face
for (my $i=0; $i<16; $i++)
{
$rainbow[$i] = rand(1.0);
$rainbow_inc[$i] = 0.01 - rand(0.02);
}
# Initialize VBOs if supported
if ($hasVBO)
{
printf("Using VBOs\n");
($VertexObjID,$NormalObjID,$ColorObjID,$TexCoordObjID,$IndexObjID) =
glGenBuffersARB_p(5);
#glBindBufferARB(GL_ARRAY_BUFFER_ARB, $VertexObjID);
$verts->bind($VertexObjID);
glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $verts, GL_STATIC_DRAW_ARB);
glVertexPointer_c(3, GL_FLOAT, 0, 0);
if (DO_TESTS)
{
print "\nTests:\n";
my $size = glGetBufferParameterivARB_p(GL_ARRAY_BUFFER_ARB,
GL_BUFFER_SIZE_ARB);
print " Vertex Buffer Size (bytes): $size\n";
my $count = $verts->elements();
print " Vertex Buffer Size (elements): $count\n";
my $test = glGetBufferSubDataARB_p(GL_ARRAY_BUFFER_ARB,12,3,GL_FLOAT);
my @test = $test->retrieve(0,3);
my $ords = join('/',@test);
print " glGetBufferSubDataARB_p: $ords\n";
}
#glBindBufferARB(GL_ARRAY_BUFFER_ARB, $NormalObjID);
$norms->bind($NormalObjID);
glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $norms, GL_STATIC_DRAW_ARB);
glNormalPointer_c(GL_FLOAT, 0, 0);
#glBindBufferARB(GL_ARRAY_BUFFER_ARB, $ColorObjID);
$colors->bind($ColorObjID);
glBufferDataARB_p(GL_ARRAY_BUFFER_ARB, $colors, GL_DYNAMIC_DRAW_ARB);
$rainbow->assign(0,@rainbow);
glBufferSubDataARB_p(GL_ARRAY_BUFFER_ARB, $rainbow_offset, $rainbow);
glColorPointer_c(4, GL_FLOAT, 0, 0);
#glBindBufferARB(GL_ARRAY_BUFFER_ARB, $TexCoordObjID);
$texcoords->bind($TexCoordObjID);
print "Using classic Vertex Buffers\n";
glVertexPointer_p(3, $verts);
glNormalPointer_p($norms);
$colors->assign($rainbow_offset,@rainbow);
glColorPointer_p(4, $colors);
glTexCoordPointer_p(2, $texcoords);
}
print "-- done\n";
}
sub ourInit
{
my ($Width, $Height) = @_;
printf("\nUsing POGL v$Acme::MITHALDU::BleedingOpenGL::VERSION\n");
# Build texture.
($TextureID_image,$TextureID_FBO) = glGenTextures_p(2);
ourBuildTextures();
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
# Initialize shaders.
ourInitShaders();
# Initialize vertex buffers
ourInitVertexBuffers();
# Initialize rendering parameters
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
#glEnable(GL_BLEND);
# Color to clear color buffer to.
glClearColor(0.1, 0.1, 0.1, 0.0);
# Depth to clear depth buffer to; type of test.
glClearDepth(1.0);
glDepthFunc(GL_LESS);
# Enables Smooth Color Shading; try GL_FLAT for (lack of) fun.
glShadeModel(GL_SMOOTH);
# Load up the correct perspective matrix; using a callback directly.
cbResizeScene($Width, $Height);
# Set up a light, turn it on.
glLightfv_p(GL_LIGHT1, GL_POSITION, @Light_Position);
glLightfv_p(GL_LIGHT1, GL_AMBIENT, @Light_Ambient);
glLightfv_p(GL_LIGHT1, GL_DIFFUSE, @Light_Diffuse);
glEnable(GL_LIGHT1);
# A handy trick -- have surface material mirror the color.
glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}
# ------
# Function to build a simple full-color texture with alpha channel,
# and then create mipmaps.
# Also sets up FBO texture and Vertex/Fragment programs.
sub ourBuildTextures
{
my $gluerr;
my $tex;
# Build Image Texture
($TextureID_image,$TextureID_FBO) = glGenTextures_p(2);
# Use OpenGL::Image to load texture
if ($hasImage && -e $Tex_File)
{
my $img = new OpenGL::Image(source=>$Tex_File);
die $@ if $@;
my($eng,$ver) = $img->Get('engine','version');
print "Using OpenGL::Image - $eng v$ver\n";
($Tex_Width,$Tex_Height) = $img->Get('width','height');
my $alpha = $img->Get('alpha') ? 'has' : 'no';
print "Loading texture: $Tex_File, $Tex_Width x $Tex_Height, $alpha alpha\n";
($Tex_Type,$Tex_Format,$Tex_Size) =
$img->Get('gl_internalformat','gl_format','gl_type');
# Use OGA for testing
$Tex_Image = $img;
$Tex_Pixels = $img->GetArray();
print "Using ImageMagick's gaussian blur on inset\n" if ($hasIM_635);
}
# Build texture from scratch if OpenGL::Image not available
else
{
my $hole_size = 3300; # ~ == 57.45 ^ 2.
# Iterate across the texture array.
for(my $y=0; $y<$Tex_Height; $y++)
{
for(my $x=0; $x<$Tex_Width; $x++)
{
# A simple repeating squares pattern.
# Dark blue on white.
if ( ( ($x+4)%32 < 8 ) && ( ($y+4)%32 < 8))
{
$tex .= pack "C3", 0,0,120; # Dark blue
}
else
{
$tex .= pack "C3", 240, 240, 240; # White
}
# Make a round dot in the texture's alpha-channel.
# Calculate distance to center (squared).
my $t = ($x-64)*($x-64) + ($y-64)*($y-64);
if ( $t < $hole_size)
{
$tex .= pack "C", 255; # The dot itself is opaque.
}
elsif ($t < $hole_size + 100)
{
$tex .= pack "C", 128; # Give our dot an anti-aliased edge.
}
else
{
$tex .= pack "C", 0; # Outside of the dot, it's transparent.
}
}
}
$Tex_Pixels = OpenGL::Array->new_scalar(GL_UNSIGNED_BYTE,$tex,length($tex));
$Tex_Type = GL_RGBA8;
$Tex_Format = GL_RGBA;
$Tex_Size = GL_UNSIGNED_BYTE;
}
glBindTexture(GL_TEXTURE_2D, $TextureID_image);
# Use MipMap
if ($useMipMap)
{
print "Using Mipmap\n";
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST_MIPMAP_LINEAR);
# The GLU library helps us build MipMaps for our texture.
if (($gluerr = gluBuild2DMipmaps_c(GL_TEXTURE_2D, $Tex_Type,
$Tex_Width, $Tex_Height, $Tex_Format, $Tex_Size,
$Tex_Pixels->ptr())))
{
printf STDERR "GLULib%s\n", gluErrorString($gluerr);
exit(-1);
}
}
# Use normal texture - Note: dimensions must be power of 2
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D_c(GL_TEXTURE_2D, 0, $Tex_Type, $Tex_Width, $Tex_Height,
0, $Tex_Format, $Tex_Size, $Tex_Pixels->ptr());
}
# Benchmarks for Image Loading
if (DO_TESTS && $hasIM)
{
my $loops = 1000;
my $im = new Image::Magick();
$im->Read($Tex_File);
$im->Set(magick=>'RGBA',depth=>8);
$im->Negate(channel=>'alpha');
# Bench ImageToBlob
my $start = gettimeofday();
for (my $i=0;$i<$loops;$i++)
{
my($blob) = $im->ImageToBlob();
glTexImage2D_s(GL_TEXTURE_2D, 0, GL_RGBA8, $Tex_Width, $Tex_Height,
0, GL_RGBA, GL_UNSIGNED_BYTE, $blob);
}
my $now = gettimeofday();
my $fps = $loops / ($now - $start);
print "ImageToBlob + glTexImage2D_s: $fps\n";
# Bench GetPixels
$start = gettimeofday();
for (my $i=0;$i<$loops;$i++)
{
my @pixels = $im->GetPixels(map=>'BGRA',
width=>$Tex_Width, height=>$Tex_Height, normalize=>'false');
glTexImage2D_p(GL_TEXTURE_2D, 0, $Tex_Type, $Tex_Width, $Tex_Height,
0, $Tex_Format, $Tex_Size, @pixels);
}
$now = gettimeofday();
$fps = $loops / ($now - $start);
print "GetPixels + glTexImage2D_p: $fps\n";
# Bench OpenGL::Image
if ($hasIM_635)
{
my $start = gettimeofday();
for (my $i=0;$i<$loops;$i++)
{
glTexImage2D_c(GL_TEXTURE_2D, 0, $Tex_Type, $Tex_Width, $Tex_Height,
0, $Tex_Format, $Tex_Size, $Tex_Pixels->ptr());
}
my $now = gettimeofday();
my $fps = $loops / ($now - $start);
print "OpenGL::Image + glTexImage2D_c: $fps\n";
}
}
# Build FBO texture
if ($hasFBO)
{
printf("Using FBOs\n");
($FrameBufferID) = glGenFramebuffersEXT_p(1);
($RenderBufferID) = glGenRenderbuffersEXT_p(1);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, $FrameBufferID);
glBindTexture(GL_TEXTURE_2D, $TextureID_FBO);
# Initiate texture
glTexImage2D_c(GL_TEXTURE_2D, 0, $Tex_Type, $Tex_Width, $Tex_Height,
0, $Tex_Format, $Tex_Size, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
# Bind texture/frame/render buffers
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, $TextureID_FBO, 0);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, $RenderBufferID);
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24_ARB,
$Tex_Width, $Tex_Height);
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_RENDERBUFFER_EXT, $RenderBufferID);
# Test status
if (DO_TESTS)
{
my $stat = glCheckFramebufferStatusEXT(GL_RENDERBUFFER_EXT);
printf("FBO Status: %04X\n",$stat);
}
}
# Select active texture
{
glDisable(GL_LIGHTING);
}
if ($Alpha_Add)
{
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
}
else
{
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
}
# If we're blending, we don'$t want z-buffering.
if ($Blend_On)
{
glDisable(GL_DEPTH_TEST);
}
else
{
glEnable(GL_DEPTH_TEST);
}
# Need to manipulate the ModelView matrix to move our model around.
glMatrixMode(GL_MODELVIEW);
# Reset to 0,0,0; no rotation, no scaling.
glLoadIdentity();
# Move the object back from the screen.
glTranslatef(0.0,0.0,$Z_Off);
# Rotate the calculated amount.
glRotatef($X_Rot,1.0,0.0,0.0);
glRotatef($Y_Rot,0.0,1.0,0.0);
# Clear the color and depth buffers.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
# Update Rainbow Cube Face
for (my $i=0; $i<scalar(@rainbow); $i++)
{
$rainbow[$i] += $rainbow_inc[$i];
if ($rainbow[$i] < 0)
{
$rainbow[$i] = 0.0;
}
elsif ($rainbow[$i] > 1)
{
$rainbow[$i] = 1.0;
}
else
{
next;
}
$rainbow_inc[$i] = -$rainbow_inc[$i];
}
if ($hasVBO)
{
glBindBufferARB(GL_ARRAY_BUFFER_ARB, $ColorObjID);
my $color_map = glMapBufferARB_p(GL_ARRAY_BUFFER_ARB,
GL_WRITE_ONLY_ARB,GL_FLOAT);
my $buffer = glGetBufferPointervARB_p(GL_ARRAY_BUFFER_ARB,
GL_BUFFER_MAP_POINTER_ARB,GL_FLOAT);
$color_map->assign($rainbow_offset,@rainbow);
glUnmapBufferARB(GL_ARRAY_BUFFER_ARB);
}
else
{
$colors->assign($rainbow_offset,@rainbow);
glColorPointer_p(4, $colors);
}
# Render cube
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
for (my $i=0; $i<scalar(@indices); $i+=4)
{
glDrawArrays(GL_QUADS, $i, 4);
}
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
# Move back to the origin (for the text, below).
glLoadIdentity();
# We need to change the projection matrix for the text rendering.
glMatrixMode(GL_PROJECTION);
# But we like our current view too; so we save it here.
glPushMatrix();
# Now we set up a new projection for the text.
glLoadIdentity();
glOrtho(0,$Window_Width,0,$Window_Height,-1.0,1.0);
# Lit or textured text looks awful.
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
# We don'$t want depth-testing either.
glDisable(GL_DEPTH_TEST);
# But, for fun, let's make the text partially transparent too.
glColor4f(0.6,1.0,0.6,.75);
$buf = sprintf "TIME TO EXIT: %.1fs", $time_to_exit;
my $bufwidth = 6 * length $buf;
glRasterPos2i($Window_Width-4-$bufwidth,2); ourPrintString(GLUT_BITMAP_HELVETICA_12,$buf);
# Render our various display mode settings.
$buf = sprintf "Mode: %s", $TexModesStr[$Curr_TexMode];
glRasterPos2i(2,2); ourPrintString(GLUT_BITMAP_HELVETICA_12,$buf);
$buf = sprintf "Alpha: %d", $Alpha_Add;
glRasterPos2i(2,14); ourPrintString(GLUT_BITMAP_HELVETICA_12,$buf);
$buf = sprintf "Blend: %d", $Blend_On;
( run in 0.648 second using v1.01-cache-2.11-cpan-39bf76dae61 )