Maizie Bones (new game)

Discussions related to graphics (2D and 3D), animation and games programming
guest
Posts: 268
Joined: Mon 02 Apr 2018, 09:12

Re: Maizie Bones (new game)

Post by guest » Mon 12 Nov 2018, 13:51

David Williams wrote:
Mon 12 Nov 2018, 10:11
the GPU still ends up Z-buffering potentially hundreds of occluded objects (especially walls, floors & ceilings) that can never ordinarily be seen from a particular vantage point, and that is very inefficient (and does cause slowdown).
I obviously didn't explain myself properly, because both you and DDRM seem to have misunderstood the point I was trying to make. The relevant performance comparison I was drawing attention to is between sending multiple small objects in the arrays passed to PROC_render() and sending fewer, larger, objects which represent the identical 'scene'. My assumption is that the total number of vertices and faces, and therefore the work that GPU has to do, is exactly the same in the two cases. What isn't the same is the work that BBC BASIC has to do in d3dlib/ogllib, which is related to the number of individual objects, not to the complexity of the 3D scene.

I was not advocating combining multiple objects, some of which might have been pruned, into larger objects that can't be pruned. This increases the overall complexity of what the GPU is being asked to render, which clearly isn't desirable and could well outweigh any advantage gained by passing fewer objects to PROC_render().
So the visible cells get switched on, all the others get switched off so that the GPU doesn't process them.
Yes of course, and I was never suggesting anything different. But it still seems to me quite likely that there might be several objects in relatively close physical proximity that you would treat as a group from the point of view of whether they are switched off (pruned) or switched on - perhaps they are all in the same 'room'. Because these objects probably have different texture maps (assuming they are textured) it is natural to treat them independently in the program, and pass them to PROC_render() in separate array elements, but my point is that performance can be improved by combining them into one large FVF file, sharing one tiled texture map, and using the UV coordinates to isolate the different textures for the different objects.

If there is no opportunity for grouping objects in this way in your program, then my suggestion isn't relevant, but more generally I still think it is worthwhile to point out the potential. Although I made the comment in a thread about your Maizie Bones games it was never intended to be directed specifically at you.
You might remember that with the 'Blue Monster Hunter' subgame in Maizie Bones, the 3D graphics were rendered via Direct3D inside a 'static box'. I will probably need to figure out how to do that with BBCSDL. I will of course read the SDL2.0 docs, but I might need to tap you for assistance with this if I stumble!
I don't think I'll be able to help with that, since it's not something I have attempted. You are of course correct in thinking that 'multiple windows' is not something that can be achieved in Android or iOS, they really don't have the concept of 'windows' at all. However I would point out that my BBCSDL adaptation of 'Treasure Tower' uses the 3D renderer to wrap the 2D maze around a cylinder, and this appears to be in a separate 'window' (the 'TV screen') but it really isn't. I'll be releasing it with the next version of BBCSDL (assuming you have no objection) but here's a sneak preview - 100% BASIC, one window:

http://www.youtube.com/watch?v=mB3RY8GFgsQ

DDRM
Administrator
Posts: 145
Joined: Mon 02 Apr 2018, 18:04

Re: Maizie Bones (new game)

Post by DDRM » Mon 12 Nov 2018, 16:38

I can see why my comment "that's interesting..." could be interpreted as conflicting with your advice. I didn't mean it like that - I was sort of setting an upper bound. Frankly, I was astonished that I could use anything like that number of polygons and still be able to fly around at all! What prompted my post was that you find that using multiple objects is slower, so I'll need to allow for the fact that the total number will need to be significantly smaller to be useful.

Is one potential advantage of using a separate object/buffer that you can use it multiple times (for example, to provide a clump of identical trees)? Presumably it would render slower, but take up a lot less memory, than incorporating the tree multiple times in the single file?

Best wishes,

D

guest
Posts: 268
Joined: Mon 02 Apr 2018, 09:12

Re: Maizie Bones (new game)

Post by guest » Mon 12 Nov 2018, 17:21

