Update 75

It seems TGA and PSD are the fastest image format read by stb_image. TGA is an old uncompressed format with support transparency layers, uncompressed images have the same size on the disk and in memory. PSD is compressed with RLE which is really simple and fast to decode however it do not compress a lot the image. I think I will be using PSD for the most sprite sheets now.

For my sprite sheets generator, I have had some problems with CImg trying to generate a sprite sheet with a lot of small images. So I now use OpenCV for the generation which seems to be the standard for computer vision. OpenCV is quite heavy, but everything is reliable and really fast compared to CImg.

The last level progresses a little bit each day and becomes bigger and bigger. This level has a lot of big images, for example, the level objects and one map need three sprite sheets. So maybe I will split the objects along maps more to balance the loading time and improve memory footprint.

Update 74

This week I have done more art for the game, and then packing the art into multiple sprite sheets. After that, I have spent multiple days trying to optimize the loading of the sprite sheet.

At first, I have been trying to implement a support for DXT texture, but with SDL_gpu using stb_image to load the texture into an SDL_Surface and then converting it to a GPU_Image. I have tried to decode the DXT textures with GLI, but after that SDL_gpu was not able to recognize the format.

Another problem with DXT texture is the artifacts produced by the compression so I have been trying to find a format lossless and fast. I have made a small benchmark for png with no compression and a lot of compression with stb_image and libpng.

compressed png (stb_image): 360.591 ms
uncompressed png (libpng): 543.351 ms
compressed png (libpng): 330.504 ms

I was expecting the png with no compression to be faster, the time to read the file seems to outweigh the decoding of the png. The small png are compressed with TruePNG and the zopflipng with the max compression settings. To make the game load faster I can first load all the asset for a level in the RAM and then for each map transfer the asset needed into the VRAM. The total memory needed to load the assets of the level is: 30 * 2048 *2048 * 4 = 503 MB. This is fine since most people have at least 4GB of RAM.

To make the game load faster I can first load all the asset for a level in the RAM and then for each map transfer the asset needed into the VRAM. The total memory needed to load the assets of the level is: 30 * 2048 *2048 * 4 = 503 MB. This is fine since most people have at least 4GB of RAM (steam survey).

To make the game load faster I can first load all the asset for a level in the RAM and then for each map transfer the asset needed into the VRAM. The total memory needed to load the assets of the level is: 30 * 2048 *2048 * 4 = 503 MB. This is fine since most people have at least 4GB of RAM.

For the moment, loading on the fly compressed png files seem efficient enough, the loading time is around 1 second for the map with the most sprites to load.

Update 73

The last level is progressing slowly because I have changed the story little bit at one point and there are a lot of art to redo, new dialogs, and even new shaders.

Most of my shaders are a modified version of some shaders found on shadertoy. This time I have combined two shaders to make one.
This one applies a glitchy effect on the image and also radial blur at the position of the uniform mouse.

varying vec4 color;
varying vec2 texCoord;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform float globalTime;
uniform vec2 resolution;
uniform float Strength;
uniform vec2 mouse;
#define AMPLITUDE 0.2 //0.2
#define SPEED 5 //0.05
float rand(float n){return fract(sin(n) * 43758.5453123);}
vec4 rgbShift( in vec2 p, in vec4 shift, in float Samples) {
shift *= 2.0*shift.w - 1.0;
vec2 rs = vec2(shift.x,-shift.y);
vec2 gs = vec2(shift.y,-shift.z);
vec2 bs = vec2(shift.z,-shift.x);
//vec2 pos = vec2(960.0*(resolution.x/1920.0), 540.0*(resolution.y/1080.0));
vec2 pos = vec2(mouse.x, mouse.y);
vec2 dir = (gl_FragCoord.xy-pos.xy)/resolution.xy*vec2(-1.0,1.0);
float r = 0;
float g = 0;
float b = 0;
float a = 0;
for (int i = 0; i < Samples; i += 2) {
r += texture2D(tex0,p+rs+float(i)/float(Samples)*dir*Strength).x;
g += texture2D(tex0,p+gs+float(i)/float(Samples)*dir*Strength).y;
b += texture2D(tex0,p+bs+float(i)/float(Samples)*dir*Strength).z;
a += texture2D(tex0,p+float(i)/float(Samples)*dir*Strength).w;
r += texture2D(tex0,p+rs+float(i+1)/float(Samples)*dir*Strength).x;
g += texture2D(tex0,p+gs+float(i+1)/float(Samples)*dir*Strength).y;
b += texture2D(tex0,p+bs+float(i+1)/float(Samples)*dir*Strength).z;
a += texture2D(tex0,p+float(i+1)/float(Samples)*dir*Strength).w;
}
return vec4(r,g,b,a);
}
vec4 noise( in vec2 p ) {
return texture2D(tex1, p, 0.0);
}
vec4 vec4pow( in vec4 v, in float p ) {
// Don't touch alpha (w), we use it to choose the direction of the shift
// and we don't want it to go in one direction more often than the other
return vec4(pow(v.x,p),pow(v.y,p),pow(v.z,p),v.w); 
}
void main() {
vec2 p = texCoord;	
vec4 c = vec4(0.0,0.0,0.0,1.0);
vec4 shift = vec4pow(noise(vec2(SPEED*rand(globalTime), 2.0*SPEED*rand(globalTime)/25.0)),11.0)*vec4(AMPLITUDE,AMPLITUDE,AMPLITUDE,1.0);
const int Samples = 64;
c += rgbShift(p, shift, Samples);
gl_FragColor = c/float(Samples);
}

I think most of the shaders of the game are done by now. There is a total of 4 fragment shaders. After that, I have more art to do, maybe some animations and then the ending video of the game (I not sure what to include in the video).

Update 72

This week I have worked exclusively on the last level, adding new things, redoing old stuff. I am trying to add new effects such as this:

With this amount of particles, I doubt the particles system can handle it, I need to make some performance test. The solution good solution is to use shaders, there is this tutorial with WebGL.

In Obduction, the effect is used multiples times, so it needs to be available for multiple cases. I am only using this once in the game, so I can probably prerender this effect with adobe after effect in a video. This is probably the fastest solution if I can make the video fast enough. If I use shaders to make this effect it can add a lot of complexity in adding multiples effects at the same time. And another good thing with video is I don’t have to worry about the frame rate, the video will run at 30 fps

This is probably the fastest solution if making the video is fast. If I use shaders to make this effect it can add a lot of complexity in adding multiples effects at the same time. And another good thing with video is I don’t have to worry about the frame rate, the video will run at 30 fps. I don’t need to have input from the player for the effect, this makes the use of something prerendered possible.

Update 71

A lot of optimization and bug fixing this week, the level did not progress at all.I have optimized the text rendering with a small library

I have optimized the text rendering with a small library NFont developed by the creator of SDL_gpu. I have gained a more stable framerate 60 fps when a shader is used.

I have also improved the loading time of the game by generating sprite sheets for the objects. Doing that I have discovered the rendering of SDL_gpu (which use OpenGL) is not precise when the image is rotated, the image becomes blurry. So I add to replace SDL_gpu with a library specialized in image processing to have something precise. I have chosen a small, simple and header only library: CImg. The replacement is not finished yet, I need to redo the sprite sheets for the animations, maps, and menu.

There are so many unexpected bugs coming along, it became really difficult to have accurate estimations. The only thing I know is I have two months left before the job hunting. Hopefully, everything will be finished by then, if not I will continue working part-time on the game. I am not going to release something unfinished or not polished enough.