Voxel - a start

Not sure if Riven will still allow this in WIP…probably not :\

Just want to clarify about memory leaks…

Memory leaks ain’t something a language has, but what a program has.
It’s a mistake of the programmer, who forgot to free some memory. In java we have our GC and we don’t have to free any memory, so in that sense, ‘java hasn’t got memory leaks’.

The memory leaks people in java talk about are mistakes of the programmer (again), but it’s simply just forgetting to null some value or to stop a running thread.

Nulling values example:


public class Stack<E> {
    private ArrayList<E> elems = new ArrayList<>();
    private int index = 0;

    public void push(E elem) {
        elems.set(index++, elem);
    }

    public E pop() {
        // Memory leak alert!!!
        // we should throw the element we get out of the list out of our list:
        E elem = elems.get(index--);
        elems.set(index, null);
        return elem;
    }
}

Threading memory leak example (happened to me once. Heavy object… 200 MB object…):


public class LightUpdater {
    private Thread updatingThread;

    public LightUpdater(final World world) {
        // Threads aren't really GC'ed. (how stupid would that be anyways?) =)
        // So this thread will linger around, even tough the LightUpdater isn't needed anymore...
        // And additionally, the Thread now references the 'world' instance, so the world doesn't
        // get GC'ed.
        // Bad luck =)
        updatingThread = new Thread(new Runnable() {
            public void run() {
                // update light from world
                updateLight(world);
            }
        }).start();
    }
}

Here is my png loader, which uses libpng:


/*
 * TextureLoader.cpp
 *
 *  Created on: 10.02.2012
 *      Author: matheusdev
 */

#include <iostream>
#include <GL/gl.h>
#include <string.h>
#include <png.h>
#include <zlib.h>
#include "Texture.h"
#include "TextureLoader.h"

using namespace std;

TextureLoader::TextureLoader() {
	for (int i = 0; i < TEX_MAX_VAL; i++) {
		textures[i] = NULL;
	}
	loadTextures();
}

TextureLoader::~TextureLoader() {
	for (int i = 0; i < TEX_MAX_VAL; i++) {
		if (textures[i] != NULL) {
			textures[i]->~Texture();
			delete textures[i];
		}
	}
}

void TextureLoader::loadTextures() {
	textures[AWESOMEFACE_RECT] = loadTexture
			("resources/images/awesomeface_rect.png", 64, 64, AWESOMEFACE_RECT, false);
	textures[AWESOMEFACE_ROUND] = loadTexture
			("resources/images/awesomeface_round.png", 256, 256, AWESOMEFACE_ROUND, true);
}

