View Full Version : [TBGL] Question about TBGL_DrawFrame
For the past week I've been porting a simple Java program over to thinBasic. It's nothing impressive, it just draws an image on the screen. The pseudo code for the drawing routine looks much like the following.
For x = 1 To %winWidth
For y = 1 To %winHeight
Next
TBGL_DrawFrame
Next
I've placed TBGL_DrawFrame between the two Next commands so that the User can see the image being drawn on the screen, however as it's being drawn it flickers quite badly. The ways that I've found to overcome this are to use glDrawBuffer(%GL_FRONT_AND_BACK) or use glDrawBuffer(%GL_FRONT) and glFlush().
Is there a TBGL way of overcoming the flickering without resorting to native OpenGL commands?
Petr Schreiber
28-11-2015, 19:52
Hi Matthew,
always so pleasant to see you here :) Please, if you can, share the code and I can check for the possible root cause of flicker.
If you prefer to not share here at the moment, just send it at petrschreiber@thinbasic.com.
Petr
Hi Petr don't worry the program I'm writing isn't Top Secret, I'm happy to share. :-)
Prepare yourself for a lot of links. After reading this (http://forum.basicprogramming.org/index.php/topic,5127.0.html) thread on the BASIC programming forum I was interested in finding out more about Voronoi diagrams (https://en.wikipedia.org/wiki/Voronoi_diagram). I ended up finding this (http://rosettacode.org/wiki/Voronoi_diagram#Java) Java program on Rosetta Code, so I thought I'd port it to different dialects of BASIC. So-far I've ported it to FreeBASIC and Basic4GL. I should add that both versions flickered just the same until I started using glDrawBuffer(%GL_FRONT_AND_BACK).
The program is a bit slow (and uncommented) at the moment but I hope in the future to make it a bit faster by using GBuffers and Oxygen.
Uses "TBGL"
#INCLUDE "%app_includepath%\thinbasic_gl.inc"
Randomize
Dim hWnd As DWord
%winWidth = 640
%winHeight = 480
%winDepth = 32
hWnd = TBGL_CreateWindowEx("Voronoi diagram", %winWidth, %winHeight, %winDepth, %TBGL_WS_WINDOWED | %TBGL_WS_DONTSIZE | %TBGL_WS_CLOSEBOX)
TBGL_ShowWindow
TBGL_RenderMatrix2D ( 0, %winHeight, %winWidth, 0)
TBGL_BackColor 0, 0, 0, 0
' glDrawBuffer(%GL_FRONT_AND_BACK)
' glDrawBuffer(%GL_FRONT)
Long sites = 10
Long townX(sites), townY(sites)
Long colR(sites), colG(sites), colB(sites)
Long i, n, x, y
Long appRunning = %FALSE
For i = 1 To sites
townX(i) = Rnd(0, %winWidth)
townY(i) = Rnd(0, %winHeight)
colR (i) = Rnd(0, 255)
colG (i) = Rnd(0, 255)
colB (i) = Rnd(0, 255)
Next
TBGL_ResetKeyState()
While TBGL_IsWindow(hWnd)
TBGL_ClearFrame
For x = 1 To %winWidth
For y = 1 To %winHeight
n = 1
For i = 1 To sites
If VoronoiDistance(townX(i), x, townY(i), y) < VoronoiDistance(townX(n), x, townY(n), y) Then
n = i
EndIf
Next
TBGL_BeginPoly(%GL_POINTS)
TBGL_Color(colR(n), colG(n), colB(n))
TBGL_Point(x, y)
TBGL_EndPoly
Next
DoEvents
If TBGL_GetWindowKeyOnce(hWnd, %VK_ESCAPE) Then Exit For
TBGL_DrawFrame
' glFlush()
Next
If appRunning = %FALSE Then Exit While
Wend
TBGL_DestroyWindow
Function VoronoiDistance(x1, x2, y1, y2 As Long) As Double
Dim distance As Double
distance = Sqr(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)))
Return distance
End Function
not your demo matthew but the first example in http://forum.basicprogramming.org/index.php/topic,5127.0.html
it produced the same shape almost instantly. its 2D inside 3D so we can rotate it (uncomment line 40)
not optimized , i just filled Petr code about using oxygen for the math hard task and Gbuffers to store the arrays here http://www.thinbasic.com/community/showthread.php?12619-Boosting-calculation-speed-using-compilers-DLLs-%28such-as-FreeBasic%29&p=92365#post92365
the most important lines is:
Dim oVertexA() At #VertexA As TBGL_TVECTOR3F
Dim oColorA() At #ColorA As TBGL_TRGB
since it connects the arrays oVertexA to arrays VertexA, it seems oVertexA dimensioned as necessary.
the arrays is linear but we project the 2D point in the above page to 1D like this:
ind = (yy-1)*640 + xx
oVertexA(ind).x = xx
9414
Uses "TBGL", "math", "Oxygen"
Function TBMain()
Local hWnd As DWord
Local FrameRate As Double
' -- Create and show window
hWnd = TBGL_CreateWindowEx("Plotting 3D Data in an array using GBuffers- Calculate with Oxygen JIT ..Esc to quit", 600, 600, 32, %TBGL_WS_WINDOWED Or %TBGL_WS_CLOSEBOX)
TBGL_ShowWindow
TBGL_BackColor 255,255,255
' -- Create 3D points buffer
DWord gbPoints = TBGL_GBufferCreate(%TBGL_POINTS, %TBGL_3D)
Global Nb As DWord = 1000000
' -- Define data for it
Global VertexA(Nb) As TBGL_TVECTOR3F ' single
Global ColorA(Nb) As TBGL_TRGB ' Byte
FillArrays()
' -- Create buffer dynamically linked to the arrays above
TBGL_GBufferDefineFromArray(gbPoints, %TBGL_DYNAMIC, CountOf(VertexA), VertexA(1), ColorA(1))
' -- Resets status of all keys
TBGL_ResetKeyState()
'TBGL_PointSize 2
' -- Main loop
While TBGL_IsWindow(hWnd)
'init
FrameRate = TBGL_GetFrameRate
TBGL_ClearFrame
TBGL_Camera(0, 0, 40, 0, 0, 0)
' -- Turn triangle
'TBGL_Rotate GetTickCount/50, 0, 1, 0
TBGL_Scale 0.045, 0.045, 1
TBGL_Translate -320, -320
' -- Render it
TBGL_GBufferRender(gbPoints)
TBGL_DrawFrame
' -- ESCAPE key to exit application
If TBGL_GetWindowKeyState(hWnd, %VK_ESCAPE) Then Exit While
Wend
' -- Destroying the buffer is not necessary,
' -- the garbage collector will take care of it
' -- Destroy window
TBGL_DestroyWindow
End Function
Function FillArrays()
String src = "
basic
' -- Re-declare types
Type TBGL_TRGB
r As Byte
g As Byte
b As Byte
End Type
Type TBGL_TVECTOR3F
x As Single
y As Single
z As Single
End Type
'RANDOMISER
'==========
'
Dim seed As Long=0x12345678
'
Function Rnd() As Single 'this is from oxygen examples in thinbasic folder
'
Static As Single f, d=1/0x7fffffff
mov eax,seed
rol eax,7
imul eax,eax,13
mov seed,eax
push eax
fild DWord [esp]
ADD esp,4
fmul DWord d
fstp DWord f
Function=f
End Function
' -- Link variables
Dim oVertexA() At #VertexA As TBGL_TVECTOR3F
Dim oColorA() At #ColorA As TBGL_TRGB
Single g
Long i
Integer sq=640: Single s2 = sq/2
#def points 240
Dim x(points) as single
Dim y(points) as single
dim kl(points) as TBGL_TRGB
For i = 1 To points
x(i)=abs(Rnd()*sq): y(i)=abs(Rnd()*sq)
g=127-127*(Abs(s2-x(i))/s2)+127-127*(Abs(s2-y(i))/s2)
kl(i).r=255-x(i)/sq*255
kl(i).g = g
kl(i).b = y(i)/(sq*255)
Next
Single a, b, q
Long xx, yy, d , kkl, i
For xx = 1 To sq
For yy = 1 To sq
d = 307201
For i = 1 To points
a=x(i)-xx: b=y(i)-yy
q=a*a+b*b
If q < d Then d = q: kkl = i
Next i
ind = (yy-1)*640 + xx
oVertexA(ind).x = xx
oVertexA(ind).y = yy
oVertexA(ind).z = 0
oColorA(ind).r = kl(kkl).r
oColorA(ind).g = kl(kkl).g
oColorA(ind).b = kl(kkl).b
'oColorA(i).r = 255:oColorA(i).g=0: oColorA(i).b=0
'pset xx,yy,kl(kkl)
Next yy
Next xx
terminate
"
' -- Pass the source
O2_Asmo src
' -- Check for errors
If Len(o2_error) Then
MsgBox 0, o2_error : Stop
End If
' -- Execute
o2_exec
End Function
Petr Schreiber
30-11-2015, 20:24
Matthew,
as I understand it, your original example basically needed something like single buffer, something to have image visible immediately. I... I am sorry, but I do not think single buffering should still exist in 21st century :D*
But of course, I want you to enable you to do what you need. So... what about thinking about the problem differentely? What about having a canvas under your control?
It is an approach I learned to use, and maybe you will like it too. For canvas, you can use memory bitmap. That is persistent. And then map it on quad.
And yes, one more tip. You don't need to define VoronoiDistance, thinBasic has it covered with optimized Dist function!:
Uses "TBGL"
Randomize
%winWidth = 640
%winHeight = 480
%winDepth = 32
DWord hWnd = TBGL_CreateWindowEx("Voronoi diagram", %winWidth, %winHeight, %winDepth, %TBGL_WS_WINDOWED | %TBGL_WS_DONTSIZE | %TBGL_WS_CLOSEBOX)
TBGL_ShowWindow
TBGL_RenderMatrix2D ( 0, %winHeight, %winWidth, 0)
TBGL_BackColor 0, 0, 0, 0
Long sites = 10
Long townX(sites), townY(sites)
Long colR(sites), colG(sites), colB(sites)
Long i, n, x, y
For i = 1 To sites
townX(i) = Rnd(0, %winWidth)
townY(i) = Rnd(0, %winHeight)
colR (i) = Rnd(0, 255)
colG (i) = Rnd(0, 255)
colB (i) = Rnd(0, 255)
Next
TBGL_ResetKeyState()
' -- Canvas built as black
String drawingCanvas = Repeat$(%winWidth*%winHeight, Chr$(0, 0, 0, 255))
' -- Now we overlay a easy to handle array over
Dim pixelOverlay(%winWidth, %winHeight) As TBGL_TRGBA At StrPtr(drawingCanvas)
Long xStep = 5 ' -- How much lines at time?
Long lastX = 1 ' -- Memory for x
While TBGL_IsWindow(hWnd)
TBGL_ClearFrame
For x = lastX To Min(lastX+xStep, %winWidth)
For y = 1 To %winHeight
n = 1
For i = 1 To sites
If Dist(townX(i), townY(i), x, y) < Dist(townX(n), townY(n), x, y) Then
n = i
EndIf
Next
' -- Writing bitmap like a thinBasic boss
With pixelOverlay(x, y)
.r = colR(n)
.g = colG(n)
.b = colB(n)
End With
Next
If TBGL_GetWindowKeyOnce(hWnd, %VK_ESCAPE) Then Exit While
TBGL_MakeTexture drawingCanvas, %TBGL_DATA_RGBA, %winWidth, %winHeight, 1, %TBGL_TEX_NEAREST
Next
lastX = x
TBGL_PushState %TBGL_TEXTURING
TBGL_BindTexture 1
TBGL_BeginPoly %GL_QUADS
TBGL_TexCoord2D 0, 0 : TBGL_Vertex 0, 0
TBGL_TexCoord2D 1, 0 : TBGL_Vertex %winWidth, 0
TBGL_TexCoord2D 1, 1 : TBGL_Vertex %winWidth, %winHeight
TBGL_TexCoord2D 0, 1 : TBGL_Vertex 0, %winHeight
TBGL_EndPoly
TBGL_PopState
If TBGL_GetWindowKeyOnce(hWnd, %VK_ESCAPE) Then Exit While
TBGL_DrawFrame
Wend
TBGL_DestroyWindow
Of course, this example does not reach the performance of Primo's Oxy accelerated solution, as it uses pure parsing, but it could be further combined with oxygen to reach optimum performance.
Petr
* I will give a thought to enabling single buffering in TBGL
I still do a lot of my programming in Basic4GL which isn't too fast when it comes to creating Fractals and similar mathematical drawing so I usually just draw straight to the front buffer using glDrawBuffer(GL_FRONT) and glFlush() as it's a little faster than swapping buffers which I feel is a waste when nothing's actually moving on the screen.
Your method of drawing onto a Quad is something else I was thinking of doing in Basic4GL using glTexSubImage2D, I didn't even know that thinBasic had a Dist function built-in so thanks for that.
Why don't you like single-buffering? :-) I've always found it useful for getting quick results for some programs.
Petr Schreiber
01-12-2015, 21:21
Hehe,
good question. Maybe I think that single buffer and GPU graphics don't go much together, as the main benefit -performance- is usually lost and/or you are using it for per pixel operations, while GPU graphics are shining most when working at vector level.
See this GPU-less example :)
(And guess what, Canvas can be used in double buffer mode too)
Uses "UI"
Randomize
%winWidth = 640
%winHeight = 480
%winDepth = 32
DWord hWnd = Canvas_Window("Voronoi diagram", 100, 100,%winWidth, %winHeight)
Canvas_Attach(hWnd, 0)
Long sites = 10
Long townX(sites), townY(sites)
Long colR(sites), colG(sites), colB(sites)
Long i, n, x, y
For i = 1 To sites
townX(i) = Rnd(0, %winWidth)
townY(i) = Rnd(0, %winHeight)
colR (i) = Rnd(0, 255)
colG (i) = Rnd(0, 255)
colB (i) = Rnd(0, 255)
Next
While IsWindow(hWnd)
For x = 0 To %winWidth
For y = 0 To %winHeight
n = 1
For i = 1 To sites
If Dist(townX(i), townY(i), x, y) < Dist(townX(n), townY(n), x, y) Then
n = i
EndIf
Next
Canvas_SetPixel(x, y, Rgb(colR(n), colG(n), colB(n)))
Next
If Asc(Canvas_Inkey) = 27 Then Exit While
Next
If Asc(Canvas_Inkey) = 27 Then Exit While
Wend
Petr
ErosOlmi
06-12-2015, 10:40
Please do not use infinite loops otherwise script will continue to run (as a process) even if the main window is closed.
Correct loop would be something like:
While IsWindow(hWnd)
...
Wend
In this way, when the hWnd window will be closed the script will stop execution.
Ciao
Eros
Petr Schreiber
06-12-2015, 10:42
Fixed, nice catch :)
ErosOlmi
06-12-2015, 10:45
primo catched :)
http://www.thinbasic.com/community/project.php?issueid=497&filter=all#note2833