From: peter <my....@gm...> - 2009-07-10 07:33:03
|
hello thanks kevin for the opengl example. i have used his example to display a triangle which can be rotated in a 3D space using the up down left right keys. also added a button and a textbox, i have 2 question: 1- i can rotate the triangle by keys, until i click on the button to display some text in the textbox, why is this behaviour, and how i can restore the triangle rotating after clicking the button. 2- is it possible to make the opengl window smaller than the win32gui window !! best wishes attached below the code, and for your convenience from here: http://rapidshare.com/files/254072142/triangle.rar peter use strict; use warnings; #these constants are needed for SetPixelFormat() but aren't defined in Win32::GUI use constant { PFD_TYPE_RGBA => 0, PFD_DOUBLEBUFFER => 0x00000001, PFD_DRAW_TO_WINDOW => 0x00000004, PFD_SUPPORT_OPENGL => 0x00000020, PFD_MAIN_PLANE => 0, }; use OpenGL qw(:glfunctions :glconstants :glufunctions); #use OpenGL qw(:all); use Win32::API; use Win32::GUI qw(); use Win32::GUI::Carp qw(warningsToDialog fatalsToDialog immediateWarnings winwarn windie); use Win32::GUI::Constants qw(IDI_APPLICATION WS_CLIPCHILDREN WS_CLIPSIBLINGS WM_CREATE WM_SIZE WM_CLOSE VK_ESCAPE CW_USEDEFAULT MB_OK MB_ICONEXCLAMATION); my $g_HDC; #global handle to device context my $hRC; #handle to rendering context my $rtri = 0.0; my $xrot = 0; my $yrot = 0; #define PIXELFORMATDESCRIPTOR struct used for the SetPixelFormat function #refer to the Windows SDK documentation for more info about this structure Win32::API::Struct->typedef( PIXELFORMATDESCRIPTOR => qw( WORD nSize; WORD nVersion; DWORD dwFlags; BYTE iPixelType; BYTE cColorBits; BYTE cRedBits; BYTE cRedShift; BYTE cGreenBits; BYTE cGreenShift; BYTE cBlueBits; BYTE cBlueShift; BYTE cAlphaBits; BYTE cAlphaShift; BYTE cAccumBits; BYTE cAccumRedBits; BYTE cAccumGreenBits; BYTE cAccumBlueBits; BYTE cAccumAlphaBits; BYTE cDepthBits; BYTE cStencilBits; BYTE cAuxBuffers; BYTE iLayerType; BYTE bReserved; DWORD dwLayerMask; DWORD dwVisibleMask; DWORD dwDamageMask; ) ); #needed for the wglMakeCurrent functions Win32::API::Type->typedef('HGLRC', 'HANDLE'); #import some extra functions #more info can be found in the Windows SDK documentation #exchanges the front and back buffers of the current pixel format Win32::API->Import('gdi32', 'BOOL SwapBuffers(HDC hdc);') or windie "Win32::API->Import(SwapBuffers): $^E"; #attempts to match an appropriate pixel format supported by a device context to # a given pixel format specification. Win32::API->Import('gdi32', 'int ChoosePixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR * ppfd);') or windie "Win32::API->Import(ChoosePixelFormat): $^E"; #sets the pixel format of the specified device context to the format specified # by the iPixelFormat index returned from ChoosePixelFormat(). Win32::API->Import('gdi32', 'BOOL SetPixelFormat(HDC hdc, int iPixelFormat, PIXELFORMATDESCRIPTOR * ppfd);') or windie "Win32::API->Import(SetPixelFormat): $^E"; #creates a new OpenGL rendering context, which is suitable for drawing on the # device referenced by hdc. Win32::API->Import('opengl32', 'HGLRC wglCreateContext(HDC hdc);') or windie "Win32::API->Import(wglCreateContext): $^E"; #makes a specified OpenGL rendering context the calling thread's current # rendering context. Win32::API->Import('opengl32', 'BOOL wglMakeCurrent(HDC hdc, HGLRC hglrc);') or windie "Win32::API->Import(wglMakeCurrent): $^E"; #deletes a specified OpenGL rendering context. Win32::API->Import('opengl32', 'BOOL wglDeleteContext(HGLRC hglrc);') or windie "Win32::API->Import(wglDeleteContext): $^E"; #create main window my $main = Win32::GUI::Window->new( -name => "main", -text => "OpenGL Example: Colour Cube", -size => [640,480], -left => CW_USEDEFAULT, #let system position window -pushstyle => #Excludes the area occupied by child windows when drawing occurs # within the parent window. WS_CLIPCHILDREN | #When a particular child window needs to be painted, all other overlapping # child windows are clipped out of the region of the child window to be updated. WS_CLIPSIBLINGS, -onTerminate => sub { #WM_CLOSE wglMakeCurrent($g_HDC->Handle(), 0); #deselect rendering context from $hDC wglDeleteContext($hRC); #delete rendering context $hRC return -1; #exit main loop }, -onResize => sub { #WM_SIZE my $self = shift; return 0 unless $self; my $height = $self->Height(); #get height and width my $width = $self->Width(); $height = 1 if $height == 0; #don't divide by 0 glViewport(0,0,$width,$height); #set viewport to new dimensions glMatrixMode(GL_PROJECTION); #set matrix mode to projection matrix glLoadIdentity(); #reset projection matrix gluPerspective(54.0, $width / $height, 1.0, 1000.0); #calculate aspect ratio of window glMatrixMode(GL_MODELVIEW); #set modelview matrix glLoadIdentity(); #reset modelview matrix return 1; }, -onKeyDown => sub { #WM_KEYDOWN my ($self, $flags, $key) = @_; return -1 if $key == VK_ESCAPE; #exit if escape key pressed if ($key == 37) { $yrot -= 3.0; } elsif ($key == 39) { $yrot += 3.0; } elsif ($key == 38) { $xrot += 3.0; } elsif ($key == 40) { $xrot -= 3.0; } else { return; } #glutPostRedisplay(); return 1; }, ); $main->AddButton( -text => "Run", -name => "Button1", -left => 23, -top => 10, -width => 56, -height => 36, -foreground => 0, ); my $textfield = $main->AddTextfield( -text => "", -name => "Textfield_1", -left => 120, -top => 10, -width => 150, -height => 100, -multiline => 1, -vscroll => 1, ); unless($main){ windie("Cannot create window: $^E"); } $main->SetIcon(Win32::GUI::Icon->new(IDI_APPLICATION)); #set window icon #WM_CREATE $g_HDC = $main->GetDC(); #set global device context to device context of main window unless(SetupPixelFormat($g_HDC->Handle())){ #setup pixel format for device context exit 1; #exit if setup fails } $hRC = wglCreateContext($g_HDC->Handle()); #create rendering context used by OpenGL to draw wglMakeCurrent($g_HDC->Handle(), $hRC); #select rendering context $hRC into $g_HDC #Initialize OpenGL #my ($width, $height) = (300,200); glClearColor(0.0, 0.0, 0.0, 0.0); # Enables clearing of the Depth buffer glClearDepth(1.0); # The type of depth test to do glDepthFunc(GL_LESS); # Enables depth testing with that type glEnable(GL_DEPTH_TEST); # Enables smooth color shading glShadeModel(GL_SMOOTH); # Reset the projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity; # Calculate the aspect ratio of the Window #gluPerspective(45.0, $width/$height, 0.1, 100.0); # Reset the modelview matrix $main->Show(); #show window while(Win32::GUI::DoEvents() != -1){ Render(); } #This function is used to set the pixel format for the device context. # Accepts a handle to the device context of the window and returns true if succeeds # or false if fails. #Adapted from code from OpenGL Game Programming (Premier Press, 2004) sub SetupPixelFormat { my $hDC = shift; #is a handle to DC my $nPixelFormat; my $pfd = Win32::API::Struct->new('PIXELFORMATDESCRIPTOR'); #create new structure $pfd->{nSize} = $pfd->sizeof(); #return sizeof structure $pfd->{nVersion} = 1; #default version $pfd->{dwFlags} = PFD_DRAW_TO_WINDOW | #window drawing support PFD_SUPPORT_OPENGL | #OpenGL support PFD_DOUBLEBUFFER; #double buffering support $pfd->{iPixelType} = PFD_TYPE_RGBA; #rgba colour mode $pfd->{cColorBits} = 32; #32 bit colour mode $pfd->{cRedBits} = 0; #ignore colour bits $pfd->{cRedShift} = 0; # $pfd->{cGreenBits} = 0; # $pfd->{cGreenShift} = 0; # $pfd->{cBlueBits} = 0; # $pfd->{cBlueShift} = 0; # $pfd->{cAlphaBits} = 0; #not alpha buffer $pfd->{cAlphaShift} = 0; #ignore alpha shift bit $pfd->{cAccumBits} = 0; #no accumulation buffer $pfd->{cAccumRedBits} = 0; #ignore accumulation bits $pfd->{cAccumGreenBits} = 0; # $pfd->{cAccumBlueBits} = 0; # $pfd->{cAccumAlphaBits} = 0; # $pfd->{cDepthBits} = 16; #16 bit z-buffer size $pfd->{cStencilBits} = 0; #no stencil buffer $pfd->{cAuxBuffers} = 0; #no auxiliary buffer $pfd->{iLayerType} = PFD_MAIN_PLANE; #main drawing plane $pfd->{bReserved} = 0; #reserved $pfd->{dwLayerMask} = 0; #layer masks ignored $pfd->{dwVisibleMask} = 0; # $pfd->{dwDamageMask} = 0; # # choose best matching pixel format unless( $nPixelFormat = ChoosePixelFormat($hDC, $pfd) ){ winwarn("Can't find an appropriate pixel format"); return 0; } # set pixel format to device context unless( SetPixelFormat($hDC, $nPixelFormat, $pfd) ){ winwarn("Unable to set pixel format"); return 0; } return 1; } #This function draws the cube of points. The colour of each point is based on its position #Adapted from code from OpenGL Game Programming (Premier Press, 2004) sub DrawCube { glRotatef( $yrot, 0.0, 1.0, 0.0 ); glRotatef( $xrot, 1.0, 0.0, 0.0 ); glPushMatrix(); #glBegin(GL_POINTS); #glRotatef($rtri, 0.0, 1.0, 0.0); glBegin(GL_POLYGON); glColor3f(1.0, 0.0, 0.0); glVertex3f( 0.0, 20.0, 0.0); # Top vertex glColor3f(0.0, 1.0, 0.0); # Set The Color To Green glVertex3f( 20.0, -20.0, 0.0); # Bottom right vertex glColor3f(0.0, 0.0, 1.0); # Set The Color To Blue glVertex3f(-20.0, -20.0, 0.0); glEnd(); $rtri = $rtri + 3.0; glPopMatrix(); } #This function is used to draw the cube and is called every frame #Adapted from code from OpenGL Game Programming (Premier Press, 2004) sub Render { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); #clear color and depth buffer glLoadIdentity(); #replaces the current matrix with the identity matrix. glTranslatef(0.0, 0.0, -150.0); #move to 0,0,-150 glPushMatrix(); #save current matrix DrawCube(); #draw cube glPopMatrix(); #restore matrix glFlush(); #clear buffers SwapBuffers($g_HDC->Handle()); #exchange front and back buffers of device context } #Conveniently, the Windows specific functions for setup of OpenGL accept and return # handles to windows or contexts, which are just numbers, and the handles to # these are stored in the Window and DC objects created by Win32::GUI. This method # provides an easy access to this value. Placing the method in the #Win32::GUI::DC # package allows both Windows and DCs to use it. sub Button1_Click { $textfield->Append("OpenGL example : rotating triangle\r\n"); } package Win32::GUI::DC; sub Handle { return shift->{-handle}; } __END__ |