Texture* TextureLoader::loadTexture
		(const string filename, int width, int height, unsigned int id, bool linear) {
	//header for testing if it is a png
	png_byte header[8];

	//open file as binary
	FILE *fp = fopen(filename.c_str(), "rb");
	if (!fp) {
		fprintf(stderr, "Failed to open File via fopen: %s\n", filename.c_str());
		return NULL;
	}

	//read the header
	fread(header, 1, 8, fp);

	//test if png
	int is_png = !png_sig_cmp(header, 0, 8);
	if (!is_png) {
		fclose(fp);
		return NULL;
	}

	//create png struct
	png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
			NULL, NULL);
	if (!png_ptr) {
		fclose(fp);
		fprintf(stderr, "Could not create png struct from %s\n", filename.c_str());
		return (NULL);
	}

	//create png info struct
	png_infop info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr) {
		png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
		fclose(fp);
		fprintf(stderr, "Could not get png_info out of %s\n", filename.c_str());
		return (NULL);
	}

	//create png info struct
	png_infop end_info = png_create_info_struct(png_ptr);
	if (!end_info) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
		fclose(fp);
		fprintf(stderr, "Could not get the png's end_info from %s\n", filename.c_str());
		return (NULL);
	}

	//png error stuff, not sure libpng man suggests this.
	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		fclose(fp);
		fprintf(stderr, "Failed to init pngio from %s\n", filename.c_str());
		return (NULL);
	}

	//init png reading
	png_init_io(png_ptr, fp);

	//let libpng know you already read the first 8 bytes
	png_set_sig_bytes(png_ptr, 8);

	// read all the info up to the image data
	png_read_info(png_ptr, info_ptr);

	//variables to pass to get info
	int bit_depth, color_type;
	png_uint_32 twidth, theight;

	// get info about png
	png_get_IHDR(png_ptr, info_ptr, &twidth, &theight, &bit_depth, &color_type,
			NULL, NULL, NULL);

	//update width and height based on png info
	width = twidth;
	height = theight;

	// Update the png info struct.
	png_read_update_info(png_ptr, info_ptr);

	// Row size in bytes.
	int rowbytes = png_get_rowbytes(png_ptr, info_ptr);

	// Allocate the image_data as a big block, to be given to opengl
	png_byte *image_data = new png_byte[rowbytes * height];

	if (!image_data) {
		//clean up memory and close stuff
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		fclose(fp);
		return NULL;
	}

	// row_pointers is for pointing to image_data for reading the png with libpng
	png_bytep *row_pointers = new png_bytep[height];
	if (!row_pointers) {
		//clean up memory and close stuff
		png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
		delete[] image_data;
		fclose(fp);
		return NULL;
	}
	// set the individual row_pointers to point at the correct offsets of image_data
	for (int i = 0; i < height; ++i)
		row_pointers[height - 1 - i] = image_data + i * rowbytes;

	// read the png into image_data through row_pointers
	png_read_image(png_ptr, row_pointers);

	// Now generate the OpenGL texture object
	Texture *tex = new Texture(id, GL_TEXTURE_2D);
	glGenTextures(1, &tex->texID);
	glBindTexture(GL_TEXTURE_2D, tex->texID);
	if (linear) {
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	} else {
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	}
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA,
			GL_UNSIGNED_BYTE, (GLvoid*) image_data);
	int error = glGetError();
	if (error != GL_NO_ERROR) {
		fprintf(stderr, "Got an OpenGL-Error after binding Texture: %i\n", error);
		fprintf(stderr, "%i\n", 0x0502);
	}

	// clean up memory and close stuff
	png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
	delete[] image_data;
	delete[] row_pointers;
	fclose(fp);

	return tex;
}

But enough incredibly ugly code for now.
C++ isn’t where you want to go, believe me. It won’t be worth it. Going one language level back isn’t getting you anywhere.

Thanks for that,

I don’t believe it is one language back, like I said, I’ve been coding in C++ for 16 years, mostly on windows platforms and embedded systems.

Both C++ and java have there place and for games development, C++ is suited.

I’ve used Java for around 8 years, mainly for back end server code (JSP, Servlets, EJB’s, Struts, Spring) but not much for gaming, in fact, the voxel engine I was doing is my first attempt at using Java for gaming.

Texture loader - this is what I’ve ended up using, looks cool:

http://www.lonesock.net/soil.html

Anyway, I’ve ported frustum culling, camera, game loop, skybox, vector3f over, just a little matter of actually rendering something :wink: - should I go straight with shaders or first draw something with the fixed pipeline?!

Thanks

Update with how my port going to C++ - well, must admit, wishing hadn’t bothered, lol. Just wasted
a load of time of time I don’t really have!

I use to enjoy coding in C++, but I guess since using java for now over 8 years, I’m enjoying it a lot more.

Lesson learned, time to get back to my vox project with Java.

Would I be wise to switch to the programmable pipeline and use shaders as opposed to fixed pipeline?
It seems a lot of people doing the voxel engines on here are using fixed pipeline.

Thanks,
Steve

I think it’s a good idea to use the programmable pipeline.
Just don’t forget to make some sort of fallback for the systems that don’t support shaders.

Have a nice day!

  • Longor1996

Update with how my port going to C++ - well, must admit, wishing hadn’t bothered, lol. Just wasted
a load of time of time I don’t really have!

I use to enjoy coding in C++, but I guess since using java for now over 8 years, I’m enjoying it a lot more.

