#!/usr/local/bin/perl # # teapotgif.pl : make an animated gif image of a rotating teapot # (c) 2013 jl_morel@bribes.org - http://http://bribes.org/perl use strict; use warnings; use OpenGL qw/ :all /; use OpenGL::Image; use Image::Magick; my $animatedgifname = "teapot.gif"; my $animatedgif = Image::Magick->new(); my @light0_position = ( 2.0, 8.0, 2.0, 0.0 ); my @light_diffuse = ( 1.0, 1.0, 1.0, 1.0 ); my @light_ambient = ( 0.15, 0.15, 0.15, 0.15 ); my @mat_amb_diff_color = ( 0.4, 0.2, 0.8, 1.0 ); #------ Initialization routine sub init { glClearColor( 1, 1, 1, 1 ); # White background glShadeModel(GL_SMOOTH); # Smooth shading glEnable(GL_DEPTH_TEST); # Enable hidden surface removal glEnable(GL_MULTISAMPLE); # Enable multisample antialiasing glEnable(GL_LIGHTING); # Enable lighting glEnable(GL_LIGHT0); glLightfv_p( GL_LIGHT0, GL_POSITION, @light0_position ); glLightfv_p( GL_LIGHT0, GL_DIFFUSE, @light_diffuse ); glLightfv_p( GL_LIGHT0, GL_AMBIENT, @light_ambient ); glMaterialfv_p( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, @mat_amb_diff_color ); glEnable(GL_CLIP_PLANE0); # One clip plane needed } #------ Draw the teapot my $size = 3.5; # teapot size my $spin = 0; # rotation angle sub display { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glLoadIdentity(); gluLookAt( 2.0, 4.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 ); glPushMatrix(); glRotatef( $spin, 0.0, 1.0, 0.0 ); # The plane equation is 0x+0y+1z=0 with normal vector (0,0,1) glClipPlane_p( GL_CLIP_PLANE0, 0, 0, 1, 0 ); glutSolidTeapot($size); # Same plane but with normal vector (0,0,-1) glClipPlane_p( GL_CLIP_PLANE0, 0, 0, -1, 0 ); glutWireTeapot($size); glPopMatrix(); glutSwapBuffers(); } #------ GLUT Callback called when the window is resized sub reshape { my ( $w, $h ) = @_; glViewport( 0, 0, $w, $h ); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective( 45.0, $h ? $w / $h : 0, 1.0, 20.0 ); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } #------ Routine for rotating the teapot my $WaitUntil = 0; sub spinDisplay { my $TimeNow = glutGet(GLUT_ELAPSED_TIME); if ( $TimeNow >= $WaitUntil ) { $spin += 1.0; if ( $spin > 360 ) { # 10/100ths of a second between images, loop indefinitely $animatedgif->Set( delay => 10, loop => 0 ); $animatedgif->Write($animatedgifname); unlink "tmp.gif"; exit; } if ( $spin % 5 == 0 ) { # One capture every 5 degree IMCapture("tmp.gif"); # Save as gif image $animatedgif->Read("tmp.gif"); } glutPostRedisplay(); $WaitUntil = $TimeNow + 1000 / 25; # 25 frames/s } } #------ Main glutInit(); glutInitDisplayMode( GLUT_DOUBLE # Double buffering | GLUT_RGB # RGB color mode | GLUT_DEPTH # Hidden surface removal | GLUT_MULTISAMPLE # Multisample antialiasing ); glutInitWindowSize( 420, 240 ); glutCreateWindow("Teapot"); init(); glutDisplayFunc( \&display ); glutReshapeFunc( \&reshape ); glutIdleFunc( \&spinDisplay ); glutMainLoop(); #------ Image capture function with ImageMagick # Usage: IMCapture( $imgname [, $x, $y, $width, $height ] ); # $imgname is the image name with extension (.gif, .jpeg, .png ...) # The optional part [ $x, $y, $width, $height ] defines the dimensions # of the rectangle to capture. # If not supplied, the dimensions of the current window are used. sub IMCapture { my $file = shift; my ( $x, $y, $width, $height ) = @_ == 4 ? @_ : glGetIntegerv_p(GL_VIEWPORT); my $img = new OpenGL::Image( engine => 'Magick', width => $width, height => $height ); my ( $def_fmt, $def_type ) = $img->Get( 'gl_format', 'gl_type' ); glFinish(); glReadPixels_c( $x, $y, $width, $height, $def_fmt, $def_type, $img->Ptr() ); $img->Save($file); }