I have also experimented with OpenGL and Win32::GUI. I started to write a module to integrate the two, but never completed it - I did get it running though, and successfully ported most of the examples that some with the OpenGL module.
I'll make make my code available sometime next week, once I get back home; if anyone wants to pick this up I can give some direction on what needs doing to complete it. Rob. 2009/5/22 Jason Plum <m...@warheads.net>: > May I be lucky enough to pick my ass up and put it back onto my chair, then > also say thanks for the well documented and detailed example! > > I myself have toyed with OpenGL via perl before, but have never thought of > combining it with Win32::GUI myself. Seeing as I'm a maintainer for a game, > and some people have asked for updated tools with animations from said > game.. I may someday put this example to a very literal use. > Thanks again, > Jason P > > On Thu, May 21, 2009 at 11:18 PM, Kevin Marshall <kejoh...@hotmail.com> > wrote: >> >> Hey, >> >> This lengthy post is about how to use the Win32::GUI module together with >> the Perl OpenGL module (POGL). >> >> I would first like to thank the developers of Perl-Win32-GUI module. I >> have been using this module for a while now, and prefer using this module >> than coding the whole thing in C/C++. Thanks. I have decided to give back >> to the Win32::GUI community by way of sharing a solution for using OpenGL in >> conjunction with the Win32::GUI module. I hope that someone out there will >> find this useful. >> >> After reading the book OpenGL Game Programming (Premier Press), I decided >> to port some of the code examples to Perl. Since the Win32::GUI module makes >> the creation of windows easy, it was simply a matter of converting the >> relevant C/C++ code into Perl. A basic knowledge of OpenGL is needed in >> order to understand the example that I have provided. The example contains >> comments that should explain what each section does, but I'll provide a >> brief overview of the process. I'll only be discussing the Windows+OpenGL >> specific code, so if you don't have a good grasp of OpenGL, I recommend >> finding a good book or website about OpenGL programming before going any >> further. Detailed information regarding Windows API functions, and OpenGL >> functions can be found in the Windows Software Development Kit >> Documentation. >> >> OpenGL is a powerful, low-level rendering and modelling software library. >> OpenGL does not provide higher functionality, such as windowing, in order to >> remain platform independent. OpenGL uses a rendering context to store OpenGL >> commands and settings. This means that each platform must provide >> functionality to specify a rendering context for OpenGL. For UNIX systems, >> this is provided by GLX. For Windows this is provided by a set of functions >> affectionately known as 'wiggle' functions, since most of these start with >> 'wgl'. There are a number of other Win32 API functions that are also needed. >> These 'wiggle' and Win32 API functions relate Windows Device Contexts with >> the OpenGL rendering contexts. The Win32::API module is needed to import >> these functions for use in the program. >> >> Example Program Description: >> >> Lines 21-51 show some setup required for the functions that are to be >> imported. This includes creating the structure PIXELFORMATDESCRIPTOR used >> by the SetPixelFormat() function and creating a typedef for the >> wglMakeCurrent() function. Lines 52-63 show the functions that need to be >> imported. Info on these functions can be found in the SDK docs. >> >> Lines 64-100 creates the main window and sets its icon. This should be >> fairly basic for anyone experienced with the Win32::GUI module, so I'll just >> cover the important parts. Line 68 sets the -left of the window to >> CW_USEDEFAULT. This specifies that the system should position the window. >> Lines 69-71 add the window styles WS_CLIPCHILDREN and WS_CLIPSIBLINGS. >> These affect how the window will be painted. For more info about these >> styles, see the SDK docs. Lines 72-76 setup an -onTerminate event handler. >> This will be called when the window is destroyed. At this point the >> rendering context is deselected from the main window Device Context and is >> then deleted. More on these functions later. Just know that each takes a >> handle to a device or rendering context. The sub returns -1 to exit the main >> loop. For those of you familiar with C/C++ Windows programming, this >> function roughly corresponds to the WM_CLOSE message. Lines 77-90 setup an >> -onResize event handler. This is called whenever the window is resized and >> corresponds to the WM_SIZE message. The functions in the sub are OpenGL >> specific and basically just reset the viewport to the new dimensions and >> resets the perspective. Refer to the SDK docs or a good OpenGL resource for >> info about these functions. Lines 91-95 setup a -onKeyDown event handler >> which exits the program when the ESC key is pressed. >> >> Lines 101-106 are where the device and rendering contexts are setup. Line >> 101 gets the device context of the main window and stores it in a global >> variable. Lines 102-104 calls the SetupPixelFormat() function, passing it >> the handle to the main window device context. If this sub fails the program >> exits. Lines 116-157 show the SetupPixelFormat() function. Line 119 creates >> a new PIXELFORMATDESCRIPTOR structure and lines 120-147 fills the structure >> with appropriate data. See the SDK docs for more info about this structure. >> Lines 148-151 calls the ChoosePixelFormat() function passing the handle to >> the DC and the PIXELFORMATDESCRIPTOR structure. This function chooses the >> best matching pixel format for the DC from the data specified in the >> PIXELFORMATDESCRIPTOR structure. The function returns 0 if not pixel format >> can be found. Lines 152-155 set the pixel format of the DC to the format >> returned from the ChoosePixelFormat() function and returns 0 if it fails. >> The sub returns 1 to show that it succeeded. Line 105 creates an OpenGL >> rendering context from the specified DC using the wglCreateContext() >> function. The function is passed the handle to the main window DC and >> returns the handle to a rendering context. Line 106 selects the rendering >> context into the device context using the wglMakeCurrent() function. This >> functions is passed the handle to the main window DC and the handle to the >> rendering context created with wglCreateContext(). Passing 0 as the >> rendering context causes the rendering context to be deselected, such as in >> the -onTerminate event handler above. The wglDeleteContext() function is >> used to delete a rendering context and should be used after the rendering >> context has been deselected. The deselection and deletion of a rendering >> context should be performed when a window is destroyed, which is why this is >> done in the -onTerminate event handler above. Lines 101-106 could be thought >> of as equivalent to the WM_CREATE message (you could even use the Hook() >> method to implement this). >> >> Lines 107-111 show some basic setup of OpenGL before any rendering is >> done. These are OpenGL specific, so if you are unsure of what these do, >> refer to the docs. >> >> Lines 113-115 setup the main message loop. Win32::GUI::Dialog() can't be >> used here because the Render() function has to be called every frame. This >> loop is essentially the same, but a few differences are present which may >> affect applications with multiple windows, since the Win32::GUI::Dialog() >> functions does more behind the scenes. It would be nice if the >> Win32::GUI::Dialog() function accepted a sub ref which could be called every >> frame, but I'm not sure how easy that would be to create. Anyway, this does >> the job fine, but there are probably better methods. >> >> Lines 158-172 and 173-188 are the DrawCube() and Render() functions, >> respectively. These are used to draw the cube every frame and are OpenGL >> specific. Refer to the docs about what the OpenGL functions do if you are >> unsure. >> >> Line 189-193 creates a Handle() method in the Win32::GUI::DC package. This >> method returns the handle of the object passed in. Putting it in the DC >> package allows both windows and DCs to access it. This method is used when >> the OpenGL/Win32API function requires a handle. Since the objects store in >> handle internally, it makes it really easy to pass this value to the >> functions that need it. >> >> Here is my code example: >> >> >> ################################################################################ >> # >> # Win32::GUI + OpenGL example >> # >> # This program demonstrates a basic example of using the Perl Win32::GUI >> # module in conjunction with the Perl OpenGL module to render a spinning >> # cube of points in the window. >> # >> # Requirements: >> # Perl, >> # Win32::GUI, >> # Win32::GUI::Carp, >> # Win32::API, and >> # OpenGL >> # >> # This program was written using ActiveState Perl 5.8.8 Build 820 running >> on >> # Windows XP and using Win32::GUI v1.06, Win32::GUI::Carp v1.01, >> # Win32::API v0.46, and OpenGL v0.56 >> # >> # Parts of this program are based on example code from the book OpenGL >> Game >> # Programming (Premier Press, 2004) from the Premier Press Game >> # Development Series. I recommend this book for anyone interested in >> using >> # OpenGL for developing games on Windows. The book is written for the >> # development of games written in C/C++ and assumes an advanced knowledge >> # of the language but provides an in-depth look at OpenGL programming on >> # Windows platforms, as well as a look at using DirectInput and >> # DirectX Audio. >> # >> >> ################################################################################ >> >> 1: use strict; >> 2: use warnings; >> #these constants are needed for SetPixelFormat() but aren't defined in >> Win32::GUI >> 3: use constant { >> 4: PFD_TYPE_RGBA => 0, >> 5: PFD_DOUBLEBUFFER => 0x00000001, >> 6: PFD_DRAW_TO_WINDOW => 0x00000004, >> 7: PFD_SUPPORT_OPENGL => 0x00000020, >> 8: PFD_MAIN_PLANE => 0, >> 9: }; >> >> 10: use OpenGL qw(:glfunctions :glconstants :glufunctions); >> 11: use Win32::API; >> 12: use Win32::GUI qw(); >> 13: use Win32::GUI::Carp qw(warningsToDialog fatalsToDialog >> immediateWarnings winwarn windie); >> 14: use Win32::GUI::Constants qw(IDI_APPLICATION WS_CLIPCHILDREN >> WS_CLIPSIBLINGS >> 15: WM_CREATE WM_SIZE WM_CLOSE VK_ESCAPE CW_USEDEFAULT MB_OK >> MB_ICONEXCLAMATION); >> >> 16: my $g_HDC; #global handle to device context >> 17: my $hRC; #handle to rendering context >> >> #keep track of rotation of cube >> 18: my $objectXRot = 0.0; >> 19: my $objectYRot = 0.0; >> 20: my $objectZRot = 0.0; >> >> #define PIXELFORMATDESCRIPTOR struct used for the SetPixelFormat function >> #refer to the Windows SDK documentation for more info about this structure >> 21: Win32::API::Struct->typedef( >> 22: PIXELFORMATDESCRIPTOR => qw( >> 23: WORD nSize; >> 24: WORD nVersion; >> 25: DWORD dwFlags; >> 26: BYTE iPixelType; >> 27: BYTE cColorBits; >> 28: BYTE cRedBits; >> 29: BYTE cRedShift; >> 30: BYTE cGreenBits; >> 31: BYTE cGreenShift; >> 32: BYTE cBlueBits; >> 33: BYTE cBlueShift; >> 34: BYTE cAlphaBits; >> 35: BYTE cAlphaShift; >> 36: BYTE cAccumBits; >> 37: BYTE cAccumRedBits; >> 38: BYTE cAccumGreenBits; >> 39: BYTE cAccumBlueBits; >> 40: BYTE cAccumAlphaBits; >> 41: BYTE cDepthBits; >> 42: BYTE cStencilBits; >> 43: BYTE cAuxBuffers; >> 44: BYTE iLayerType; >> 45: BYTE bReserved; >> 46: DWORD dwLayerMask; >> 47: DWORD dwVisibleMask; >> 48: DWORD dwDamageMask; >> 49: ) >> 50: ); >> >> #needed for the wglMakeCurrent functions >> 51: 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 >> 52: Win32::API->Import('gdi32', 'BOOL SwapBuffers(HDC hdc);') >> 53: 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. >> 54: Win32::API->Import('gdi32', 'int ChoosePixelFormat(HDC hdc, >> PIXELFORMATDESCRIPTOR * ppfd);') >> 55: 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(). >> 56: Win32::API->Import('gdi32', 'BOOL SetPixelFormat(HDC hdc, int >> iPixelFormat, PIXELFORMATDESCRIPTOR * ppfd);') >> 57: or windie "Win32::API->Import(SetPixelFormat): $^E"; >> >> #creates a new OpenGL rendering context, which is suitable for drawing on >> the >> # device referenced by hdc. >> 58: Win32::API->Import('opengl32', 'HGLRC wglCreateContext(HDC hdc);') >> 59: or windie "Win32::API->Import(wglCreateContext): $^E"; >> >> #makes a specified OpenGL rendering context the calling thread's current >> # rendering context. >> 60: Win32::API->Import('opengl32', 'BOOL wglMakeCurrent(HDC hdc, HGLRC >> hglrc);') >> 61: or windie "Win32::API->Import(wglMakeCurrent): $^E"; >> >> #deletes a specified OpenGL rendering context. >> 62: Win32::API->Import('opengl32', 'BOOL wglDeleteContext(HGLRC hglrc);') >> 63: or windie "Win32::API->Import(wglDeleteContext): $^E"; >> >> #create main window >> 64: my $main = Win32::GUI::Window->new( >> 65: -name => "main", >> 66: -text => "OpenGL Example: Colour Cube", >> 67: -size => [640,480], >> 68: -left => CW_USEDEFAULT, #let system position window >> 69: -pushstyle => >> #Excludes the area occupied by child windows when drawing occurs >> # within the parent window. >> 70: 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. >> 71: WS_CLIPSIBLINGS, >> 72: -onTerminate => sub { #WM_CLOSE >> 73: wglMakeCurrent($g_HDC->Handle(), 0); #deselect rendering context >> from $hDC >> 74: wglDeleteContext($hRC); #delete rendering context $hRC >> 75: return -1; #exit main loop >> 76: }, >> 77: -onResize => sub { #WM_SIZE >> 78: my $self = shift; >> 79: return 0 unless $self; >> 80: my $height = $self->Height(); #get height and width >> 81: my $width = $self->Width(); >> 82: $height = 1 if $height == 0; #don't divide by 0 >> 83: glViewport(0,0,$width,$height); #set viewport to new dimensions >> 84: glMatrixMode(GL_PROJECTION); #set matrix mode to projection matrix >> 85: glLoadIdentity(); #reset projection matrix >> 86: gluPerspective(54.0, $width / $height, 1.0, 1000.0); #calculate >> aspect ratio of window >> 87: glMatrixMode(GL_MODELVIEW); #set modelview matrix >> 88: glLoadIdentity(); #reset modelview matrix >> 89: return 1; >> 90: }, >> 91: -onKeyDown => sub { #WM_KEYDOWN >> 92: my ($self, $flags, $key) = @_; >> 93: return -1 if $key == VK_ESCAPE; #exit if escape key pressed >> 94: return 1; >> 95: }, >> 96: ); >> 97: unless($main){ >> 98: windie("Cannot create window: $^E"); >> 99: } >> 100: $main->SetIcon(Win32::GUI::Icon->new(IDI_APPLICATION)); #set window >> icon >> >> #WM_CREATE >> 101: $g_HDC = $main->GetDC(); #set global device context to device >> context of main window >> 102: unless(SetupPixelFormat($g_HDC->Handle())){ #setup pixel format for >> device context >> 103: exit 1; #exit if setup fails >> 104: } >> 105: $hRC = wglCreateContext($g_HDC->Handle()); #create rendering context >> used by OpenGL to draw >> 106: wglMakeCurrent($g_HDC->Handle(), $hRC); #select rendering context >> $hRC into $g_HDC >> >> #Initialize OpenGL >> 107: glShadeModel(GL_SMOOTH); #set shading to smooth >> 108: glEnable(GL_DEPTH_TEST); #do depth comparisons and update the >> depth buffer >> 109: glEnable(GL_CULL_FACE); #cull polygons based on their winding >> in window coordinates >> 110: glFrontFace(GL_CCW); #The orientation of front-facing polygons >> 111: glClearColor(0.0, 0.0, 0.0, 0.0); #values that glClear uses to >> clear the colour buffers >> >> 112: $main->Show(); #show window >> >> #message event >> #This is necessary because Render() needs to be called every frame. >> #This can produce interesting results in more complex applications (with >> more >> # than one window) since the Win32::GUI::Dialog() function does more than >> just >> # check if a sub has returned -1 (perhaps the ability to call a code block >> every >> # iteration of Win32::GUI::Dialog() would be useful) >> 113: while(Win32::GUI::DoEvents() != -1){ >> 114: Render(); >> 115: } >> >> #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) >> 116: sub SetupPixelFormat { >> 117: my $hDC = shift; #is a handle to DC >> 118: my $nPixelFormat; >> 119: my $pfd = Win32::API::Struct->new('PIXELFORMATDESCRIPTOR'); #create >> new structure >> 120: $pfd->{nSize} = $pfd->sizeof(); #return sizeof structure >> 121: $pfd->{nVersion} = 1; #default version >> 122: $pfd->{dwFlags} = PFD_DRAW_TO_WINDOW | #window drawing support >> 123: PFD_SUPPORT_OPENGL | #OpenGL support >> 124: PFD_DOUBLEBUFFER; #double buffering support >> 125: $pfd->{iPixelType} = PFD_TYPE_RGBA; #rgba colour mode >> 126: $pfd->{cColorBits} = 32; #32 bit colour mode >> 127: $pfd->{cRedBits} = 0; #ignore colour bits >> 128: $pfd->{cRedShift} = 0; # >> 129: $pfd->{cGreenBits} = 0; # >> 130: $pfd->{cGreenShift} = 0; # >> 131: $pfd->{cBlueBits} = 0; # >> 132: $pfd->{cBlueShift} = 0; # >> 133: $pfd->{cAlphaBits} = 0; #not alpha buffer >> 134: $pfd->{cAlphaShift} = 0; #ignore alpha shift bit >> 135: $pfd->{cAccumBits} = 0; #no accumulation buffer >> 136: $pfd->{cAccumRedBits} = 0; #ignore accumulation bits >> 137: $pfd->{cAccumGreenBits} = 0; # >> 138: $pfd->{cAccumBlueBits} = 0; # >> 139: $pfd->{cAccumAlphaBits} = 0; # >> 140: $pfd->{cDepthBits} = 16; #16 bit z-buffer size >> 141: $pfd->{cStencilBits} = 0; #no stencil buffer >> 142: $pfd->{cAuxBuffers} = 0; #no auxiliary buffer >> 143: $pfd->{iLayerType} = PFD_MAIN_PLANE; #main drawing plane >> 144: $pfd->{bReserved} = 0; #reserved >> 145: $pfd->{dwLayerMask} = 0; #layer masks ignored >> 146: $pfd->{dwVisibleMask} = 0; # >> 147: $pfd->{dwDamageMask} = 0; # >> # choose best matching pixel format >> 148: unless( $nPixelFormat = ChoosePixelFormat($hDC, $pfd) ){ >> 149: winwarn("Can't find an appropriate pixel format"); >> 150: return 0; >> 151: } >> # set pixel format to device context >> 152: unless( SetPixelFormat($hDC, $nPixelFormat, $pfd) ){ >> 153: winwarn("Unable to set pixel format"); >> 154: return 0; >> 155: } >> 156: return 1; >> 157: } >> >> #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) >> 158: sub DrawCube { >> 159: glPointSize(2.0); #set size of points drawn >> 160: glPushMatrix(); >> 161: glBegin(GL_POINTS); >> 162: for(my $x = 0.0; $x <= 1.0; $x += 0.1){ >> 163: for(my $y = 0.0; $y <= 1.0; $y += 0.1){ >> 164: for(my $z = 0.0; $z <= 1.0; $z += 0.1){ >> 165: glColor3f($x,$y,$z); >> #move and scale vertexes so that cube rotates about centre >> 166: glVertex3f($x*50-25,$y*50-25,$z*50-25); >> 167: } >> 168: } >> 169: } >> 170: glEnd(); >> 171: glPopMatrix(); >> 172: } >> >> #This function is used to draw the cube and is called every frame >> #Adapted from code from OpenGL Game Programming (Premier Press, 2004) >> 173: sub Render { >> 174: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); #clear color and >> depth buffer >> 175: glLoadIdentity(); #replaces the current matrix with the >> identity matrix. >> 176: glTranslatef(0.0, 0.0, -150.0); #move to 0,0,-150 >> 177: glPushMatrix(); #save current matrix >> 178: glRotatef($objectXRot, 1.0, 0.0, 0.0); #rotate around x axis >> 179: glRotatef($objectYRot, 0.0, 1.0, 0.0); #rotate around y axis >> 180: glRotatef($objectZRot, 0.0, 0.0, 1.0); #rotate around z axis >> 181: DrawCube(); #draw cube >> 182: glPopMatrix(); #restore matrix >> 183: glFlush(); #clear buffers >> 184: SwapBuffers($g_HDC->Handle()); #exchange front and back buffers >> of device context >> 185: $objectXRot += 0.01; #increment rotation >> 186: $objectYRot += 0.02; >> 187: $objectZRot += 0.01; >> 188: } >> >> #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. >> 189: package Win32::GUI::DC; >> 190: sub Handle { >> 191: return shift->{-handle}; >> 192: } >> 193: __END__ >> >> Here are some tips and tricks regarding using Win32::GUI module and the >> OpenGL module that I have come across on my travels: >> >> Win32::GUI: >> >> It is possible to create child windows that are rendered to using OpenGL >> instead of rendering to the parent window, but requires a lot more setup. >> One of the tricks needed is to specify the right styles for the window. I >> have yet to perfect this technique, but perhaps when I get it working >> correctly I'll post an example. >> >> >> OpenGL: >> >> try to use the *_p variants of functions, if they exist. The function has >> been tweaked to behave more like a regular Perl function, such as the >> ability to accept and return arrays. This is a lot more convenient than >> having to pack() and unpack() your a arguments. Some functions don't have a >> *_p variant, so the next best thing is to use the *_c variant, which >> accept OpenGL::Array objects. The use of OpenGL::Array is not documented in >> the module, but docs can be found on the website for the module (just search >> the web for POGL). I haven't included an example of this here, since it >> requires more knowledge of OpenGL, but experienced OpenGL programmers should >> have no problems using them. >> >> >> As an alternative to creating windows using Win32::GUI, windows can be >> created using the GLUT(OpenGL Utility Toolkit) functions supplied with >> OpenGL. These can create windows that a platform-independent, as well as a >> lot of other stuff. A lot of the examples supplied for the OpenGL module use >> the GLUT, making them more portable, but OpenGL needs to be compiled with >> support for GLUT, requiring the GLUT libraries. Since I can't seem to get >> XS-implemented modules to compile properly on my machine (I use PPM >> instead), I just stick with Win32::GUI. Its all about personal preference. >> >> Well, that's it for my Win32::GUI+OpenGL example. I hope someone finds it >> useful. I'm no expert at OpenGL or the Win32 API, so there is probably a >> better way of doing this. So far this model has worked for basic >> implementations but don't expect to be able to make anything to big, such as >> games, but you never know. I'd love to hear any questions or comments about >> this example, as well as any examples of anything anyone else has done. >> >> As a side note, I'm new to posting messages on the mailing lists. I was >> wondering whether I can send pictures attached (I was hoping to show a >> screen shot of my program). Also, how do I post a reply to an existing >> thread. Any help would be much appreciated. >> >> Sorry about any typos in advance. Contact me if you find any errors with >> this post (such as with the sample program). >> >> Thanks. >> >> Kevin Marshall >> >> (kejohm88 AT hotmail DOT com) >> >> >> >> ________________________________ >> Click Here View photos of singles in your area >> >> ------------------------------------------------------------------------------ >> Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT >> is a gathering of tech-side developers & brand creativity professionals. >> Meet >> the minds behind Google Creative Lab, Visual Complexity, Processing, & >> iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian >> Group, R/GA, & Big Spaceship. http://www.creativitycat.com >> _______________________________________________ >> Perl-Win32-GUI-Users mailing list >> Perl-Win32-GUI-Users@lists.sourceforge.net >> https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users >> http://perl-win32-gui.sourceforge.net/ > > > > -- > Maximus* > WarheadsSE > MaxSource > > ------------------------------------------------------------------------------ > Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT > is a gathering of tech-side developers & brand creativity professionals. > Meet > the minds behind Google Creative Lab, Visual Complexity, Processing, & > iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian > Group, R/GA, & Big Spaceship. http://www.creativitycat.com > _______________________________________________ > Perl-Win32-GUI-Users mailing list > Perl-Win32-GUI-Users@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users > http://perl-win32-gui.sourceforge.net/ > ------------------------------------------------------------------------------ Register Now for Creativity and Technology (CaT), June 3rd, NYC. CaT is a gathering of tech-side developers & brand creativity professionals. Meet the minds behind Google Creative Lab, Visual Complexity, Processing, & iPhoneDevCamp asthey present alongside digital heavyweights like Barbarian Group, R/GA, & Big Spaceship. http://www.creativitycat.com _______________________________________________ Perl-Win32-GUI-Users mailing list Perl-Win32-GUI-Users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/perl-win32-gui-users http://perl-win32-gui.sourceforge.net/