#!/usr/bin/perl
# This code is based on the code by Jeff Molofee '99
# and ported to SDL by Sam Lantinga '2000
# Original ported to Perl/SDL by Wayne Keenan '2000
# And updated by David Goehrig '02
#
#
# Jeff's tutorials can be found at www.demonews.com/hosted/nehe
use strict;
use Getopt::Long;
use Data::Dumper;
use Benchmark;
use SDL;
use SDL::App;
use SDL::OpenGL;
use SDL::Event;
use SDL::Surface;
use SDL::OpenGL;
my $arg_screen_width =640;
my $arg_screen_height=512;
my $arg_fullscreen=0;
GetOptions(
"width:i" => \$arg_screen_width,
"height:i" => \$arg_screen_height,
"fullscreen!" => \$arg_fullscreen,
) or die $!;
############################################################
my $light = 0;
my $xrot=0; # x rotation
my $yrot=0; # y rotation
my $xspeed=0; # x rotation speed
my $yspeed=0; # y rotation speed
my $z=-5.0; # depth into the screen.
my $filter = 1; # Which Filter To Use (nearest/linear/mipmapped) */
main();
exit;
sub main
{
my $done=0;
my $vidmode_flags= SDL_OPENGL;
$vidmode_flags|= SDL_FULLSCREEN if $arg_fullscreen;
my $app = new SDL::App ( -title => "Jeff Molofee's GL Code Tutorial ... NeHe '99",
-icon => "icon.png",
-flags => $vidmode_flags,
-width => $arg_screen_width,
-height =>$arg_screen_height,
-opengl => 1,
);
SDL::ShowCursor(0);
my $event = new SDL::Event;
$event->set(SDL_SYSWMEVENT,SDL_IGNORE);
InitGL($arg_screen_width, $arg_screen_height);
while ( not $done )
{
DrawGLScene();
$app->sync();
$event->pump;
$event->poll;
$done = 1 if ( $event->type == SDL_QUIT ) ;
if ( $event->type == SDL_KEYDOWN )
{
my $key= $event->key_sym;
$done = 1 if ( $key == SDLK_ESCAPE ) ;
if ($key==SDLK_l)
{
printf("Light was: %d\n", $light);
$light = $light ? 0 : 1; # switch the current value of light, between 0 and 1.
printf("Light is now: %d\n", $light);
if (!$light)
{
glDisable(GL_LIGHTING);
}
else
{
glEnable(GL_LIGHTING);
}
}
if ($key==SDLK_f)
{
printf("Filter was: %d\n", $filter);
$filter = 1+(($filter) % 3) ;
printf("Filter is now: %d\n", $filter);
}
#bit lax:
$z-=0.02 if ( $key == SDLK_PAGEUP );
$z+=0.02 if ( $key == SDLK_PAGEDOWN );
$xspeed+=0.02 if ( $key == SDLK_UP );
$xspeed-=0.02 if ( $key == SDLK_DOWN );
$yspeed-=0.01 if ( $key == SDLK_LEFT );
$yspeed+=0.01 if ( $key == SDLK_RIGHT );
}
}
}
#########################################################################
#Pretty much in original form, but 'Perlised'
sub InitGL
{
my ($Width, $Height) = @_;
glViewport(0, 0, $Width, $Height);
LoadGLTextures(); # Load The Texture(s)
glEnable(GL_TEXTURE_2D); # Enable Texture Mapping
glClearColor(0.0, 0.0, 0.0, 0.0); # This Will Clear The Background Color To Black
glClearDepth(1.0); # Enables Clearing Of The Depth Buffer
glDepthFunc(GL_LESS); # The Type Of Depth Test To Do
glEnable(GL_DEPTH_TEST); # Enables Depth Testing
glShadeModel(GL_SMOOTH); # Enables Smooth Color Shading
glMatrixMode(GL_PROJECTION);
glLoadIdentity(); # Reset The Projection Matrix
gluPerspective(45.0, $Width/$Height, 0.1, 100.0); # Calculate The Aspect Ratio Of The Window
glMatrixMode(GL_MODELVIEW);
my $LightAmbient = [ 0.5, 0.5, 0.5, 1.0 ]; # white ambient light at half intensity (rgba) */
my $LightDiffuse = [ 1.0, 1.0, 1.0, 1.0 ]; # super bright, full intensity diffuse light. */
my $LightPosition = [ 0.0 , 0.0, 2.0, 1.0 ]; # position of light (x, y, z, (position of light)) */
#hmm, undefine:
glLight(GL_LIGHT1, GL_AMBIENT, @$LightAmbient); # add lighting. (ambient)
glLight(GL_LIGHT1, GL_DIFFUSE, @$LightDiffuse); # add lighting. (diffuse).
glLight(GL_LIGHT1, GL_POSITION,@$LightPosition); # set light position.
glEnable(GL_LIGHT1); # turn light 1 on.
}
# The main drawing function.
sub DrawGLScene
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); # Clear The Screen And The Depth Buffer
glLoadIdentity(); # Reset The View
glTranslate(0.0,0.0,$z); # move z units out from the screen.
glRotate($xrot,1.0,0.0,0.0); # Rotate On The X Axis
glRotate($yrot,0.0,1.0,0.0); # Rotate On The Y Axis
glBindTexture(GL_TEXTURE_2D, $filter); # choose the texture to use.
glBegin(GL_QUADS); # begin drawing a cube
# Front Face (note that the texture's corners have to match the quad's corners)
glNormal( 0.0, 0.0, 1.0); # front face points out of the screen on z.
glTexCoord(0.0, 0.0); glVertex(-1.0, -1.0, 1.0); # Bottom Left Of The Texture and Quad
glTexCoord(1.0, 0.0); glVertex( 1.0, -1.0, 1.0); # Bottom Right Of The Texture and Quad
glTexCoord(1.0, 1.0); glVertex( 1.0, 1.0, 1.0); # Top Right Of The Texture and Quad
glTexCoord(0.0, 1.0); glVertex(-1.0, 1.0, 1.0); # Top Left Of The Texture and Quad
# Back Face
glNormal( 0.0, 0.0,-1.0); # back face points into the screen on z.
glTexCoord(1.0, 0.0); glVertex(-1.0, -1.0, -1.0); # Bottom Right Of The Texture and Quad
glTexCoord(1.0, 1.0); glVertex(-1.0, 1.0, -1.0); # Top Right Of The Texture and Quad
glTexCoord(0.0, 1.0); glVertex( 1.0, 1.0, -1.0); # Top Left Of The Texture and Quad
glTexCoord(0.0, 0.0); glVertex( 1.0, -1.0, -1.0); # Bottom Left Of The Texture and Quad
# Top Face
glNormal( 0.0, 1.0, 0.0); # top face points up on y.
glTexCoord(0.0, 1.0); glVertex(-1.0, 1.0, -1.0); # Top Left Of The Texture and Quad
glTexCoord(0.0, 0.0); glVertex(-1.0, 1.0, 1.0); # Bottom Left Of The Texture and Quad
glTexCoord(1.0, 0.0); glVertex( 1.0, 1.0, 1.0); # Bottom Right Of The Texture and Quad
glTexCoord(1.0, 1.0); glVertex( 1.0, 1.0, -1.0); # Top Right Of The Texture and Quad
# Bottom Face
glNormal( 0.0, -1.0, 0.0); # bottom face points down on y.
glTexCoord(1.0, 1.0); glVertex(-1.0, -1.0, -1.0); # Top Right Of The Texture and Quad
glTexCoord(0.0, 1.0); glVertex( 1.0, -1.0, -1.0); # Top Left Of The Texture and Quad
glTexCoord(0.0, 0.0); glVertex( 1.0, -1.0, 1.0); # Bottom Left Of The Texture and Quad
glTexCoord(1.0, 0.0); glVertex(-1.0, -1.0, 1.0); # Bottom Right Of The Texture and Quad
# Right face
glNormal( 1.0, 0.0, 0.0); # right face points right on x.
glTexCoord(1.0, 0.0); glVertex( 1.0, -1.0, -1.0); # Bottom Right Of The Texture and Quad
glTexCoord(1.0, 1.0); glVertex( 1.0, 1.0, -1.0); # Top Right Of The Texture and Quad
glTexCoord(0.0, 1.0); glVertex( 1.0, 1.0, 1.0); # Top Left Of The Texture and Quad
glTexCoord(0.0, 0.0); glVertex( 1.0, -1.0, 1.0); # Bottom Left Of The Texture and Quad
# Left Face
glNormal(-1.0, 0.0, 0.0); # left face points left on x.
glTexCoord(0.0, 0.0); glVertex(-1.0, -1.0, -1.0); # Bottom Left Of The Texture and Quad
glTexCoord(1.0, 0.0); glVertex(-1.0, -1.0, 1.0); # Bottom Right Of The Texture and Quad
glTexCoord(1.0, 1.0); glVertex(-1.0, 1.0, 1.0); # Top Right Of The Texture and Quad
glTexCoord(0.0, 1.0); glVertex(-1.0, 1.0, -1.0); # Top Left Of The Texture and Quad
glEnd(); # done with the polygon.
$xrot+=$xspeed; # X Axis Rotation
$yrot+=$yspeed; # Y Axis Rotation
}
sub LoadGLTextures
{
# Load Texture
my ($pixels, $width, $height, $size)=ImageLoad("Data/crate.png");
# Create Texture
glGenTextures(3);
# texture 1 (poor quality scaling)
glBindTexture(GL_TEXTURE_2D, 1); # 2d texture (x and y size)
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); # cheap scaling when image bigger than texture
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); # cheap scaling when image smalled than texture
# 2d texture, level of detail 0 (normal), 3 components (red, green, blue), x size from image, y size from image,
# border 0 (normal), rgb color data, unsigned byte data, and finally the data itself.
#glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);
glTexImage2D(GL_TEXTURE_2D,
0, #level (0 normal, heighr is form mip-mapping)
3, #internal format (3=GL_RGB)
$width,$height,
0, # border
GL_RGB, #format RGB color data
GL_UNSIGNED_BYTE, #unsigned bye data
$pixels); #ptr to texture data
# texture 2 (linear scaling)
glBindTexture(GL_TEXTURE_2D, 2); # 2d texture (x and y size)
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); # scale linearly when image bigger than texture
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); # scale linearly when image smalled than texture
#glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);
glTexImage2D(GL_TEXTURE_2D,
0, #level (0 normal, heighr is form mip-mapping)
3, #internal format (3=GL_RGB)
$width,$height,
0, # border
GL_RGB, #format RGB color data
GL_UNSIGNED_BYTE, #unsigned bye data
$pixels); #ptr to texture data
# texture 3 (mipmapped scaling)
glBindTexture(GL_TEXTURE_2D, 3); # 2d texture (x and y size)
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); # scale linearly when image bigger than texture
glTexParameter(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); # scale linearly + mipmap when image smalled than texture
#glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->w, image1->h, 0, GL_RGB, GL_UNSIGNED_BYTE, image1->pixels);
glTexImage2D(GL_TEXTURE_2D,
0, #level (0 normal, heighr is form mip-mapping)
3, #internal format (3=GL_RGB)
$width,$height,
0, # border
GL_RGB, #format RGB color data
GL_UNSIGNED_BYTE, #unsigned bye data
$pixels); #ptr to texture data
# 2d texture, 3 colors, width, height, RGB in that order, byte data, and the data.
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, $width, $height, GL_RGB, GL_UNSIGNED_BYTE, $pixels);
my $glerr=glGetError();
die "Problem setting up 2d Texture (dimensions not a power of 2?)):".gluErrorString($glerr)."\n" if $glerr;
}
#somthing needs to keep the ref count alive for objects which represents data in C space (they have no ref count):
my @ref=();
sub ImageLoad
{
my $filename=shift;
my $surface = new SDL::Surface( -name => $filename); #makes use of SDL: BMP loader.
my $width=$surface->width();
my $height=$surface->height();
my $bytespp= $surface->bytes_per_pixel();
my $size= $width*$height*$bytespp;
my $surface_pixels=$surface->pixels();
my $surface_size=$width*$height*$surface->bytes_per_pixel();
my $raw_pixels = $surface_pixels;
#do a conversion (the pixel data is accessable as a simple string)
my $pixels=$raw_pixels;
my $pre_conv= $pixels; #rotate image 180 degrees!
my $new_pixels="";
for (my $y=0; $y< $height; $y++)
{
my $y_pos=$y*$width*$bytespp; #calculate offset into the image (a string)
my $row=substr ($pre_conv, $y_pos, $width*$bytespp); #extract 1 pixel row
$row =~ s/\G(.)(.)(.)/$3$2$1/gms; #turn the BMP BGR order into OpenGL RGB order;
$new_pixels.= reverse $row;
}
$raw_pixels = $new_pixels; #put transformed data into C array.
push @ref, $raw_pixels, $surface;
#we could have created another SDL surface frm the '$raw_pixel's... oh well.
return ($raw_pixels, $width, $height, $size);
}