March 28, 2024, 10:48:29 AM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Mandlebrot in a DX window

Started by GWS, March 07, 2012, 07:39:22 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

GWS

March 07, 2012, 07:39:22 PM Last Edit: March 28, 2012, 03:48:28 AM by GWS
Hi,

I've been playing and came up with this ..  :)

It seems to give a different look to a mandlebrot - you can click on it to enlarge any point of interest.


' Mandlebrot - GWS March 2012
' using DirextX 2D
' Click on the fractal to enlarge the pattern at that point.
' Click Normal to return to the standard Mandlebrot display.

autodefine "OFF"

window w
int i,y,px,wstyle,run
int Width,Height
int mx,my,clickcount
float Z_re2,Z_im2,Z_re,Z_im,c_re,c_im
float x1,x2,y1,y2
float Rfac,Ifac,scale,Re,Im
pointer sprite1

Width=1024
Height=768
run = 1

wstyle = @minbox|@noautodraw
openwindow w,0,0,Width,Height,wstyle,0,"Mandlebrot",&handler
' create a DirectX screen (no allowance is made for the user not having DirectX - just go for it) ...
attachscreen(w,Width,Height,0)

frontpen backBuffer,RGB(255,255,255)
setfont backbuffer,"Arial",10,500
drawmode backBuffer,@TRANSPARENT

control backbuffer,@BUTTON,"Normal",Width*0.1,Height*0.85,70,25,0, 1
control backbuffer,@BUTTON,"Exit",Width*0.8,Height*0.85,70,25,0, 2

' working sprite to draw on - and to refresh from if the window needs re-painting ..
sprite1 = CREATESPRITE(Width,Height,1,1)

centerwindow w

scale = 1.0
clickcount = 0

' define the corners for two complex numbers (x1+iy1) and (x2+iy2) ..
x1 = -2
y1 = -1.2
x2 = 1
y2 = 1.2

' calculate factors to match screen pixels to corresponding complex values ..
Rfac = (x2 - x1)/(Width - 1)
Ifac = (y2 - y1)/(Height - 1)

fillscreen RGB(0,0,30)
flip

gosub NewPattern

drawsprite sprite1
move backBuffer,50,20
print backBuffer,"Click anywhere on the Fractal for an enlargement."

flip

waituntil run = 0
freesprite sprite1
closescreen
closewindow w
end

sub handler(),int :' just to keep the return(0) happy - yeuk!
select @MESSAGE
case @IDCLOSEWINDOW
    run = 0
case @idcontrol
select @controlid
case 1
' set to display normal mandlebrot ..
clickcount = 0
Scale = 1.0
x1 = -2
x2 = 1
y1 = -1.2
y2 = 1.2
setfocus w

gosub Redraw

return
case 2
run = 0
endselect
case @IDLBUTTONDN
' where was the mouse button clicked ..
mx = @MOUSEX
my = @MOUSEY
clickcount = clickcount + 1

' magnify by 10 at each click ..
Scale = clickcount * 10

' calculate the Real and Imaginary values corresponding to the point clicked ..
Re = x1 + @mousex * Rfac
Im = y2 - @mousey * Ifac

' plot from the selected Re +/- 1.5 , and from Im -/+ 1.2
x1 = Re - 1.5 / Scale
x2 = Re + 1.5 / Scale
y1 = Im - 1.2 / Scale
y2 = Im + 1.2 / Scale

' recalculate the Re and Im factors for the current scale ..
gosub Redraw

case @IDPAINT
drawspritexy sprite1,0,0
flip
endselect
return(0) :' shouldn't be needed in a civilized system
endsub


sub NewPattern
float xm
int NIter
' routine to generate a Mandlebrot pattern ..
' increase the number of iterations as the scale increases
NIter = 50 * sqrt(Scale)

SpriteToBuffer(sprite1)
Fillscreen RGB(0,0,50), SpriteBuffer
LOCKBUFFER SpriteBuffer

for y = 0 to Height - 1
c_im = y2 - y * Ifac

for px = 0 to Width - 1
c_re = x1 + px * Rfac
Z_re = c_re
Z_im = c_im

for i = 1 to NIter
xm = i :' colour multiplier

Z_re2 = Z_re * Z_re
Z_im2 = Z_im * Z_im