Lesson learned, time to get back to my vox project with Java.

Would I be wise to switch to the programmable pipeline and use shaders as opposed to fixed pipeline?
It seems a lot of people doing the voxel engines on here are using fixed pipeline.

Thanks,
Steve

I think it’s a good idea to use the programmable pipeline.
Just don’t forget to make some sort of fallback for the systems that don’t support shaders.

Have a nice day!

  • Longor1996

Thanks for your advice,

How difficult a task is it to switch to using shaders as opposed to fixed pipeline?
Such as transformations, camera system, object placement, lighting.

Programmable pipeline I believe was introduced in OpenGL3.0 - is this correct? Would not pretty
much everybody have this support on their GFX card now?

I do a lot of mobile dev work although not done any opengl on it, but that uses the programmable pipeline so if porting to say android, using programmable pipeline seems the way to go?

Programmable pipeline is pretty much supported everywhere: see here. Keep in mind shaders became core in GL 2.0.

GL 3.0+ (and thus GLSL that uses in/out, etc) is not as widely supported. This is why I would recommend GL 2.0+ as your target. You can see my code and tutorials are all compatible with GL 2.0, but use the programmable pipeline and do away with (most) deprecated techniques.

Shaders are not difficult to learn. The matrix/vector math might be tricky, but it’s not necessary to understand it very deeply as long as you have a nice utility library like LWJGL or LibGDX. Lighting is a little more difficult but there is so much on the web that you should be able to pick it up relatively quickly.

If you ever hope to target Android or iOS you should definitely learn the programmable pipeline.

Further; I would suggest LibGDX regardless of wether you plan to support mobile. This will give you a lot of control over GL (as with LWJGL), but will also give you a lot of extra features (like vector math, image decoding, 3D model loading, a powerful GUI toolkit, freetype font rendering, VBO/mesh utilities, etc). It handles all the crappy Android/iOS specific stuff for you (like audio, managing context loss, compressed textures, etc).

Thanks for your advice,

How difficult a task is it to switch to using shaders as opposed to fixed pipeline?
Such as transformations, camera system, object placement, lighting.

Programmable pipeline I believe was introduced in OpenGL3.0 - is this correct? Would not pretty
much everybody have this support on their GFX card now?

I do a lot of mobile dev work although not done any opengl on it, but that uses the programmable pipeline so if porting to say android, using programmable pipeline seems the way to go?

Programmable pipeline is pretty much supported everywhere: see here. Keep in mind shaders became core in GL 2.0.

GL 3.0+ (and thus GLSL that uses in/out, etc) is not as widely supported. This is why I would recommend GL 2.0+ as your target. You can see my code and tutorials are all compatible with GL 2.0, but use the programmable pipeline and do away with (most) deprecated techniques.

Shaders are not difficult to learn. The matrix/vector math might be tricky, but it’s not necessary to understand it very deeply as long as you have a nice utility library like LWJGL or LibGDX. Lighting is a little more difficult but there is so much on the web that you should be able to pick it up relatively quickly.

If you ever hope to target Android or iOS you should definitely learn the programmable pipeline.

Further; I would suggest LibGDX regardless of wether you plan to support mobile. This will give you a lot of control over GL (as with LWJGL), but will also give you a lot of extra features (like vector math, image decoding, 3D model loading, a powerful GUI toolkit, freetype font rendering, VBO/mesh utilities, etc). It handles all the crappy Android/iOS specific stuff for you (like audio, managing context loss, compressed textures, etc).

Many thanks @davedes, will certainly look at your tutorials.

I have used LibGdx in the past when doing an Android game, although didn’t go that low level with it.

I like LWJGL, it makes setting stuff up a lot simpler and a lot less tedious.

Thanks again,
Steve

Many thanks @davedes, will certainly look at your tutorials.

I have used LibGdx in the past when doing an Android game, although didn’t go that low level with it.

I like LWJGL, it makes setting stuff up a lot simpler and a lot less tedious.

Thanks again,
Steve