Welcome, Guest
You have to register before you can post on our site.



Search Forums

(Advanced Search)

Forum Statistics
» Members: 41
» Latest member: Joachim
» Forum threads: 152
» Forum posts: 489

Full Statistics

Online Users
There are currently 17 online users.
» 0 Member(s) | 17 Guest(s)

Latest Threads
Its getting better
Forum: Getting started
Last Post: Brian Beuken
Yesterday, 12:12 PM
» Replies: 0
» Views: 7
Cube OpenGL ES 2.0 exampl...
Forum: Getting Started
Last Post: jomoengineer
Yesterday, 06:06 AM
» Replies: 4
» Views: 33
Chapter 7 Assets
Forum: Fundamentals Errata/Questions
Last Post: Brian Beuken
02-18-2019, 08:28 PM
» Replies: 16
» Views: 223
OpenGLES3.0 causes flcker...
Forum: Help my code won't work??
Last Post: Brian Beuken
02-18-2019, 06:22 PM
» Replies: 3
» Views: 30
Asus Tinkerboard
Forum: Other SBC's
Last Post: Brian Beuken
02-17-2019, 02:27 PM
» Replies: 9
» Views: 1,098
Make sure you update and ...
Forum: Getting started
Last Post: jomoengineer
02-15-2019, 08:02 AM
» Replies: 1
» Views: 56
So....what do I do?
Forum: Getting started
Last Post: Brian Beuken
02-13-2019, 09:10 AM
» Replies: 10
» Views: 2,260
Reviewing the code
Forum: Scratchpad Games
Last Post: Brian Beuken
02-13-2019, 12:53 AM
» Replies: 1
» Views: 77
If your trial has run out...
Forum: Getting started
Last Post: Brian Beuken
02-11-2019, 10:08 PM
» Replies: 1
» Views: 42
Finally have a machine
Forum: OpenGLES3.2 Shaders
Last Post: Brian Beuken
02-11-2019, 11:51 AM
» Replies: 6
» Views: 845

  C++ Coding MagPi #69
Posted by: Brian Beuken - 04-13-2018, 08:29 AM - Forum: General Chat - No Replies

A bit of a leap this month as we finally get a game (of sorts) up and running. Most of the explanations for what is happening are in the source code as the article needs to describe what we're doing rather than spell out the code.

Using what we learned previously about creating objects and giving them graphics we can arrange for a playfield to be displayed and populate it with items which we set up at the beginning and also create as the game is in progress.

This is our first proper use of inheritance and creating objects in the free space memory using the new keyword. It also means we need to take responsibility for removing items we make when we are done with them which brings us to the delete keyword. These 2 keywords should always balance up.

We will also see that even though we are making a game, it clearly suffers from some issues, especially speed. Next month we need to look into why a project that is working fine, isn't working fast and what we can do about that.

Print this item

  [Chapter 04] Unclear where to put the FileHandler code
Posted by: sephris - 04-10-2018, 01:06 PM - Forum: Fundamentals Errata/Questions - Replies (2)


So I just finished the part about displaying the single picture ("lenna.png") in chapter 04. There's one part that seemed unclear to me and that's where to put this FileHandler code:

int Width, Height;
char* OurRawData = FileHandler.Load((char*)"../assets/lenna.png", &Width, &Height);
if (OurRawData == NULL) printf("Picture failed to load.\n");
p_state->user_data->textureID = CreateTexture2D(Width, Height, OurRawData);

You mention a while (TRUE) loop on page 63 as if it's already existing, but if you look back at the first code listing for the triangle on page 49, there is no while loop in the main function. 