if (Z_re2 + Z_im2 > 4)
WritePixelFast px,y,rgb(30+xm,90+xm,190+xm),SpriteBuffer
goto breaknext
endif

Z_im = 2 * Z_re * Z_im + c_im
Z_re = Z_re2 - Z_im2 + c_re

next i

label breaknext

next px
next y

UNLOCKBUFFER SpriteBuffer
endsub


sub Redraw
' redraw the pattern after a change ..
Rfac = (x2 - x1)/(Width - 1)
Ifac = (y2 - y1)/(Height - 1)

gosub NewPattern

drawsprite sprite1

move backBuffer,50,20
print backBuffer,"Click on the Fractal to enlarge a section."

flip
endsub


best wishes, :)

Graham

[Modified to compile under the strict rules of IWB2 ..  ::)]

Tomorrow may be too late ..

LarryMc

As always, pretty neat, Graham.

However it won't complie in the latest version of IWB.

You have a GOTO BREAK statement with the corresponding label.

BREAK is now a keyword that is used to break out of loops other than FOR/NEXT

Also the compiler generates a warning if the handler routine is not formally structured
i.e. : SUB handler(),int
and the handler has to return 0 or their will be warning messages.

Note: it you modified it to zoom in on a continuos loop it looks like you're flying by a solar flare or something.

LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

GWS

Ah! .. that's what comes of late night projects ..  ;D

I'd forgotten all the new-fangled constraints, and some of the code is several years old.

I do hate that return 0 stuff from subs that don't need to return anything.

I'll try to make it compliant ..  ::)

It only zooms where you click .. it's not auto-zoom - although that's an idea ..  :P

The mandlebrot is the big black ugly thing in the centre - all the pretty stuff is round the edges. :)

best wishes, :)

Graham
Tomorrow may be too late ..

GWS

OK .. I've modified the code above to comply with the strict rules of play ..  ::)

Can't say I'm keen on the SUB handler(),int, or the Return(0) idea.
The original user guide said .. You don't need a 'Return' statement if the subroutine has nothing to return.
And if it returns nothing, why specify a return type?

It's getting a bit too 'C' ish I reckon ..  :-\

Still on with the fun - I've got another idea ..  ;D

best wishes, :)

Graham
Tomorrow may be too late ..

LarryMc

Quote from: GWS on March 08, 2012, 01:57:06 AM
Can't say I'm keen on the SUB handler(),int, or the Return(0) idea.
The original user guide said .. You don't need a 'Return' statement if the subroutine has nothing to return.
And if it returns nothing, why specify a return type?
That statement is still true.
But a message handler has always returned a value; it's just that the compiler had special case code so you didn't have to enter it.
Sapero had to add some code to insure that the user didn't try to pass parameters to OnMenu, OnControl,OnMessage functions and the special case code was getting in his way.  So he standardized the way subroutines work, including handlers.

Except for the BREAK statement in your original code the other stuff simply generates warnings, not errors.
There are even compiler options now that you can opt for that keep those particular warnings from appearing if you so desire.

And I'm waiting for your next idea... :)

LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

GWS

March 08, 2012, 07:54:55 PM #5 Last Edit: March 08, 2012, 09:13:19 PM by GWS
'OnMenu, OnControl, OnMessage functions'  ..

I didn't even know they existed ..  ::)  The 'pro' version has always been a logical maze for me.

I obviously need to have a read through the latest user guide.  :)

Next idea is stuck temporarily .. I'll get back to it momentarily ..  :)

Graham
Tomorrow may be too late ..

GWS

I've played with it a bit more, and I think this version is probably the best ..  :)

It uses pre-defined colours, but some components are randomised ..


' Mandlebrot - GWS March 2012
' using DirextX 2D
' second version using pre-set colours
' Click on the fractal to enlarge the pattern at that point.
' Click Normal to return to the standard Mandlebrot display.

autodefine "OFF"

window w
int i,y,px,wstyle,run
int Width,Height
int mx,my,clickcount
float Z_re2,Z_im2,Z_re,Z_im,c_re,c_im
float x1,x2,y1,y2
float Rfac,Ifac,scale,Re,Im
pointer sprite1

int col[255]

for i = 0 to 63
col[0+i] = rgb(rnd(3*i),3*i,3*i+128)
col[64+i] = rgb(i+150,2*i,rnd(2*i)+128)
col[128+i] = rgb(3*i+150,rnd(255-3*i),170)
col[192+i] = rgb(rnd(250),50,255-2*i)
next i