DDRM wrote:
Mon 12 Nov 2018, 16:38
What prompted my post was that you find that using multiple objects is slower, so I'll need to allow for the fact that the total number will need to be significantly smaller to be useful.
When you call PROC_render() in d3dlib.bbc or ogllib.bbc (or gleslib.bbc, but you don't usually install that explicitly) some of the work involved in rendering the scene is done in BBC BASIC code - for example the various trigonometric calculations involved with orienting objects and the 'camera' - and some by Direct3D/OpenGL.

The time taken by the latter, i.e. by the OS 3D library, depends primarily on the overall complexity of your 3D model, i.e. the total number of vertices and triangles etc. The time taken by the code in the BBC BASIC library, however, is effectively independent of the complexity of the model but is determined by the number of different 'objects' passed in the arrays, i.e. the numeric value of the nobj% parameter.

It therefore follows that for a given 3D complexity, reducing the number of 'objects' will result in an overall performance improvement, because the BBC BASIC library code will run faster but the Direct3D/OpenGL code won't be greatly affected. Of course if you need to be able to control the position or orientation of objects independently then they must be passed in different array elements, but objects which have a rigid relationship with each other can be combined into fewer FVF files and that way offer a benefit.
Is one potential advantage of using a separate object/buffer that you can use it multiple times (for example, to provide a clump of identical trees)?
Yes, in that relatively rare event it would be. For example in 'soldiers.bbc' the 16 tin soldiers are simply repetitions of the same object, sharing the same FVF file and the same texture. However, and this is noteworthy, each soldier - even though it consists of many different parts with different colours and textures - is represented by a single FVF file and the various textures are all combined into one 'patchwork' texture soldier.gif. You may find it interesting to look at that image file; I've no idea how it was originally generated.

DDRM
Administrator
Posts: 145
Joined: Mon 02 Apr 2018, 18:04

Re: Maizie Bones (new game)

Post by DDRM » Tue 13 Nov 2018, 08:36

Thanks, that's very helpful.

D

guest
Posts: 268
Joined: Mon 02 Apr 2018, 09:12

Re: Maizie Bones (new game)

Post by guest » Thu 15 Nov 2018, 03:23

David Williams wrote:
Mon 12 Nov 2018, 10:11
You might remember that with the 'Blue Monster Hunter' subgame in Maizie Bones, the 3D graphics were rendered via Direct3D inside a 'static box'. I will probably need to figure out how to do that with BBCSDL. I will of course read the SDL2.0 docs, but I might need to tap you for assistance with this if I stumble!
I expect you have discovered this already, but it seems that outputting 3D graphics in a 'child' window (created using the multiwin library) works perfectly straightforwardly, but as soon as you try to do anything in the 'main' window (even something as simple as outputting text) it instantly kills the 3D rendering. It's not at all obvious to me why doing something in one window is upsetting the other window. :?

So if in your proposed program you simply need to display something static in the main window whilst the 3D animation takes place that ought to be easy, but if you want to change the contents of the main window (for example to update a score) I haven't succeeded in doing that.

David Williams
Posts: 84
Joined: Wed 04 Jul 2018, 16:23

Re: Maizie Bones (new game)

Post by David Williams » Thu 15 Nov 2018, 03:59

guest wrote:
Thu 15 Nov 2018, 03:23
So if in your proposed program you simply need to display something static in the main window whilst the 3D animation takes place that ought to be easy, but if you want to change the contents of the main window (for example to update a score) I haven't succeeded in doing that.
I will probably be able to get away with displaying things like score and health indicators (if those are even required), messages, and representations of collected items, etc., as (perhaps) textured objects (quads, etc.) sent along as part of the 3D rendering 'pipeline' (rather like I did with the 'crosshair' in Blue Monster Hunter -- not textured in that case, but it was a static '3D' object whose position was re-calculated (albeit often unnecessarily) each frame.


David.
--

guest
Posts: 268
Joined: Mon 02 Apr 2018, 09:12

Re: Maizie Bones (new game)

Post by guest » Thu 15 Nov 2018, 13:53

David Williams wrote:
Thu 15 Nov 2018, 03:59
I will probably be able to get away with displaying things like score and health indicators (if those are even required)…
I made it work! The problem was more one of careless coding than anything fundamental: there are several things you have to do when switching between the 2D 'main' window and the 3D 'child' window (swap the window handles, swap the renderer handles, swap the OpenGL contexts) and it's important that they be done in the right order - and I wasn't doing it right. This program, assuming it works for you, should do what you want and allow you to update the main window whilst the 3D window is open if you need to.

Code: Select all

      REM Demonstration of independent 3D child window

      INSTALL @lib$+"ogllib"
      INSTALL @lib$+"multiwin"
      PROC_multiwin(1)

      SYS "SDL_GetWindowID", @hwnd% TO IDmain%
      ON CLOSE IF @lparam% = 0 OR @lparam% = IDmain% PROCcleanup : QUIT ELSE RETURN
      ON ERROR ON ERROR OFF : ERROR 0,REPORT$ : PROCcleanup : QUIT

      SYS "SDL_GetWindowPosition", @hwnd%, ^x%, ^y%
      hw1%% = FN_createwin(1, "3D window", x% + 230, y% + 10, 400, 300, 0, 0, 0)
      SYS "SDL_SetWindowBordered", hw1%%, 0

      PROC_selectwin(1)
      SYS "SDL_GL_GetCurrentContext", @memhdc% TO Context2D%%
      PROC3dsetup
      SYS "SDL_GL_GetCurrentContext", @memhdc% TO Context3D%%
      SYS "SDL_GL_MakeCurrent", @hwnd%, Context2D%%, @memhdc%
      PROC_selectwin(0)
      
      COLOUR 128+2
      CLS
      *REFRESH

      REPEAT
        REM Select 3D window (don't use PROC_selectwin for this):
        @hwnd%=Win{(1)}.hwnd%%
        @memhdc%=Win{(1)}.hdc%%
        SYS "SDL_GL_MakeCurrent", @hwnd%, Context3D%%, @memhdc%

        REM. Render the tumbling object:
        eye() = 0, 0, -9
        at() = 0, 0, 0

        y() = TIME/200
        r() = TIME/80
        PROC_render(pDevice%, &7F7F7F, 1, l%(), 1, m%(), t%(), pVB%(), nv%(), vf%(), vl%(), \
        \ y(), p(), r(), X(), Y(), Z(), eye(), at(), PI/6, @vdu%!208/@vdu%!212, 1, 1000, 0)
        SYS "SDL_RaiseWindow", @hwnd%

        REM Select 2D window:
        SYS "glFinish"
        SYS "SDL_GL_MakeCurrent", @hwnd%, Context2D%%, @memhdc%
        PROC_selectwin(0)

        N% += 1
        PRINT '"Main window "; N%;
        *REFRESH

      UNTIL FALSE
      PROCcleanup
      END

      DEF PROCcleanup
      pVB%(0) += 0  : IF pVB%(0)  PROC_release(pVB%(0))
      pDevice% += 0 : IF pDevice% PROC_release(pDevice%)
      *REFRESH ON
      PROC_selectwin(0)
      PROC_closewin(1)
      ENDPROC

      DEF PROC3dsetup
      LOCAL F%, V%, a, b, c, d, e, f, x1, x2, x3, y1, y2, y3, z1, z2, z3, n()

      DIM pVB%(0)
      VDU 20,26,12

      DIM pVB%(0), nv%(0), vf%(0), vl%(0), l%(0), m%(0), t%(0), y(0), p(0), r(0)
      DIM X(0), Y(0), Z(0), eye(2), at(2), n(2)

      REM. Initialise OpenGL:
      pDevice% = FN_initgl(@hwnd%, 0, 1)
      IF pDevice% = 0 ERROR 100, "Couldn't initialise OpenGL"

      REM. Create 3D object with surface normals:
      F% = OPENOUT(@tmp$+"lighting.fvf")
      BPUT #F%,18 : BPUT#F%,0 : BPUT #F%,0 : BPUT#F%,0   : REM number of vertices
      BPUT #F%,&12 : BPUT #F%,0 : BPUT#F%,24 : BPUT#F%,0 : REM vertex format and size
      FOR V% = 0 TO 5
        READ x1, y1, z1, x2, y2, z2, x3, y3, z3
        a = x2 - x3
        b = y2 - y3
        c = z2 - z3
        d = x1 - x3
        e = y1 - y3
        f = z1 - z3
        n(0) = b*f-c*e
        n(1) = c*d-a*f
        n(2) = a*e-b*d
        n() /= MOD(n())
        PROC4(F%,x1) : PROC4(F%,y1) : PROC4(F%,z1)       : REM xyz coordinates
        PROC4(F%,n(0)) : PROC4(F%,n(1)) : PROC4(F%,n(2)) : REM surface normal
        PROC4(F%,x2) : PROC4(F%,y2) : PROC4(F%,z2)       : REM xyz coordinates
        PROC4(F%,n(0)) : PROC4(F%,n(1)) : PROC4(F%,n(2)) : REM surface normal
        PROC4(F%,x3) : PROC4(F%,y3) : PROC4(F%,z3)       : REM xyz coordinates
        PROC4(F%,n(0)) : PROC4(F%,n(1)) : PROC4(F%,n(2)) : REM surface normal
      NEXT
      CLOSE #F%

      REM. Load 3D object:
      pVB%(0) = FN_load3d(pDevice%, @tmp$+"lighting.fvf", nv%(0), vf%(0), vl%(0))
      IF pVB%(0) = 0 ERROR 101, "Couldn't load 'lighting.fvf'"

      REM. Point-source light:
      DIM light{Type%, Diffuse{r%,g%,b%,a%}, Specular{r%,g%,b%,a%}, \
      \ Ambient{r%,g%,b%,a%}, Position{x%,y%,z%}, Direction{x%,y%,z%}, \
      \ Range%, Falloff%, Attenuation0%, Attenuation1%, Attenuation2%, \
      \ Theta%, Phi%}

      light.Type% = 1              : REM. point source
      light.Diffuse.r% = FN_f4(1)  : REM. diffuse colour RGB
      light.Diffuse.g% = FN_f4(1)
      light.Diffuse.b% = FN_f4(1)
      light.Specular.r% = FN_f4(1) : REM. specular colour RGB
      light.Specular.g% = FN_f4(1)
      light.Specular.b% = FN_f4(1)
      light.Position.x% = FN_f4(0) : REM. position XYZ
      light.Position.y% = FN_f4(0)
      light.Position.z% = FN_f4(-4)
      light.Range% = FN_f4(10)     : REM. range
      light.Attenuation0% = FN_f4(1) : REM. attenuation (constant)
      l%(0) = light{} - PAGE + !340

      REM. Gold-coloured material:
      DIM material{Diffuse{r%,g%,b%,a%}, Ambient{r%,g%,b%,a%}, \
      \     Specular{r%,g%,b%,a%}, Emissive{r%,g%,b%,a%}, Power%}

      material.Diffuse.r% = FN_f4(1)  : REM. diffuse colour RGB
      material.Diffuse.g% = FN_f4(0.7)
      material.Diffuse.b% = FN_f4(0)
      material.Specular.r% = FN_f4(1) : REM. specular colour RGB
      material.Specular.g% = FN_f4(1)
      material.Specular.b% = FN_f4(1)
      material.Power% = FN_f4(20): REM. specular 'power'
      m%(0) = material{} - PAGE + !340
      ENDPROC

      REM. Pyramid (6 triangles each with three vertices):
      DATA -1, -1,  1, -1, -1, -1,  0, .414,  0
      DATA  1, -1,  1, -1, -1,  1,  0, .414,  0
      DATA  1, -1, -1,  1, -1,  1,  0, .414,  0
      DATA -1, -1, -1,  1, -1, -1,  0, .414,  0
      DATA  1, -1, -1, -1, -1, -1, -1,   -1,  1
      DATA -1, -1,  1,  1, -1,  1,  1,   -1, -1

      DEF PROC4(F%,a) : LOCAL A% : A%=FN_f4(a)
      BPUT #F%,A% : BPUT #F%,A%>>8 : BPUT#F%,A%>>16 : BPUT#F%,A%>>24
      ENDPROC

David Williams
Posts: 84
Joined: Wed 04 Jul 2018, 16:23

Re: Maizie Bones (new game)

Post by David Williams » Thu 15 Nov 2018, 17:12

guest wrote:
Thu 15 Nov 2018, 13:53
This program, assuming it works for you, should do what you want and allow you to update the main window whilst the 3D window is open if you need to.
Thank you, I've just tried the program under BBCSDL (Windows), and I've added it to my growing collection of handy BBCSDL code snippets (I hope others do likewise). Whilst it demonstrates a way to have a main window for 2D and a separate child window for 3D output, it isn't really what I want, which is to be able to display the 3D render output inside a graphics window/viewport within the main window like I did with 'Blue Monster Hunter' (via a 'static box' created with the WINLIB5 library). But I accept that this may not be easily or at all possible with SDL2.0/OpenGL. I really don't want to come across as unappreciative of your effort (I'm grateful), it's just that for my particular application, the two separate window (main + child) approach doesn't really appeal to me.


David.
--

guest
Posts: 268
Joined: Mon 02 Apr 2018, 09:12

Re: Maizie Bones (new game)

Post by guest » Thu 15 Nov 2018, 18:14

David Williams wrote:
Thu 15 Nov 2018, 17:12
it isn't really what I want, which is to be able to display the 3D render output inside a graphics window/viewport within the main window like I did with 'Blue Monster Hunter' (via a 'static box' created with the WINLIB5 library).
The 'static box' created with the WINLIB5 library is a 'child window' of your main window, but a parent-child window hierarchy is a Windows-specific feature that not all OSes have; notably MacOS doesn't support it so neither does SDL 2.0. Crucially, SDL is not a Windows emulator like Wine, it doesn't try to make one OS behave like another. Rather, it presents the native capabilities of the OS in a platform-independent way.

The closest you can get to a 'child window' in SDL is to arrange that an auxiliary window is displayed in front of its 'parent' window (which I've done using SDL_RaiseWindow in the code listed) and to automatically move the auxiliary window to track movement of the main window (which I've not done in that code, but is obviously easily arranged by means of an ON MOVE handler):

Code: Select all

      ON MOVE SYS "SDL_SetWindowPosition", hw1%%, ((@lparam% << 16) >> 16) + 230, (@lparam% >> 16) + 10 : RETURN
I've previously described the alternative approach of having a single window, with the 3D content visible through a transparent 'hole' or 'window' in an otherwise opaque layer, such as in my adaptation of the Treasure Tower subgame. But that and the 'synthetic child window' are the only two options you have.

Post Reply