My first reaction was to put the new code into the esMainLoop function (I mean, it's already called main loop, it has a while loop that terminates and it worked previously) which resulted in a program that was executing but displayed no picture, no compiler errors and none of the debug messages. So, without any errors I started looking for mistakes elsewhere and checked the code that was changed in this chapter so far against the book ... twice. Only when looking at the project file you uploaded for chapter 04 did I notice that you had placed a new while loop in the main function. 
So, to summarize, on page 61 you wrote "After the FileHandler add this code;"  which in my opinion should have been something like "Above the esMainLoop function in the main function at the bottom, add the following code:" and then on page 63 it should have said to add the new line below and put a while (TRUE) loop around it while also mentioning that execution of the program can now only be stopped from within Visual Studio by pressing the "Stop Debugging"-button.

Another thing, maybe for the next edition: Could you please highlight the changes you made to existing code?

Print this item

  Missing tileset
Posted by: Brian Beuken - 04-10-2018, 08:01 AM - Forum: Help my code won't work?? - Replies (1)

Skramble tile set is missing, I'll add this ASAP
but for now here it is

Attached Files Thumbnail(s)
Print this item

  Shadow Mapping Shaders
Posted by: Brian Beuken - 04-08-2018, 02:30 AM - Forum: OpenGLES2.0 Shaders - No Replies

Shadow Mapping requires 2 sets of shaders, one to gather the shadows and one to render them

The principles are explained in the Fundamentals book, so I won't go into them here, and the shaders are also available on downloadable demo's but I thought I'd put them here in isolation for you as well. These are optimized to run reasonably well on OpenGLES2.0 giving the client side (CPU) the responsibility to create the MVP for light and Models. Normally on a PC you'd let the Shader caclulate them, but here its better to let the CPU pass these as a uniform. (because even though PC is far slower to do the calculations, its a one time thing, but on a limited core GPU you don't gain the performance boost you would on a 512core unit)

1st thing to remember is that you need to do a gathering pass, where you render your height map into an FBO so you need to have an FBO 1st. This is easy to set up like so.

// only used when creating dynamic shadows.
// Create and return a frame buffer object
GLuint Graphics::CreateShadowBuffer(int width, int height)
    GLuint    FBO, RenderBuffer;
    glActiveTexture(GL_TEXTURE1);  // use an unused texture
// make a texture the size of the screen
    glGenTextures(1, &ShadowTexture);
    glBindTexture(GL_TEXTURE_2D, ShadowTexture); // its bound to texture 1

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
// once the texture is set up, we can turn to the Framebuffer    

    glGenFramebuffers(1, &FBO); // allocate a FrameBuffer
    glGenRenderbuffers(1, &RenderBuffer); // allocate a render buffer
    glBindRenderbuffer(GL_RENDERBUFFER, RenderBuffer); // bind it
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width,height); //give some parameters for it
    glBindTexture(GL_TEXTURE_2D, ShadowTexture);  // bind the texture
    glBindFramebuffer(GL_FRAMEBUFFER, FBO); // and the frame buffer

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, RenderBuffer); // they are now attached
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ShadowTexture, 0); // and so is the texture that will be created

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        printf("oh bugger framebuffer not properly set up");
    glActiveTexture(GL_TEXTURE0);  // careful to not damage this
    return FBO;

Height and width should be the same (512x512 or 1024*1024 work well), but  you can have any size you want up to the max size of textures, but the bigger the better, though there is a speed penalty the bigger the buffer is. If you have a very large scene, it might be better to use a number of different lights and switch between them with different view areas to cover the space.

Now that you have your framebuffer, you only need to switch it on and clear it before running a gathering pass

// if we are going to have shadows, we need to do a pass through all the objects and do the draw shadow routines for anything that casts
    glBindFramebuffer(GL_FRAMEBUFFER, MyGraphics->ShadowFB);
    glViewport(0, 0, ShadowBufferSize, ShadowBufferSize);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // clear
    for (int i = 0; i < MyObjects.size(); i++)
        MyObjects[i]->DrawShadow(); // most objects will do a dummy call
    } // for

The DrawShadow method is a much more simplified drawing system, which has no need of textures or light effects, it only needs to do a simple draw with these shaders, 1st the vertex.

#version 100

precision mediump float;
// simple shader to gather the depth, its a 1st pass shader designed to render into a bound FBO

attribute vec4 a_position;
uniform mat4 u_lightMVP; // light MVP is the casters Model, the lights view and Projection
varying vec4 v_texCoords; // we have to pass coords to the frag shader

void main()
    gl_Position = u_lightMVP * a_position;
    v_texCoords = gl_Position; // pass this to the fragment which can't access gl_Position
And now the fragment
#version 100
precision mediump float;
varying vec4 v_texCoords;

Generate shadow map
We need to gather the depth values, bring them into range
and then encode them into the x and y values of the
colour value we create
This shader should be linked with ShadowMap.vsh and used with a bound FBO

void main()
    float value = 10.0 - v_texCoords.z; // 10 is the most usual range
    float num = floor(value);
    float f = value - num;    // get the floating point value
    float vn = num * 0.1;
    gl_FragColor = vec4(vn, f, 0.0, 1.0);    