Width=1024
Height=768
run = 1

wstyle = @minbox|@noautodraw
openwindow w,0,0,Width,Height,wstyle,0,"Mandlebrot",&handler
' create a DirectX screen (no allowance is made for the user not having DirectX - just go for it) ...
attachscreen(w,Width,Height,0)

frontpen backBuffer,RGB(255,255,255)
setfont backbuffer,"Arial",10,500
drawmode backBuffer,@TRANSPARENT

control backbuffer,@BUTTON,"Normal",Width*0.1,Height*0.85,70,25,0, 1
control backbuffer,@BUTTON,"Exit",Width*0.8,Height*0.85,70,25,0, 2

' working sprite to draw on - and to refresh from if the window needs re-painting ..
sprite1 = CREATESPRITE(Width,Height,1,1)

centerwindow w

scale = 1.0
clickcount = 0

' define the corners for two complex numbers (x1+iy1) and (x2+iy2) ..
x1 = -2
y1 = -1.2
x2 = 1
y2 = 1.2

' calculate factors to match screen pixels to corresponding complex values ..
Rfac = (x2 - x1)/(Width - 1)
Ifac = (y2 - y1)/(Height - 1)

fillscreen RGB(0,0,30)
flip

gosub NewPattern

drawsprite sprite1
move backBuffer,50,20
print backBuffer,"Click anywhere on the Fractal for an enlargement."

flip

waituntil run = 0
freesprite sprite1
closescreen
closewindow w
end

sub handler(),int
select @MESSAGE
case @IDCLOSEWINDOW
    run = 0
case @idcontrol
select @controlid
case 1
' set to display normal mandlebrot ..
clickcount = 0
Scale = 1.0
x1 = -2
x2 = 1
y1 = -1.2
y2 = 1.2
setfocus w

gosub Redraw

case 2
run = 0
endselect
case @IDLBUTTONDN
' where was the mouse button clicked ..
mx = @MOUSEX
my = @MOUSEY
clickcount = clickcount + 1

' magnify by 10 at each click ..
Scale = clickcount * 10

' calculate the Real and Imaginary values corresponding to the point clicked ..
Re = x1 + @mousex * Rfac
Im = y2 - @mousey * Ifac

' plot from the selected Re +/- 1.5 , and from Im -/+ 1.2
x1 = Re - 1.5 / Scale
x2 = Re + 1.5 / Scale
y1 = Im - 1.2 / Scale
y2 = Im + 1.2 / Scale

' recalculate the Re and Im factors for the current scale ..
gosub Redraw

case @IDPAINT
drawspritexy sprite1,0,0
flip
endselect
return(0)
endsub


sub NewPattern
int NIter,clr,xm
' routine to generate a Mandlebrot pattern ..

NIter = 150

SpriteToBuffer(sprite1)
Fillscreen RGB(0,0,20), SpriteBuffer
LOCKBUFFER SpriteBuffer

for y = 0 to Height - 1
c_im = y2 - y * Ifac

for px = 0 to Width - 1
c_re = x1 + px * Rfac
Z_re = c_re
Z_im = c_im

for i = 1 to NIter
xm = i :' colour multiplier

Z_re2 = Z_re * Z_re
Z_im2 = Z_im * Z_im

if (Z_re2 + Z_im2 > 4)

if xm = NIter
clr = 0
else
clr = col[xm]
endif

WritePixelFast px,y,clr,SpriteBuffer
goto breaknext

endif

Z_im = 2 * Z_re * Z_im + c_im
Z_re = Z_re2 - Z_im2 + c_re

next i

label breaknext

next px
next y

UNLOCKBUFFER SpriteBuffer
endsub


sub Redraw
' redraw the pattern after a change ..
Rfac = (x2 - x1)/(Width - 1)
Ifac = (y2 - y1)/(Height - 1)

gosub NewPattern

drawsprite sprite1

move backBuffer,50,20
print backBuffer,"Click on the Fractal to enlarge a section."

flip
endsub


There are lots of variables to tweak to get different colour effects.

Also, increasing the number of iterations gives a sharper image, at the expense of taking longer to produce.

best wishes, :)

Graham
Tomorrow may be too late ..