glDrawElements with PureBasic x64

Everything related to 3D programming
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

glDrawElements with PureBasic x64

Post by applePi »

i have fallen in a pitfall when trying the OpenGl function glDrawElements in windows 7 x64 using PB571_x64
the following example works nicely with PB 32 bit, but when trying it in PB x64 it display erroneous shape, precisely half of the shape and erroneous connections between the points.

Code: Select all

Global Dim MeshDataInd(0)
glVertexPointer_(3, #GL_FLOAT, SizeOf(VertexData), @vertex(0,0)\x)
glDrawElements_(#GL_QUADS, indexsize, #GL_UNSIGNED_INT, @MeshDataInd(0))
the story is that glDrawElements function use MeshDataInd(indx) to refer to the items of vertex(0,0) data array, since MeshDataInd(indx) = "the point number of creation". it is our choice to let MeshDataInd(indx) to refer to any point and the result is either points, lines, triangles, quads.
all the time i was thinking the default variable type is Long and not Integer as the case now. so i left the Global Dim MeshDataInd(0) without the .l and in reality it is .i
looking at the Help file : By default, when a data type is not indicated, the data is an integer
Long .l 4 bytes -2147483648 to +2147483647
Integer .i 4 bytes (using 32-bit compiler) -2147483648 to +2147483647
Integer .i 8 bytes (using 64-bit compiler) -9223372036854775808 to +9223372036854775807

so the Integer type is different in PB 32 than PB x64 this is why i get half of the shape

below is the code works in PBx32 and PBx64 correctly, i have only changed to type long explicitly
Global Dim MeshDataInd.l(0)

Code: Select all

Structure VertexData
  x.f
  y.f
  z.f
  r.f
  g.f
  b.f
  tx.f
  ty.f
EndStructure


Declare FPS(timer.l)
Declare FillArray()

Define event, quit

ExamineDesktops()
OpenWindow(0, 0, 0, DesktopWidth(0), DesktopHeight(0), ".. Up/Down: zoom in/out... 'W': wire frame... 'A'/'Z': change Camera view")
SetWindowColor(0, RGB(200,220,200))
OpenGLGadget(0, 5, 5, WindowWidth(0) , WindowHeight(0) , #PB_OpenGL_Keyboard)

glMatrixMode_(#GL_PROJECTION)
glLoadIdentity_();
gluPerspective_(45.0, 800/600, 1.0, 60.0)
glMatrixMode_(#GL_MODELVIEW)
glTranslatef_(0, 0, -5)
glShadeModel_(#GL_SMOOTH)
glEnable_(#GL_DEPTH_TEST)
;glEnable_(#GL_CULL_FACE)
glColor3f_(1.0, 0.3, 0.0)
glViewport_(0, 0, 800, 600)

;resolution of the graphics grid
Global NbX=100
Global NbZ=100

Global VertexCount = (NbX+1)*(NbZ+1)
Global TexID.i


Global Dim vertex.VertexData(NbX,NbZ)
Global Dim MeshDataInd.l(0)


;Draw to texture
Dim texDat.c(512)
For i = 0 To 511
   texDat(i) = ((i + (i / 8)) % 2) * 128 + 127
Next

*Buffer = @texDat(0) 
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_NEAREST)
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_NEAREST)
glTexImage2D_(#GL_TEXTURE_2D, 0, #GL_RGB, 16, 16, 0, #GL_RGB, #GL_UNSIGNED_BYTE, *Buffer)

glEnable_(#GL_TEXTURE_2D)   ; Enable texture mapping

Global indexsize

FillArray()

;wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww

glVertexPointer_(3, #GL_FLOAT, SizeOf(VertexData), @vertex(0,0)\x) ;Vertex data is at the start of our structure VertexData
glColorPointer_(3, #GL_FLOAT, SizeOf(VertexData), @vertex(0,0)\r) ;The color data is 12 bytes below the start
glTexCoordPointer_(2, #GL_FLOAT, SizeOf(VertexData), @vertex(0,0)\tx) ;The texture data is 12 bytes below the color start

rot.f = 1

;glTranslatef_(0.0, 0.0, -2)
glViewport_(0, 0, WindowWidth(0), WindowHeight(0))
glPointSize_(3)

;the following is the camera or your eye, 0,2,3 your eyes__ 0,0,0; the object__ 0,1,0 direction
gluLookAt_( 0, 2, 3,
            0,  0, 0,
            0, 1,  0 )

SetActiveGadget(0) ; make the openGLgadget active so the keyboard can be used with it

glEnableClientState_(#GL_VERTEX_ARRAY )
glEnableClientState_(#GL_COLOR_ARRAY)
glEnableClientState_(#GL_TEXTURE_COORD_ARRAY)
 
a$=".. Up/Down: zoom in/out... 'W': wire frame... 'A'/'Z': change Camera view" 
 
Repeat
 
  fps$ = Str(FPS(1000))
  SetWindowTitle(0,"FPS  = " +fps$+ "  "+a$)
  
  ;glClearColor_(0.1, 0.1, 0.5, 1) ; color of the window
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
  glRotatef_(rot/2, 0, 1, 0);
    
  ;glPointSize_(2)
  glDrawElements_(#GL_QUADS, indexsize, #GL_UNSIGNED_INT, @MeshDataInd(0))
  ;glDrawElements_(#GL_POINTS,indexsize,#GL_UNSIGNED_INT, @MeshDataInd(0))
 
 Repeat
    event = WindowEvent()
    If event = #PB_Event_CloseWindow
      quit = #True
    EndIf
    If Event = #PB_Event_Gadget And EventGadget() = 0
    If EventType() = #PB_EventType_KeyDown  ; like KeyboardReleased
            key = GetGadgetAttribute(0,#PB_OpenGL_Key )
           
               If key = #PB_Shortcut_Escape ;  Esc key to exit
               quit = 1
           
               ElseIf Key = #PB_Shortcut_W; display wire Frame or solid frame
               If fill = 0
                glPolygonMode_(#GL_FRONT_AND_BACK, #GL_LINE )
                fill ! 1
               Else
                glPolygonMode_(#GL_FRONT_AND_BACK, #GL_FILL)
                fill ! 1
              EndIf
              ElseIf Key = #PB_Shortcut_Up
                glScalef_(1.05,1.05,1.05)
              ElseIf Key = #PB_Shortcut_Down
                glScalef_(0.95,0.95,0.95)
              ElseIf Key = #PB_Shortcut_A
                glMatrixMode_(#GL_MODELVIEW);
                glLoadIdentity_()           ;
                ;gluLookAt_(0, 40, 14,  0,0,0,  0,1,0 )
                gluLookAt_(0, 5, 1,  0,0,0,  0,1,0 )
              ElseIf Key = #PB_Shortcut_Z
               glMatrixMode_(#GL_MODELVIEW);
                glLoadIdentity_();
                ;gluLookAt_(0, 0.3, 0.5,  0,0,0,  0,1,0 ) 
                gluLookAt_(0, 3, 5,  0,0,0,  0,1,0 ) 
                               
            EndIf
               
    EndIf
   EndIf
  Until event = 0 Or quit = #True
 
  SetGadgetAttribute(0, #PB_OpenGL_FlipBuffers, #True)
 
  Delay(1)
Until quit = #True
glDisableClientState_(#GL_TEXTURE_COORD_ARRAY)
glDisableClientState_(#GL_COLOR_ARRAY)
glDisableClientState_(#GL_VERTEX_ARRAY)

 
Procedure FillArray()
 
xMin.f = -2 : yMin.f = -2: zMin.f = -2 : xMax.f = 2: yMax = 2 : zMax = 2
  range = xMax - xMin
  step1.f = range / NbX
  x.f = xMin: z.f = zMin : y.f = yMin : v.l = 0
   
  For b=0 To NbZ
   
    For a=0 To NbX
     
       y.f = Cos(x*x+z*z)
           
      ;**********************************************************************           
     
      vertex(a,b)\x = x*1
      vertex(a,b)\y = y*1 ; just amplify the height
      vertex(a,b)\z = z*1
     
      vertex(a,b)\tx = a/NbX
      vertex(a,b)\ty = b/NbZ
      
      vertex(a,b)\r = 1 :vertex(a,b)\g = 1 :vertex(a,b)\b = 1
     
      If y > 0.5
        ;vertex(a,b)\r = 0.9 :vertex(a,b)\g = 0.0 :vertex(a,b)\b = 0
      ElseIf y>=-0.3
        ;vertex(a,b)\r = 0.2 :vertex(a,b)\g = 0.9 :vertex(a,b)\b = 0
        Else
        ;vertex(a,b)\r = 1.0 :vertex(a,b)\g = 1.0 :vertex(a,b)\b = 0
      EndIf
     
      x.f + step1
        
    Next a
   
    x = xMin
    z.f + step1
   
  Next b
 
   ;ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
 
  Nb=NbX+1
 
  For b=0 To NbZ-1
    For a=0 To NbX-1
     
      P1=a+(b*Nb)
      P2=P1+1
      P3=a+(b+1)*Nb
      P4=P3+1

      MeshDataInd(indx) = P3
      ReDim MeshDataInd(indx+2)
      MeshDataInd(indx+1) = P4
      ReDim MeshDataInd(indx+3)
      MeshDataInd(indx+2) = P2
      ReDim MeshDataInd(indx+4)
      MeshDataInd(indx+3)= P1;P2
 
      indx+4
    Next
  Next
  indexsize = ArraySize(MeshDataInd()) + 1
  
EndProcedure

Procedure FPS(timer.l) ; the code is from the forum somewhere
  Static FPSCount.l, FPS.l
  Static delay.l
  Protected t.l
  If timer = 0
    ProcedureReturn -1
  EndIf
  t = ElapsedMilliseconds()
  If t-delay > timer
    FPS = FPSCount*1000/timer
    FPSCount = 0
    delay = t
  Else
    FPSCount+1
  EndIf
  ProcedureReturn FPS
EndProcedure
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: glDrawElements with PureBasic x64

Post by IdeasVacuum »

Hi ApplePi

That's a very interesting issue you have discovered.

Turns out there is a 64bit lib and a 32bit lib and they are both named opengl32.lib for historical reasons:
https://stackoverflow.com/questions/123 ... it-windows

PB571 LTS bug!

I'm not sure if we can simply overwrite the PB lib with the 64bit version - there are other associated PB files.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5353
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: glDrawElements with PureBasic x64

Post by Kwai chang caine »

Nice "hat" thanks for sharing 8)
Works fine on W10 X64 / v5.70 x86
ImageThe happiness is a road...
Not a destination
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: glDrawElements with PureBasic x64

Post by applePi »

Thank you IdeasVacuum and KCC , the link to stackoverflow is interesting, it is strange that Opengl32.dll still have its name in windows x64 and not Opengl64.dll for historical reasons
in purebasic Ogre 3d the function MeshIndex play the same rule played by glDrawElements with index array with a slight change. in fact the EXE from the following code compiled with Library subsystems opengl contains glDrawElements in its source code and long lines like this

Code: Select all

glClientActiveTextureARB(GL_TEXTURE0)
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER,20)
glDrawElements(GL_TRIANGLES,6,GL_UNSIGNED_SHORT,0x0000) Textures[ (0,9) ] 
this is captured using the tool: GLXtractor viewtopic.php?f=36&t=53022#p520998
the long captured code is in CapLog.txt file

the following is working okay in windows 32 and 64
i just have inverted the Hat curve to be able to catch a falling football:

Code: Select all

#Camera   = 0

If InitEngine3D()
 
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Textures", #PB_3DArchive_FileSystem)
  Add3DArchive(#PB_Compiler_Home + "examples/3d/Data/Scripts", #PB_3DArchive_FileSystem)
  Parse3DScripts()
 
  InitSprite()
  InitKeyboard()
  InitMouse()
 
  OpenWindow(0, 0, 0, 800, 600, "MeshIndex .......... W: wireFrame/Textured", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
  OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 0, 0, 0)
   
    ;- Material
    CreateMaterial(0, LoadTexture(0, "MRAMOR6X6.jpg"))
    DisableMaterialLighting(0, #True)
    MaterialCullingMode(0, #PB_Material_NoCulling)
    ;MaterialShadingMode(0, #PB_Material_Wireframe)

   
    ;- Mesh Plane (using triangles)
    CreateMesh(0, #PB_Mesh_TriangleList, #PB_Mesh_Static)
    ;CreateMesh(0, #PB_Mesh_LineList, #PB_Mesh_Static)
    ;CreateMesh(0, #PB_Mesh_PointList, #PB_Mesh_Static)
   
       
  Global NbX =50
  Global NbZ =50
  
  Define.w P1, P2, P3, P4
  xMin.f = -2 : yMin.f = -2: zMin.f = -2 : xMax.f = 2: yMax = 2 : zMax = 2
  range.f = xMax - xMin  
  step1.f = range / NbX
  x.f = xMin: z.f = zMin : y.f = yMin 
   
  For b=0 To NbZ
    For a=0 To NbX
      y.f = Cos(x*x+z*z)
      MeshVertexPosition(x*2, y*2, z*2 )
      MeshVertexNormal(0,1,0)
      MeshVertexTextureCoordinate(Abs(x)/2, Abs(z)/2)
      x + step1
    
  Next a
    x = xMin
    z.f + step1
  Next b
 
  Nb=NbX+1
 
  For b=0 To NbZ-1
    For a=0 To NbX-1
            
      P1=a+(b*Nb)
      P2=P1+1
      P3=a+(b+1)*Nb
      P4=P3+1
      
      ;MeshFace(P3, P2, P1)
      ;MeshFace(P2, P3, P4)

      MeshIndex(P3) ; refer to point P3
      MeshIndex(P2)
      MeshIndex(P1)
      
      MeshIndex(P2)
      MeshIndex(P3)
      MeshIndex(P4)
      
    Next
  Next
 FinishMesh(#True) 
    
    SetMeshMaterial(0, MaterialID(0))
    Plane2 = CreateEntity(#PB_Any, MeshID(0), MaterialID(0) , 0, 0, 0)
    ;-Camera
    CreateCamera(0, 0, 0, 100, 100)
    MoveCamera(0, 0, 10, 15, #PB_Absolute)
    CameraFOV(0, 40)
    CameraLookAt(0, 0,  0,  0)
    CameraBackColor(0, RGB(0, 0, 40))
    
    ;-Light
    CreateLight(0, RGB(255,255,255), -10, 60, 10)
    AmbientColor(RGB(90, 90, 90))
    
    RotateEntity(plane2, 180,0,0)
    CreateEntityBody(plane2, #PB_Entity_StaticBody )
    
    RedMaterial   = GetScriptMaterial(#PB_Any, "Color/Red")
    CreateSphere(1, 1)
    CreateEntity(1, MeshID(1), MaterialID(RedMaterial), 0, 5,0)
    CreateEntityBody(1, #PB_Entity_SphereBody )
    
    Repeat
      Repeat   
      Event = WindowEvent()
      If Event = #PB_Event_CloseWindow  ; If the user has pressed on the close button
        Quit = 1
      EndIf  
      
      Until Event = 0
           
      ExamineKeyboard()
      If KeyboardReleased(#PB_Key_W)
        If fill = 0
               CameraRenderMode(0, #PB_Camera_Wireframe) 
               fill ! 1
               Else
               CameraRenderMode(0, #PB_Camera_Textured )
               fill ! 1
        EndIf
        
      EndIf
            
      RotateEntity(Plane2, 0, 0.3, 0, #PB_Relative) 
      RenderWorld()
      
      FlipBuffers()
    Until KeyboardPushed(#PB_Key_Escape) Or Quit = 1
  
EndIf

End

Note: the code depends on 3d examples inside PureBasic distribution especially MeshManual2.pb and SetMeshData.pb
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: glDrawElements with PureBasic x64

Post by IdeasVacuum »

From the OpenGL Spec:
https://www.khronos.org/registry/OpenGL ... ents.xhtml

void glDrawElements( GLenum mode,GLsizei count, GLenum type, const void * indices);

type: Specifies the type of the values in indices. Must be one of GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
applePi
Addict
Addict
Posts: 1404
Joined: Sun Jun 25, 2006 7:28 pm

Re: glDrawElements with PureBasic x64

Post by applePi »

#GL_UNSIGNED_BYTE : 8-bit unsigned integer
#GL_UNSIGNED_SHORT : 16-bit unsigned integer
#GL_UNSIGNED_INT : 32-bit unsigned integer

https://www.khronos.org/opengl/wiki/OpenGL_Type
i have done some experiments about GL_UNSIGNED_BYTE
the important lines:
glVertexPointer_(3, #GL_BYTE, SizeOf(Point3D), @Vertex(0)\x)
glDrawElements_(#GL_LINE_STRIP,indexsize,#GL_UNSIGNED_BYTE, @index(0))

we can't assign 300 to index(?): index(500)=300 . it should be <=255, so the end dimension of Vertex(?) can be Vertex(255) but not Vertex(256)
Dim index.b(600) the same as Dim index.a(600). we can have the number of indexes as we want , infinite.
i tested these things in windows xp 32

Code: Select all

Structure Point3D
  x.b
  y.b
  z.b
  r.f
  g.f
  b.f
  
EndStructure

OpenWindow(0, 70, 50, 640, 480, "glDrawElements with GL_UNSIGNED_byte")
SetWindowColor(0, 0)
OpenGLGadget(0, 0, 0, WindowWidth(0) , WindowHeight(0))

Dim Vertex.Point3D(300)

Vertex(0)\x = 0
Vertex(0)\y = 1
Vertex(0)\z = 0

Vertex(1)\x = -1
Vertex(1)\y = -1
Vertex(1)\z = 0

Vertex(2)\x = 1
Vertex(2)\y = -1
Vertex(2)\z = 0

Vertex(3)\x = 2
Vertex(3)\y = 1
Vertex(3)\z = 0

Vertex(255)\x = -2
Vertex(255)\y = 1
Vertex(255)\z = 0

Vertex(0)\r = 1 : Vertex(0)\g = 0: Vertex(0)\b = 0
Vertex(1)\r = 0 : Vertex(1)\g = 1: Vertex(1)\b = 0
Vertex(2)\r = 0 : Vertex(2)\g = 0: Vertex(2)\b = 1
Vertex(3)\r = 1 : Vertex(3)\g = 1: Vertex(3)\b = 0
Vertex(255)\r = 0 : Vertex(255)\g = 1: Vertex(255)\b = 0


Dim index.b(600)
index(0) = 0 
index(1) = 1
index(2) = 2
index(600) = 3
index(500) = 255

indexsize = ArraySize(index()) + 1
Debug "index size = " + Str(indexsize)
rot.f = 0
Repeat
  glViewport_(0, 0, WindowWidth(0), WindowHeight(0))
  glMatrixMode_(#GL_PROJECTION)
  glLoadIdentity_()
  gluPerspective_(30.0, Abs(WindowWidth(0) / WindowHeight(0)), 0.1, 500.0)
  glMatrixMode_(#GL_MODELVIEW)
  glLoadIdentity_()
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
  glLoadIdentity_()
  glTranslatef_(0.0, 0.0, -8.0)
  
  
  glEnableClientState_(#GL_VERTEX_ARRAY )
  glEnableClientState_(#GL_COLOR_ARRAY)
    
  glVertexPointer_(3, #GL_BYTE,SizeOf(Point3D),@Vertex(0)\x)
  glColorPointer_(3, #GL_FLOAT, SizeOf(Point3D), @Vertex(0)\r) 
  
  rot+1
  glRotatef_(rot, 0, 1, 0);
  glPointSize_(10)
  glLineWidth_(10)
  glDrawElements_(#GL_LINE_STRIP,indexsize,#GL_UNSIGNED_BYTE, @index(0))

  glDisableClientState_(#GL_VERTEX_ARRAY);
  glDisableClientState_(#GL_COLOR_ARRAY)
  
  
  SetGadgetAttribute(0, #PB_OpenGL_FlipBuffers, #True)
Until WindowEvent() = #PB_Event_CloseWindow
to display this triangle by shardik viewtopic.php?f=12&t=49583&start=30 with glDrawElements and #GL_UNSIGNED_BYTE

Code: Select all

Structure Point3D
  x.b
  y.b
  z.b
  r.f
  g.f
  b.f
  
EndStructure

OpenWindow(0, 70, 50, 640, 480, "glDrawElements with GL_UNSIGNED_byte")
SetWindowColor(0, 0)
OpenGLGadget(0, 0, 0, WindowWidth(0) , WindowHeight(0))

Dim Vertex.Point3D(2)

Vertex(0)\x = 0
Vertex(0)\y = 1
Vertex(0)\z = 0

Vertex(1)\x = -1
Vertex(1)\y = -1
Vertex(1)\z = 0

Vertex(2)\x = 1
Vertex(2)\y = -1
Vertex(2)\z = 0

Vertex(0)\r = 1 : Vertex(0)\g = 0: Vertex(0)\b = 0
Vertex(1)\r = 0 : Vertex(1)\g = 1: Vertex(1)\b = 0
Vertex(2)\r = 0 : Vertex(2)\g = 0: Vertex(2)\b = 1

Dim index.b(3)
index(0) = 0 
index(1) = 1
index(2) = 2

indexsize = ArraySize(index()) + 1
rot.f = 0
Repeat
  glViewport_(0, 0, WindowWidth(0), WindowHeight(0))
  glMatrixMode_(#GL_PROJECTION)
  glLoadIdentity_()
  gluPerspective_(30.0, Abs(WindowWidth(0) / WindowHeight(0)), 0.1, 500.0)
  glMatrixMode_(#GL_MODELVIEW)
  glLoadIdentity_()
  glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
  glLoadIdentity_()
  glTranslatef_(0.0, 0.0, -8.0)
  
  
  glEnableClientState_(#GL_VERTEX_ARRAY )
  glEnableClientState_(#GL_COLOR_ARRAY)
    
  glVertexPointer_(3, #GL_BYTE,SizeOf(Point3D),@Vertex(0)\x)
  glColorPointer_(3, #GL_FLOAT, SizeOf(Point3D), @Vertex(0)\r) 
  
  rot+1
  glRotatef_(rot, 0, 1, 0);
  ;glPointSize_(10)
  ;glLineWidth_(10)
  glDrawElements_(#GL_TRIANGLES,indexsize,#GL_UNSIGNED_BYTE, @index(0))

  glDisableClientState_(#GL_VERTEX_ARRAY);
  glDisableClientState_(#GL_COLOR_ARRAY)
  
  
  SetGadgetAttribute(0, #PB_OpenGL_FlipBuffers, #True)
Until WindowEvent() = #PB_Event_CloseWindow
Post Reply