any model which casts a shadow needs to set up these shaders, and then simply run a simplified DrawShadow Method.
Once thats done, you will have a nice FBO filled with shadow info, actually height map info,  and you can switch off your FBO and render back to screen with a simple
    // release the shadow framebuffer    
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    // Setup the viewport
    glViewport(0, 0, MyGraphics->p_state->width, MyGraphics->p_state->height);

Now we're ready to render normally, Your Vertex Shader looks like this
#version 100
precision mediump float;
attribute vec4 a_position;
attribute vec3 a_normal;
attribute vec2 a_texCoord;

uniform mat4 MVP; // our models MVP
uniform mat4 u_LightsMVP; // our lights MVP (using the objects model)

varying vec4 v_ShadowTexCoord; // the texture coords for the shadow
varying vec2 v_texCoord; // the usual texture coords for the texture

// we need to bring our values into range so this matrix will do that
const mat4 biasMatrix = mat4(0.5, 0.0, 0.0, 0.0,
                             0.0, 0.5, 0.0, 0.0,
                             0.0, 0.0, 1.0, 0.0,
                             0.5, 0.5, 0.5, 1.0);

void main()

// Calculate vertex position, seen from the light view point and Normalize texture coords from -1<>1  
    v_ShadowTexCoord = biasMatrix * (u_LightsMVP * a_position); // this result gets passed to the frag shader as its a varying

// do our normal position calculations
    gl_Position = MVP * a_position; // use the models normal camera based MVP

// pass the texture coord to the frag and our lit flag
    v_texCoord = a_texCoord;


and your fragment 
#version 100
precision mediump float;

This is a base level system for adding shadows to your scene, it uses a simple
FBO as a texture to gain access to a shadow map.
The result is an effective but potentially low resolution hard shadow (depending on scene size and light spread)
Softer shadows can be done using PCF or other methods but there is a very significant
drop in performance on limited core GPU's and you need a better resolution to get good results, on phones/SBC's this may be too much.

uniform sampler2D s_texture; // texture0 our normal diffuse texture
uniform sampler2D u_s2dShadowMap; // texture1 our FBO shadows

uniform vec4 Ambient; // not used yet

varying vec4 v_ShadowTexCoord; // the coordinates passed from the vertex shader
varying vec2 v_texCoord; // passed by our normal textures

void main()
float fLight = 1.0; // supply a transparent value as defaut

/* we need to get the packed light distance data from the shadow texture, texture1. */
vec2 Depth = texture2DProj(u_s2dShadowMap, v_ShadowTexCoord).xy;
// its in 2 values scaled down so resize them
float fDepth = (Depth.x * 10.0 + Depth.y);
// reconstitute the depth
float ActualDepth = (10.0-v_ShadowTexCoord.z) + 0.1 - fDepth ;
if    (fDepth> 0.0 && ActualDepth <0.0)
    fLight = 0.6; // set lower values for a darker shadow

    gl_FragColor = texture2D( s_texture, v_texCoord )*fLight; // we can also use ambient and other light factors here
    gl_FragColor.w = 1.0;
And thats it... Assuming you set up the light to an overhead location that is not too far away from the casters, and your draw routine  provides the appropriate uniforms and attribute pointers you will get a nice set of shadows like this

[Image: snapshot.png]

Shadow mapping is an effective and relatively fast way to do shadows, but softer edge shadows are preferred, trouble is the Pi GPU and most other SBC GPU's will struggle to do too much of the sampling needed to do them, so for now this is probably the best option. But....there are ways to make it better,  I'll let you explore them.

You will note that the shadow has rather chunky pixels, this can be improved with a decent sample system to give anti aliasing, but as noted you will find there is a massive speed hit for that. 
Also a factor, is the resolution of our FBO, whatever size it is it will stretch over the view of our lights coverage of the terrain so a smaller FBO stretches further and has chunkier pixels. 
Separate lights swapped as needed and focusing on areas that are close to the size of the texture will provide better results. Larger resolution FBO's are also good, but do come at a cost of speed.

Of course these shaders don't do any lighting or Lerping, which you will need to add if you want them, but remember, the more you make your shaders do, the slower they get. 
This very simple shadow technique has its flaws, but it will work on pretty much any system. Culling systems to prevent rendering when not needed will also make a massive difference.

Print this item

  Opening this sub forum to all
Posted by: Brian Beuken - 03-27-2018, 09:32 AM - Forum: Scratchpad Games - Replies (1)

