Oxygen Basic
Programming => Example Code => Topic started by: Peter on January 21, 2014, 01:23:31 PM
-
Deleted
-
Some hardcore for the Mandelbrot algorithm: using the fpu stack to hold temp variables.
include "sw.inc"
Window 800,600,1
single x,y,zx,zy,cx,cy,tp, sys im=570,z=150,it
h = GetHeight
w = GetWidth
single iz=1/z
single four=4.0
For y=0 to <h
For x=0 to <w
zx=0
zy=0
cx= (x-400)*iz
cy= (y-300)*iz
it = im
(
'
'While zx * zx + zy * zy < 4 && it>0
'
fld dword zx : fmul st0 : fld dword zy : fmul st0
'leave zy zx squares on fstack for later use
fld st0 : fadd st2 'sum squares
fld dword four
fcomip : fstp st0 'compare and pop
(
ja exit
fstp st0 'dispose zy
fstp st0 'dispose zx
exit 2 'exit main loop
)
'
'tp = zx * zx - zy * zy + cx
'
'zy zx squares on fstack
fchs : faddp st1 : fadd dword cx
'tp on fstack
'
'zy = 2 * zx * zy + cy
'
fld1 : fadd st0 '2.0
fmul dword zx : fmul dword zy : fadd dword cy
fstp dword zy
'
'zx = tp
'
fstp dword zx 'pop tp from fstack
'
'it -=1
'
dec it
jg repeat
'
'Wend
'
)
SetPixel x,y, RGB it*12,it*8,it*4
Next
Next
Waitkey
CloseWindow
-
Here is my effort, using the SIMD registers.
But first the algorithim is rearranged, for more direct translation:
do
zxx=zx*zx
zyy=zy*zy
if zxx+zyy>=4.0 then exit do
zy = 2 * zx * zy + cy
zx = zxx - zyy + cx
if --it<1 then exit do
end do
Then, step by step, the lines are transformed into SIMD instructions.
(if yout PC is an old banger (pre-2005), it may not have the SSE3 instruction set containing HADDPS and HSUBPS )
include "sw.inc"
include "gl.inc"
'! glFlush Lib "opengl32.dll" ()
hwnd = Window 800,600,1
Init2D (hwnd)
single x, y, zz[16]
sys im=570, z=150, it, stop
h = GetHeight
w = GetWidth
float iz=1/z
float xx,yy
indexbase 0
zz[4]=4.0
For y=0 to <h
For x=0 to <w
zz[8]= (x-400)*iz
zz[9]= (y-300)*iz
movups xmm3,zz[4] '4.0
movups xmm4,zz[8] 'cx,cy
xorps xmm0,xmm0 'zero zx,zy
mov ecx ,im 'down counter
def swap 0b11100001 'shuffle-order to swap lower 2 elements
(
movups xmm1,xmm0
mulps xmm1,xmm1 'squares
movups xmm2,xmm1 '
haddps xmm2,xmm2 'squares sum
comiss xmm2,xmm3 'compare with 4.0
jae exit 'exit if value >= 4.0
movups xmm2,xmm1 '
hsubps xmm2,xmm2 'squares difference
addss xmm2,xmm4 'singular add cx for new zx
'
movups xmm1,xmm0 'to compute new zy
shufps xmm1,xmm1,swap 'swap zx,zy position
addss xmm1,xmm1 'singular 2*zy 'zy+zy
mulss xmm1,xmm0 'singular *zx
movups xmm5,xmm4 '
shufps xmm5,xmm5,swap 'swap cx,cy position
addss xmm1,xmm5 'singular add cy
unpcklps xmm2,xmm1 'pair new zx,zy (by interleaving)
movups xmm0,xmm2 'transfer new zx,zy
dec ecx
jg repeat
)
mov it,ecx 'iter count
DrawPixel x,y, 1, it*12,it*8,it*4,255
Next
Next
SwapBuffer
While KeyDown(27)=0
DoEvents
Flush
Wend
Quit2D
CloseWindow
-
I always create a texture with the pixels, then bind the texture to a quad surface. The scene has to be rebuilt every time the window is altered in some way. But, with the texture preloaded, most of the action is in the graphics card.
Not sure how best to handle animation strips though. The ideal texture is a square 2^n pixels, but I think this constraint no longer applies.
-
You can rebuild the scene whenever a WM_MOVE or WM_SIZE message is received.
Also receive the WM_ERASEBKGND message but do nothing (return 0)
This is the WndProc from OpengleSceneFrame.inc. I rarely need to alter this code: it is intended for moveable and resizeable windows.
function WndProc(sys hwnd, uMsg, wParam, lParam) as sys callback
================================================================
'
static sys hDC,hRC
select umsg
'
case WM_CHAR : lastchar=wparam
case WM_MOUSEMOVE : mposx=LoWord[lparam] : mposy=HiWord[lparam] : act=1
case WM_LBUTTONDOWN : bleft=1 : sposx=LoWord[lparam] : sposy=HiWord[lparam] : act=1
case WM_LBUTTONUP : bleft=0
case WM_RBUTTONDOWN : bright=1 : act=1
case WM_RBUTTONUP : bright=0
case WM_KEYUP : key[wparam]=0
case WM_TIMER : act=1
case WM_MOVE : act=2
case WM_SIZE : act=3
case WM_ERASEBKGND :
case WM_CLOSE : DestroyWindow hwnd
'
case WM_KEYDOWN
select case wparam
keydown 'macro
'default cases
case 27 : SendMessage hwnd, WM_DESTROY, 0, 0
case 32 : if key[32]=0 then pause=1-pause 'toggle
end select
lastkey=wparam
key[wparam]=1
'
case WM_CREATE
'
'SETUP DEVICE CONTEXT AND RENDER CONTEXT
'
hDC=GetDC hwnd
SelectPixelformat hDC,1
hRC = wglCreateContext hDC
wglMakeCurrent hDC, hRC
! Initialize(sys hWnd) : Initialize hWnd
SetWindowText hwnd,title
#ifdef fontA
BuildFont hWnd, hDC, hRC,fontA,1000
#endif
act=2
'
case WM_DESTROY
'
! Release(sys hWnd) : Release hWnd
#ifdef fontA
glDeleteLists 1000, 255
#endif
wglMakeCurrent hDC, NULL
wglDeleteContext hRC
ReleaseDC hWnd,hDC
PostQuitMessage 0
return 0
'
case else
'
return DefWindowProc(hwnd, uMsg, wParam, lParam) 'unprocessed messages
'
end select
'
if not act then exit function
'
'CREATE SCENE FRAME AND SWAP BUFFERS
'===================================
'
'
if act=3 then
'
'SET THE VIEWPORT AND PERSPECTIVE
'
GetClientRect hwnd,&cRect
glViewport 0, 0, crect.right, crect.bottom
aspect=crect.right/crect.bottom
perspective
end if 'act=3
'
! scene(sys hwnd) : scene hWnd
'
if act
glfinish
swapBuffers hdc
act=0
end if
return 0 'done
'
end function
PS: Just added WM_MOVE
one trick for static scenes to reduce system load:
'at the end of the scene procedure:
if bleft 'mouse button
sleep 10
elseif act>1 'move or resize
sleep 10
else
sleep 100
end if
end sub
-
Not sure how best to handle animation strips though. The ideal texture is a square 2^n pixels, but I think this constraint no longer applies.
The constraint still applies, just most graphics cards and drivers now automatically rescale something to the nearest power of 2. However, this causes a slight performance hit. Animation strips would be handled via a texture atlas.
-
Okay, That makes sense for texture scaling (with depixelation). The individual strip frames can be patched into the texture square, as a grid.
-
The individual strip frames can be patched into the texture square, as a grid.
Yeppers. Just shift the UV coordinates for each frame of animation.
-
What I had in mind was to patch frames from Peter's BMP strips, for example, into a square texture, say 4x4 images, then manipulate the U V coordinates, as you say.