#!/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::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); }