The book is selling well, and people are downloading files, but I can't help but notice not so many people are signing up here.

There is a problem at the moment with the email activation systems but I am manually activating all applicants as long as they are not obvious spambots. 

In case you don't want to register but still need help/content, I've opened this sub forum up to guest posts, so if you want to ask a question or make a comment without registering, feel free.

EDIT= Sadly the spambots hit as soon as it was opened, so I've had to turn on thread moderation and prevent posting replies to keep them out, but I check this site often so new threads from legitimate posters will be cleared pretty quick.

Print this item

  Other Model Formats
Posted by: Brian Beuken - 03-24-2018, 09:09 PM - Forum: Assets, Tools, Libraries and other useful things - No Replies

I am investigating some other model formats, mainly MD5 to experiment with skeletal systems where there are a lot of public domain assets around.

I won't be posting my efforts for a while though as I'm caught up in some other things non SBC related. But my colleague Ahbishek Biswas at NHTV did manage to get a nice little demo of MD5 up and running on Pi, so it just needs a bit more time to optimise

I'm also investigating the use of glFT since Soyo has a tinyglft loader that is in production, it might give us access to more interesting model formats, as soon as I can work out how to extract the data and a render system to draw it.
If anyone has had any success in that field, please tell us all about it.

Print this item

  Sounds, sounds everywhere
Posted by: Brian Beuken - 03-24-2018, 12:58 PM - Forum: Assets, Tools, Libraries and other useful things - Replies (1)

This is very very useful. 30GB of free soundfx for all sorts of game styles, easily incorporated into our games.
Download and store, there's also a useful index of all the sounds as there are so many to keep track of.


Print this item

  Don't alter the acronyms please?
Posted by: Brian Beuken - 03-21-2018, 01:46 AM - Forum: Fundamentals Errata/Questions - No Replies

page 175 
Again a great typesetter error, OOP stands for OOP. What? I wrote OOP stands for Object Oriented Programming.

That's a fun one, I hope they haven't done that too often.

Print this item

  taking monochrome too far, its a red dot!
Posted by: Brian Beuken - 03-21-2018, 01:08 AM - Forum: Fundamentals Errata/Questions - No Replies

I only just noticed this one, on page 8,11 and 12, there is mention of a grey dot when using the debugger.... which is funny because what I wrote was, there is a red dot!

Clearly the type setters looked at the monochrome version of the image, and decided to "correct" my text since it certainly is grey in the image.....but of course on your screen its red.

Print this item

  Why are you using Microsoft systems for a linux machine?
Posted by: Brian Beuken - 03-20-2018, 03:56 PM - Forum: Fundamentals Errata/Questions - No Replies

A few people have contacted me and asked this question, and I suppose it does deserve an answer.

And the honest answer is, its easier!

Sooooooo much easier!

If you chose to abandon Windows and have a desktop Linux system, then great, you got a free OS that does exactly what you want...but it does not do everything, it needs tweaking, and fiddling and installing odd tools to do something else...thats not ideal.

I'm not a Windows fan boy, by any means, it often has me swearing at it, but I just like to use simple professional tools in simple professional ways, Linux basically does not have them available. Mac does...kinda, but it also sucks the life out of you.

So like almost all pro game devs, my main work system is my home PC and work Laptop, I use my free copy of Visual Studio 2017, or my heavily discounted (educational) Visual Studio 2013 on my Windows 8.1 and Windows 10 systems, and everything works.

It just works, it does what I need it to do, largely without fuss or bother, and I use the tools all the pros use.

If you choose to use Desktop Linux, I have no issue with that,  but I don't!

Now if that puts you off buying the book, I am sorry, but you also are missing out on a simple point, the code being built isn't actually specific to the dev system. It can be compiled on any machine, as long as you understand the build process and how to add files to a project. 

So if you really want to use Linux, and one of its many IDE's you can, just create the projects in the manner required by your choice of IDE, and add the source files, take note of the libs and paths and you should be good to go. You can even use a Linux based PC with an IDE, to target your SBC just as I do with my windows system. But as I don't have Linux desktop, I can't really help with how, but I know it can be done. I hope others will post their experience of using a Linux dev system, to a Linux target,

Converting the projects won't be too hard, it'll take you an hour or 2 to get set up but, once you are, adding new files and libs won't be any greater a chore than it is for me on VS, with VGDB.

Lets all use the OS's we like, and focus on making the SBC's run our code, independent of their OS.

Print this item