Julia Set (shader)

Discussions related to graphics (2D and 3D), animation and games programming
DDRM
Posts: 33
Joined: Mon 17 Jun 2024, 08:02

Re: Julia Set (shader)

Post by DDRM »

Using static variables doesn't prevent it crashing.... :-(
Richard Russell
Posts: 591
Joined: Tue 18 Jun 2024, 09:32

Re: Julia Set (shader)

Post by Richard Russell »

DDRM wrote: Mon 26 Jan 2026, 17:09 ...and it works for me (here on this setup)...
Try it in BBCSDL, as that's a platform you should be able to run on the same machine. Another platform you can readily try is in a browser, since that's just a case of selecting the 'Deploy as a web application' checkbox.

You probably have a good excuse for not testing it on other platforms, but BB4W, BBCSDL and in-browser should be the minimum you try whenever you make modifications (I would include at least one 64-bit platform too, which you could achieve by installing 64-bit BBCSDL).

And indeed I can confirm that the program you listed does not work here, I see a white ellipse but nothing else happens, wherever the mouse is moved. Why would you remove code that does no harm and in fact turns out to be essential?
Richard Russell
Posts: 591
Joined: Tue 18 Jun 2024, 09:32

Re: Julia Set (shader)

Post by Richard Russell »

DDRM wrote: Mon 26 Jan 2026, 17:17 Using static variables doesn't prevent it crashing.... :-(
I think you must be doing something wrong, because there's no way the shader should be able to tell the difference between a structure and a pair of static variables, all it gets passed is a memory address (pointer) after all.

List the non-working code if you want me to try to diagnose the fault.
Richard Russell
Posts: 591
Joined: Tue 18 Jun 2024, 09:32

Re: Julia Set (shader)

Post by Richard Russell »

Richard Russell wrote: Mon 26 Jan 2026, 17:30 there's no way the shader should be able to tell the difference between a structure and a pair of static variables
I tried the following changes to mandel.bbc here (BBCSDL):

Changed all Float.0% to U%
Changed all Float.1% to V%
Changed all Float{} to ^U%

It worked perfectly.
Richard Russell
Posts: 591
Joined: Tue 18 Jun 2024, 09:32

Re: Julia Set (shader)

Post by Richard Russell »

Richard Russell wrote: Mon 26 Jan 2026, 17:27 And indeed I can confirm that the program you listed does not work here, I see a white ellipse but nothing else happens
To make it work here, I had to make two changes:
  • Restore the , @memhdc% to four SYS statements.
  • Remove the PRINT statement which was trying to output to the same window as the shader.
Here I output the two values, which you were trying to print, to the title bar:

Code: Select all

      MODE 9
      REM MODE 9 is 640 x 512 pixels, or 1280 x 1024 graphics units
      xres%=1280
      yres%=1024
      INSTALL @lib$ + "shaderlib"
      DIM Vertex$(10), Fragment$(20),Float{0%,1%}
      PROC_readshader(Vertex$())
      PROC_readshader(Fragment$())

      PROC_shaderinit(oVertex%, oFragment%)
      PROC_compileshader(oVertex%, Vertex$(), "Vertex")
      PROC_compileshader(oFragment%, Fragment$(), "Fragment")
      oProgram% = FN_useshaders(oVertex%, oFragment%)

      REM Here we store the locations of our shader variables ("uniforms")
      REM in BBC BASIC variables (pReal and pImag)
      SYS `glGetUniformLocation`, oProgram%, "cr", @memhdc% TO pReal%%
      SYS `glGetUniformLocation`, oProgram%, "ci", @memhdc% TO pImag%%

      REPEAT
        REM We get the mouse coordinates, and check it's in the window area
        REM (That way we know the calculated start point will lie within (-2 to 2,-1.25 to 1.25) )
        REM Though I think the shader actually only shows the area (-1.5 to 1.5, -1 to 1)?
        MOUSE px%,py%,pz%
        IF px%>0 AND px%<xres% AND py%>0 AND py%<yres% THEN
          REM Scale the mouse X coordinate into the required space. Not sure why it needs to go into a structure...
          Float.0% = FN_f4(4*px%/xres% - 3)
          SYS `glUniform1fv`, pReal%%, 1, Float{}, @memhdc%
          REM Ditto for Y coordinate
          Float.0% = FN_f4(2.5*py%/yres% - 1.25)
          SYS `glUniform1fv`, pImag%%, 1, Float{}, @memhdc%
          SYS "SDL_SetWindowTitle", @hwnd%, STR$(4*px%/1280 - 2) + \
          \                 CHR$9 + CHR$9 + STR$(4*py%/1024 - 1.25), @memhdc%
        ENDIF

        PROC_render
        WAIT 2
      UNTIL FALSE
      END

      REM Vertex shader:
      DATA "attribute vec4 vPosition;"
      DATA "void main()"
      DATA "{"
      DATA "gl_Position = vPosition;"
      DATA "}"
      DATA ""

      REM Fragment shader:
      REM We'll define two parameters, representing
      REM the real and imaginary parts of the start location
      DATA "uniform float cr;"
      DATA "uniform float ci;"

      DATA "void main()"
      DATA "{"
      DATA "float v;"
      DATA "float zr = gl_FragCoord.x  * 3.0 / 639.0 - 1.5;"
      DATA "float zi = gl_FragCoord.y * 2.0 / 511.0  - 1.0;"
      DATA "for( int i = 0; i <= 510; i++ )"
      DATA " {"
      DATA " v = float(i) / 512.0;"
      DATA " float zn = (zr + zi) * (zr - zi) + cr;"
      DATA " zi = 2.0 * zr * zi + ci; zr = zn;"
      DATA " if ((zr * zr + zi * zi) > 3.0) break;"
      DATA " }"
      DATA "gl_FragColor = vec4(sqrt(v), v, v*v, 1.0 );"
      DATA "}"
      DATA ""
