Tomb Posted June 29, 2013 Share Posted June 29, 2013 (edited) I have been working with OpenGL recently seeing if I could rewrite the GDI graphics end of the game engine I have been working on. '?do=embed' frameborder='0' data-embedContent>> It has been going well and I have been making a lot of progress so far. Most recently I changed the perspective to isometric view (see the top left image). I then decided as a test to make the entire view rotateable. (top right and bottom left images) This all worked but as you can imagine, tile picking doesn't work anymore. I have been looking into the best way to do the tile picking and came to a conclusion that there are 3 methods. Ray casting, using the GL_SELECT rendering mode, or using color picking on an underlying and never visible layer when necessary. I decided on color picking by assigning each tile a color (bottom right image) and using the GlReadPixel function at the mouse coordinates. I would only need to check the colors on mouse clicks and drawing the color tiles in a display list made for little to no speed loss. Unfortunately I can't seem to get the GlReadPixels function to work properly. I found two variations of the function in searches. Func _glReadPixels($x, $y, $width, $height, $format, $type, ByRef $pixels) DllCall( 'opengl32.dll', 'none', 'glReadPixels', _ 'int', $x, _ 'int', $y, _ 'int', $width, _ 'int', $height, _ 'uint', $format, _ 'uint', $type, _ 'ptr', DllStructGetPtr( $pixels)) EndFunc Func glReadpixels($x, $y, $width, $height, $format, $type, $pixels) DllCall("opengl32.dll", "none", "glReadpixels", "int", $x, "int", $y, "int", $width, "int", $height, "uint", $format, "uint", $type, "dword", $pixels) EndFunc I have been trying all sort of guess and test calls to get the correct return values which should be floats of the red, green, and blue values or even integers between 0 and 255 representing the values but can't seem to get the function to return anything but 0. I'm not very knowlegeable about pointers and dllstructs and was wondering if anyone could help please. Some things I have tried: Opt("MouseCoordMode", 2) ;to ensure correct window based coordinates $Mouse = MouseGetPos() $tColors = DllStructCreate("BYTE[10]") ;also tested as a float Global $pColors = DllStructGetPtr($tColors) _glReadpixels($Mouse[0], $Mouse[1], 1, 1, $GL_RGBA, $GL_UNSIGNED_BYTE, $pColors) MsgBox(0, "", DllStructGetData($tColors, 1)) Msdn states that the correct function syntax would be as follows: void WINAPI glReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels ); I would appreciate any help with this. Thanks. Edited June 29, 2013 by Tomb Link to comment Share on other sites More sharing options...
LarsJ Posted June 30, 2013 Share Posted June 30, 2013 (edited) Hi Tomb,I've just seen your message (I'm not logged on every day) and this problem. I think your code looks fine, but I'm pretty sure that "glReadpixels" in the DllCall is with a capital p: "glReadPixels". And I do think that matters. (I see now that you have a capital p in the first function.)This function works for me:Func glReadPixels($x, $y, $width, $height, $format, $type, $pixels) DllCall("opengl32.dll", "none", "glReadPixels", "int", $x, "int", $y, "int", $width, "int", $height, "uint", $format, "uint", $type, "ptr", $pixels) If @error Then MsgBox( 0, "glReadPixels", "Error" ) EndFuncRegards Lars. Edited June 30, 2013 by LarsJ Tomb 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
LarsJ Posted June 30, 2013 Share Posted June 30, 2013 (edited) I use this code for a screen dump of an OpenGL window:Local Static $iDump = 0 If $iDump = 0 Then Local $tBuffer = DllStructCreate( "byte[" & $iWidth * $iHeight * 3 & "]" ) glReadPixels( 0, 0, $iWidth, $iHeight, $GL_RGB, $GL_UNSIGNED_BYTE, DllStructGetPtr( $tBuffer ) ) Local $hFile = FileOpen( "image.data", 18 ) FileWrite( $hFile, DllStructGetData( $tBuffer, 1 ) ) FileClose( $hFile ) $iDump = 1 EndIfI just add the code to the display function.The raw RGB/RGBA image file "image.data" can be opened with GIMP (the extension must be "data"). Edited June 30, 2013 by LarsJ Tomb 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
Tomb Posted July 2, 2013 Author Share Posted July 2, 2013 Thank you for your help LarsJ. With your example and function I managed to get the right return values. Now I can determine where the player clicks regardless of world rotation Link to comment Share on other sites More sharing options...
LarsJ Posted July 3, 2013 Share Posted July 3, 2013 Good to see that it works.The code can be slightly optimized. You don't need DllStructGetPtr():Func glReadPixels( $x, $y, $width, $height, $format, $type, $pixels ) DllCall( "opengl32.dll", "none", "glReadPixels", "int", $x, "int", $y, "int", $width, "int", $height, "uint", $format, "uint", $type, "struct*", $pixels ) EndFunc Local Static $iDump = 0 If $iDump = 0 Then Local $tBuffer = DllStructCreate( "byte[" & $iWidth * $iHeight * 3 & "]" ) glReadPixels( 0, 0, $iWidth, $iHeight, $GL_RGB, $GL_UNSIGNED_BYTE, $tBuffer ) Local $hFile = FileOpen( "image.data", 18 ) FileWrite( $hFile, DllStructGetData( $tBuffer, 1 ) ) FileClose( $hFile ) $iDump = 1 EndIfIf you have a small example that shows how you do that tile picking, I would like to see it.Regards Lars. Tomb 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
Tomb Posted July 12, 2013 Author Share Posted July 12, 2013 (edited) Hey LarsJ. Thanks for posting this example its a neat optimization to get rid of the unnecessary DllStructGetPtr call. I was trying to put together a small stripped down working example but decided I should just post the code snippets for now where the tile picking happens. First the map is loaded into an array and I create two display lists of the data so that I can quickly redraw the map every loop. expandcollapse popup$MapList = glGenLists(1) $ColorMapList = glGenLists(1) GLNewList($MapList, $GL_COMPILE) For $X = 1 to 12 For $Y = 1 to 12 DrawSprite2($X * 50 - 50, $Y * 50 - 50, 50, 50, 0, $Map[$X][$Y][0] - 1, 0) Next Next GLEndList() GLNewList($ColorMapList, $GL_COMPILE) glDisable($GL_TEXTURE_2D) For $X = 1 to 12 For $Y = 1 to 12 _glPushMatrix() _glTranslatef($X * 50 - 50, $Y * 50 - 50, 0) glBegin($GL_QUADS) glColor3f($X / 15, $Y / 15, 1.0) _glVertex3i(0, 0, 0) _glVertex3i(50, 0, 0); _glVertex3i(50, 50, 0); _glVertex3i(0, 50, 0); glEnd() glColor3f(1.0, 1.0, 1.0) _glPopMatrix() Next Next glEnable($GL_TEXTURE_2D) GLEndList() The first display list, $MapList is a collection of the map tiles that will be drawn where the other display list ColorMapList just contains colors which are calculated based on the coordinates. DrawSprite2 is just a reusable function I made for placing the textured quads. expandcollapse popupFunc DrawSprite2($X, $Y, $W, $H, $R, $CurrentFrame = 0, $D = 0) Local $SpriteWidth = $W Local $SpriteHeight = $H Local $CalcW = $ImageHeight / $SpriteHeight _glPushMatrix() _glTranslatef($X, $Y, $D) $x_cell = $CurrentFrame * $cell_division $x_cell2 = ($CurrentFrame * $cell_division) + $cell_division If $R <> 0 Then _glTranslatef($W / 2, $H / 2, 0.0) _glRotatef($R, 0.0, 0.0, 1.0) _glTranslatef(-$W / 2, -$H / 2, 0.0) EndIf glBegin($GL_QUADS) _glTexCoord2d($x_cell, 0.0) _glVertex3i(0, 0, 0) _glTexCoord2d($x_cell2, 0.0) _glVertex3i($SpriteWidth, 0, 0); _glTexCoord2d( $x_cell2, 1.0 /$CalcW) _glVertex3i( $SpriteWidth, $SpriteHeight, 0); _glTexCoord2d( $x_cell, 1.0 /$CalcW) _glVertex3i(0, $SpriteHeight, 0); glEnd() _glPopMatrix() EndFunc For this current test I am only using tile picking when the left mouse is down. If the mouse is down, I draw the color map and check the pixel color, calculate which tile is under the mouse, clear the buffers, and draw the normal map. If BitAND($aKeyBoardState[01], 0xF0) > 0 Then GLDisable($GL_LIGHTING) glCallList($ColorMapList) Local $iWidth = 1 Local $iHeight = 1 Local $tBufferR = DllStructCreate( "float[" & $iWidth * $iHeight * 1 & "]" ) glReadPixels( $MouseX, $CurrentHeight - $MouseY, $iWidth, $iHeight, $GL_RED, $GL_FLOAT, $tBufferR) Local $tBufferG = DllStructCreate( "float[" & $iWidth * $iHeight * 1 & "]" ) glReadPixels( $MouseX, $CurrentHeight - $MouseY, $iWidth, $iHeight, $GL_GREEN, $GL_FLOAT, $tBufferG) ;Local $tBufferB = DllStructCreate( "float[" & $iWidth * $iHeight * 1 & "]" ) ;glReadPixels( $Mouse[0], 600 - $Mouse[1], $iWidth, $iHeight, $GL_BLUE, $GL_FLOAT, DllStructGetPtr( $tBufferB ) ) $col = Round(DllStructGetData($tBufferR, 1) * 15 - 1) $row = Round(DllStructGetData($tBufferG, 1) * 15 - 1) _glClear($GL_COLOR_BUFFER_BIT + $GL_DEPTH_BUFFER_BIT) GLEnable($GL_LIGHTING) EndIf glCallList($MapList) I separated the red and green values into their own glReadPixels calls for now to keep things simple. Unfortunately drawing the color map can be a little slow so for now I just check position on mouse clicks which works good but doesn't allow hover tile picking for tooltips or other sort of things. Although it does work great for determining which tile was clicked. Hopefully the code doesn't make this post too long but I wanted to ask you one more question. I saw your examples using glCallLists to draw text and was trying to use glCallLists for non-text calls to merge the calls into a single call. For example using _glTranslatef once to set the draw position and draw a bunch of lists at the translated position using glCallLists instead of calling each list separately. Display lists at different locations would need to be translated and drawn separately which is fine. I was just thinking it might be a possible optimization. I tried something like this: expandcollapse popup$ListArray = glGenLists(10) For $i = 0 to 10 glDisable($GL_TEXTURE_2D) GLNewList($ListArray + $i, $GL_COMPILE) _glPushMatrix() _glTranslatef($i * 50 - 50, 0, 1) glBegin($GL_QUADS) glColor3f(Random(0, 1, 1), Random(0, 1, 1), 1.0) _glVertex3i(0, 0, 0) _glVertex3i(50, 0, 0); _glVertex3i(50, 50, 0); _glVertex3i(0, 50, 0); glEnd() glColor3f(1.0, 1.0, 1.0) _glPopMatrix() GLEndList() glEnable($GL_TEXTURE_2D) Next ------------------------------------------ _glPushMatrix() _glTranslatef(0, 0, 100.0) Global $Arrays[10] $Arrays[0] = 0 $Arrays[1] = 1 $Arrays[2] = 2 $Arrays[3] = 3 $Arrays[4] = 4 $Arrays[5] = 5 $Arrays[6] = 6 $Arrays[7] = 7 $Arrays[8] = 8 $Arrays[9] = 9 glListBase($ListArray) glCallLists(10, $GL_UNSIGNED_BYTE, $Arrays) _glPopMatrix() But unfortunately none of the Display Lists appeared. Although a simple glCallList($ListArray + 1) worked. Sorry for the delayed response and massive post, and thank you for your help! Edited July 12, 2013 by Tomb Link to comment Share on other sites More sharing options...
LarsJ Posted July 14, 2013 Share Posted July 14, 2013 What a lot of writing. And code too. Thank you. I have not had time to look at it yet. But I will look into it.glCallLists. There is nothing wrong with your code. But there was a bug in my code. You have my apologies. You can find a flawless function here: Func glCallLists( $n, $type, $lists ) If IsString( $lists ) Then If $type <> $GL_UNSIGNED_BYTE Then Return SetError( 1, 0, 0 ) DllCall( $dllOpenGL32, "none", "glCallLists", "int", $n, "uint", $type, "str", $lists ) If @error Then Return SetError( 3, 0, 0 ) ElseIf IsArray( $lists ) And UBound( $lists, 0 ) = 1 Then Local $sType, $l = UBound( $lists ), $struct Switch $type Case $GL_BYTE, $GL_UNSIGNED_BYTE $sType = "byte" Case $GL_SHORT $sType = "short" Case $GL_UNSIGNED_SHORT $sType = "ushort" Case $GL_INT $sType = "int" Case $GL_UNSIGNED_INT $sType = "uint" Case $GL_FLOAT $sType = "float" Case Else Return SetError( 1, 0, 0 ) EndSwitch $struct = DllStructCreate( $sType & "[" & $l & "]" ) For $i = 0 To $l - 1 DllStructSetData( $struct, 1, $lists[$i], $i + 1 ) Next DllCall( $dllOpenGL32, "none", "glCallLists", "int", $n, "uint", $type, "struct*", $struct ) If @error Then Return SetError( 3, 0, 0 ) Else Return SetError( 1, 0, 0 ) EndIf EndFuncRegards Lars. Tomb 1 Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
Tomb Posted July 18, 2013 Author Share Posted July 18, 2013 Thank you very much for the new function LarsJ. It works perfectly and can be a great optimization to draw lots of things with fewer calls! I appreciate all of your help with getting the OpenGL functions working correctly. Link to comment Share on other sites More sharing options...
LarsJ Posted July 18, 2013 Share Posted July 18, 2013 Thank you for pointing out the bug. I had only tested the first part of the function where $lists is a string. I had not seen this error. Controls, File Explorer, ROT objects, UI Automation, Windows Message MonitorCompiled code: Accessing AutoIt variables, DotNet.au3 UDF, Using C# and VB codeShell menus: The Context menu, The Favorites menu. Shell related: Control Panel, System Image ListsGraphics related: Rubik's Cube, OpenGL without external libraries, Navigating in an image, Non-rectangular selectionsListView controls: Colors and fonts, Multi-line header, Multi-line items, Checkboxes and icons, Incremental searchListView controls: Virtual ListViews, Editing cells, Data display functions Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now