PDA

View Full Version : [TBGL] Question about TBGL_DrawFrame



matthew
28-11-2015, 16:37
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

matthew
28-11-2015, 20:49
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

primo
29-11-2015, 16:21
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

matthew
29-11-2015, 23:35
Very impressive. :-)

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

matthew
01-12-2015, 00:46
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