DDRM
Posts: 33
Joined: Mon 17 Jun 2024, 08:02

Re: Julia Set (shader)

Post by DDRM »

Ah, it's the Float{} - I can try with a pointer (which I think is what the ^ does?). Yes, that works OK.

Your new version works nicely in BBC-SDL - I can confirm that my version doesn't here either, but does with the changes you made. Your version fails in BB4W until I disable the SDL command to write to the title bar, of course, but works then.

I find it surprising and a bit alarming that the SDL version appears to require an additional undocumented parameter for the OpenGL commands - could BB4W and BBC-SDL be using different versions of OpenGL? What is that parameter doing, and why do you think it is needed? Is it to do with SDL's processing of the command before passing it to OpenGL? Do other SDL graphics commands need to be given the device context?

Best wishes,

D
Richard Russell
Posts: 591
Joined: Tue 18 Jun 2024, 09:32

Re: Julia Set (shader)

Post by Richard Russell »

DDRM wrote: Mon 26 Jan 2026, 21:29 I find it surprising and a bit alarming that the SDL version appears to require an additional undocumented parameter for the OpenGL commands
It doesn't, you're misinterpreting it. In this context @memhdc% is not a parameter (undocumented or otherwise), it's a flag which tells BBC BASIC to invoke the special handling required when calling an API function in the context of the GUI.

This has come up before, but it was probably a long time ago because it affects both BB4W and BBCSDL. It's all to do with the fact that on a modern platform such as Windows or MacOS the interpreter runs concurrently with the GUI. If special measures are not taken, this concurrency can result in instability or worse.

So the presence of @memhdc% in the parameter list, which is generally a reliable indication that the GUI is being accessed, invokes this special handling. Where things get a little complicated is when you are bypassing the regular GUI (GDI32 in BB4W, SDL2 in BBCSDL), for example because you are using OpenGL or DirectX, when the special handling is likely still required but @memhdc% isn't a needed parameter.

In those (rare) cases you have to add @memhdc% as an additional parameter, which will be ignored by the API function but still act as a flag. This means you should have kept the @memhdc% in the BB4W version as well, since you are accessing the GUI, but seemingly you got away with not doing so (although I would expect stability to suffer).

The key takeaway from this is that modern computers and modern Operating Systems are complicated and if you see something in an example program that you don't understand leave well alone (or at the very least ask for advice before simply removing it) because the chances are that it is there for a reason and it's much safer to leave it in than to remove it.
Richard Russell
Posts: 591
Joined: Tue 18 Jun 2024, 09:32

Re: Julia Set (shader)

Post by Richard Russell »

Richard Russell wrote: Mon 26 Jan 2026, 22:55 So the presence of @memhdc% in the parameter list, which is generally a reliable indication that the GUI is being accessed, invokes this special handling.
It may perhaps be helpful to add some historical context. When BB4W was first released, in 2001, the thought of bypassing the standard Windows GUI (GDI32) to write to the screen more directly wasn't considered. I probably didn't know what DirectX and Direct3D were, and I certainly had no idea that they might be callable from BBC BASIC - or indeed why one might want to.

So in those simpler times, detecting when a SYS statement was going to be calling a function in the Windows GUI, requiring special handling to deal with the concurrency issue, was simple - if the parameters included @memhdc% it was and if they didn't it wasn't. This worked even when calling GDIplus, not just GDI32. So using @memhdc% as a flag was a no-brainer.

