Hi Richard,
That's very nice! I'd point out, however, that there isn't "A" Julia set, there's one for each point in the complex plane (here you've chosen the point ci = 0.5213 : cr = -0.5125), though the interesting ones lie on the fringes of the Mandelbrot set, say in the range Cr = -2 to 2 and Ci =-1.25 to 1.25.
Is there a way (using shaderlib) to pass these parameters to the shader in real time, rather than compiling them as hard coded values? Obviously I could modify the relevant strings in the Fragment$ array, and then recompile, but that's not really an optimal solution.
I note that shaderlib doesn't appear to be documented in either the included or online manual (though it's existence is noted). I had a search on the wiki, and found some old pages of yours from 2015, but they don't use shaderlib... Looking at the code of the library, I can't see where it is possible to pass values into the shader [pipline] when it is called.
You probably don't remember (it was in 2016 and a fringe interest even then!) that I wrote a Julia viewer using assembler, which allowed the user to move the mouse about in the window (which represents the space x(real) = -2 to 2, y(imaginary) = -1.25 to 1.25 ). Your shader code should be able to achieve much the same, but in a much easier-to-write and read form.
My assembler code is below: run and move your mouse about over the window to see the Julia set corresponding to the underlying point (in the space, not the set!) - that's the kind of thing I'd like to be able to achieve.
Best wishes,
D
Code: Select all
MODE 8
xres=@vdu%!208
yres=@vdu%!212
minx=-2.0
maxx=2.0
xrange=maxx-minx
xstep=xrange/xres
miny=-1.25
maxy=1.25
yrange=maxy-miny
ystep=yrange/yres
REM Reserve space for the assembly routine itself, making sure it's in its own 2K block to avoid cache thrashing.
size% = 2048
DIM code% NOTEND AND 2047, code% size%-1
REM These are just dummy variables, while setting up the assembler
nr=3.5
ni=1.5
cr=0.29
ci=0.01
mag%=0
temp=0.0
col%=TRUE
fixed%=FALSE
PROCAssJulia
REM Set up a DIBsection for screen output, so we can write data to it directly
DIM BITMAPINFOHEADER{Size%, Width%, Height%, Planes{l&,h&}, BitCount{l&,h&}, \
\ Compression%, SizeImage%, XPelsPerMeter%, YPelsPerMeter%, \
\ ClrUsed%, ClrImportant%}
DIM bmi{Header{} = BITMAPINFOHEADER{}, Palette%(255)}
bmi.Header.Size% = DIM(BITMAPINFOHEADER{})
bmi.Header.Width% = @vdu%!208
bmi.Header.Height% = @vdu%!212
bmi.Header.Planes.l& = 1
bmi.Header.BitCount.l& = 8
REM We've made an 8 bit per pixel bitmap definition: define a palette to go with it
SYS "CreateDIBSection", @memhdc%, bmi{}, 0, ^bits%, 0, 0 TO hbitmap%
IF hbitmap% = 0 ERROR 100, "Couldn't create DIBSection"
SYS "SelectObject", @memhdc%, hbitmap% TO oldhbm%
SYS "DeleteObject", oldhbm%
PROCSetColour(col%)
CLS
bytesperpixel% = bmi.Header.BitCount.l& DIV 8
bytesperline% = ((bmi.Header.Width% * bytesperpixel%) + 3) AND -4
REPEAT
MOUSE x%,y%,z%
IF NOT fixed% THEN
cr=minx+x%*xstep/2
ci=miny+y%*ystep/2
PRINT TAB(0,0);cr,ci
ELSE
IF z%>0 THEN
tx%=x%
ty%=y%
REPEAT MOUSE x%,y%,z% UNTIL z%=0
minx+=(tx%-x%)*xstep/2
maxx+=(tx%-x%)*xstep/2
miny+=(ty%-y%)*ystep/2
maxy+=(ty%-y%)*ystep/2
ENDIF
ENDIF
CALL code%
SYS "InvalidateRect", @hwnd%, 0, 0
q$=INKEY$(0)
CASE q$ OF
WHEN "c","C":col%=NOT col%:PROCSetColour(col%)
WHEN "f","F": fixed%=NOT fixed%
WHEN CHR$(140):
fixed%=TRUE
minx+=xrange/4
maxx-=xrange/4
xrange=maxx-minx
xstep=xrange/xres
miny+=yrange/4
maxy-=yrange/4
yrange=maxy-miny
ystep=yrange/yres
WHEN CHR$(141):
fixed%=TRUE
minx-=xrange/4
maxx+=xrange/4
xrange=maxx-minx
xstep=xrange/xres
miny-=yrange/4
maxy+=yrange/4
yrange=maxy-miny
ystep=yrange/yres
ENDCASE
UNTIL q$="q" OR q$="Q"
QUIT
:
DEFPROCSetColour(col%)
LOCAL i%,r%,g%,b%
IF col% THEN
FOR i% = 0 TO 255
r% = (i% MOD 16)*16
g% = (i% MOD 64)*4
b% = 255-i%/2
bmi.Palette%(i%) = b% + (g% << 8) + (r% << 16)
NEXT
ELSE
FOR i% = 0 TO 255
bmi.Palette%(i%) = i% + (i% << 8) + (i% << 16)
NEXT
ENDIF
SYS "SetDIBColorTable", @memhdc%, 0, 256, ^bmi.Palette%(0)
ENDPROC
:
DEFPROCAssJulia
LOCAL opt%
FOR opt%=0 TO 2 STEP 2
P%=code%
[
OPT opt%
mov esi,[^yres]
mov edx,[^bits%]
fld tbyte [^miny]
fstp tbyte [^ni]
.yloop
mov ecx,[^xres]
fld tbyte [^minx]
fstp tbyte [^nr]
.xloop
mov eax,0
fld tbyte [^ci]
fld tbyte [^cr]
fld tbyte [^nr]
fst st3
fmul st0,st0
fstp st4 ;After this we have cr,ci,nr and nr2 in ST0-3, and 2 pushes
fld tbyte [^ni]
fst st5
fmul st0,st0
fstp st6 ;After this we have cr,ci,nr, nr2,ni and ni2 in ST0-5, and 2 pushes
.lpt
;OK now we should be able to calculate the new values of nr, ni
fld st2
fadd st0,st0
fmul st0,st5
fadd st0,st2
fstp st5 ;we should be in the same place, but with the new value of ni
fld st3
fsub st0,st6
fadd st0,st1
fstp st3 ;After this we now have cr,ci, the new nr, the old nr2, the new ni, and the old ni2 in ST0-5, and 2 pushes
fld st2
fmul st0,st0
fstp st4 ;now with new nr2, still 2 pushes
fld st4
fmul st0,st0
fst st6 ;now with new ni2, now 3 pushes
fadd st0,st4 ;gives magnitude squared
fistp dword [^mag%] ;store it as an integer, so it can be read into a standard register and compared, Back to 2 pushes
inc eax
mov ebx,[^mag%]
cmp ebx,4
ja esc
cmp eax,255
jb lpt
.esc
;Now we have the problem of popping the stack twice
fstp tbyte [^temp] ;should pop cr into temp
fstp tbyte [^temp] ;should pop ci into temp
mov byte [edx],al
add edx,[^bytesperpixel%]
fld tbyte [^nr]
fld tbyte [^xstep]
faddp st1,st0
fstp tbyte [^nr]
dec ecx
jnz near xloop
fld tbyte [^ni]
fld tbyte [^ystep]
faddp st1,st0
fstp tbyte [^ni]
dec esi
jnz near yloop
ret
]
NEXT opt%
ENDPROC