Much later, when BBCSDL was developed, this 'trick' worked equally well because once again most SDL2 functions that require special handling would necessarily take @memhdc% as a parameter (now referring to a Renderer rather than a Device Context).

But with the increasing use of 3D renderers or other technologies for accessing the display directly rather than via the GDI32 or SDL2 GUI (e.g. shaders) the need to add @memhdc% as a flag rather than as a true parameter has increased.
DDRM
Posts: 33
Joined: Mon 17 Jun 2024, 08:02

Re: Julia Set (shader)

Post by DDRM »

Hi Richard,

Oh, so the additional parameter is a requirement of (your) BBC BASICs? That would explain why it isn't in the OpenGL documentation!

With regard to your advice not to mess with stuff you don't understand, fair enough! However, as a computer science student I'm strongly encouraged NOT to use code I don't understand, so I tend to go read the (friendly) manual, which I know is also a piece of advice you favour, until I DO understand it, and then try to implement it in the cleanest possible way (which means not passing random stuff it doesn't need, among other things). Since the documentation made no mention of the need for the extra parameter, and it ran fine without it, I couldn't see much point in including it.

As an aside, you could argue that using Float{} is a black mark for me in that context, but (a) I tested it and it WAS necessary (b) I asked about it so I COULD understand it, and (c) I'm an idiot and should have worked out that Float{} was a pointer to the actual data, but I didn't.

Returning to the question of @memhdc%, I wonder if the reason I get away with it in BB4W (using the standard IDE) is your oft-noted fact that they run in the same thread?

It would definitely be helpful to have this use of @memhdc% noted somewhere in the manual - I've searched, and I don't think any of the current occurrences mention this use (or use it, as far as I can see). I found a couple of cases on the wiki where it is apparently used (for example, in the context of sound handling), but it doesn't explain why it is there. There's actually no page for the ShaderLib in either the embedded on online manual, so maybe it could go there?

Best wishes,

D
Richard Russell
Posts: 591
Joined: Tue 18 Jun 2024, 09:32

Re: Julia Set (shader)

Post by Richard Russell »

DDRM wrote: Tue 27 Jan 2026, 09:33 Since the documentation made no mention of the need for the extra parameter, and it ran fine without it, I couldn't see much point in including it.
Absence of evidence is not evidence of absence! :D

Firstly, the documentation making no mention of it is not the same thing as the documentation saying it is unnecessary! Secondly, that it "ran fine without it" on one specific platform (in your case 32-bit Windows) does not mean that it will run without it on any other platform.

I agree in principle about 'following the documentation' but all one could say in the BBC BASIC documentation is that the extra parameter might be required, not when it is required. The latter is determined by the function you are calling using SYS, and you won't find anywhere in the SDL 2.0 documentation whether a specific API must be called from a specific thread or not. :?

The same is sadly true of Windows. Whether or not a specific Win32 API function must be called from a specific thread, or can be called from any thread, is simply not documented. In practice the only way to find out seems to be to try it! You will find some overarching recommendation that all display-related calls be made from the 'GUI thread' but doing so unnecessarily will hit performance.

So the bottom line is that, yes, you should of course strive to understand the code you are writing and to follow the documentation, but when that documentation says nothing about the particular feature you are interested in what are you to do? And if you are coding for a cross-platform language testing it on every single platform is likely to be impractical.
As an aside, you could argue that using Float{} is a black mark for me in that context, but (a) I tested it and it WAS necessary (b) I asked about it so I COULD understand it, and (c) I'm an idiot and should have worked out that Float{} was a pointer to the actual data, but I didn't.
Given that you used the Float{} structure, which holds two numbers, I'm surprised that you didn't send both cr and ci together to the shader (as a two-component vector) rather than using two scalar calls.
Returning to the question of @memhdc%, I wonder if the reason I get away with it in BB4W (using the standard IDE) is your oft-noted fact that they run in the same thread?
The IDE doesn't come into it; the requirement for the @memhdc% 'flag' is the same even if your program runs standalone without the IDE. The key thing is that the Windows GUI itself is running in a different thread from the BBC BASIC interpreter, hence without special handling they could attempt concurrent access to shared resources such as a Device Context.
I don't think any of the current occurrences mention this use (or use it, as far as I can see)
The manual does use it. An additional @memhdc% parameter, used as a flag rather than being accepted by the called API function itself, is present in several of the sections of the manual under Accessing the SDL 2.0 API. Indeed the variety of different calls needing it (not just display related but also sound, for example) shows how difficult it can be to predict when it will be needed.
There's actually no page for the ShaderLib in either the embedded on online manual, so maybe it could go there?
It's not at all specific to shaderlib. I think the only place it could sensibly go would be in the documentation of the SYS statement. That is, after all, where the code to activate the 'special handling' resides.