aboutsummaryrefslogtreecommitdiff
#include "shape.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "../util/util.h"

#define NUM_ARRAY_ELEMENTS(a) sizeof(a) / sizeof(*a)

shape_t* Shape_CreateFromRawData(vertex_t* vertices, GLsizeiptr vertexBufferSize,
                                 GLushort* indices, GLsizeiptr indexBufferSize)
{
    shape_t* shape = (shape_t*) malloc( sizeof(shape_t) );

    shape->num_indices = ( indexBufferSize / sizeof(GLushort) );

    glGenVertexArrays(1, &shape->vao);
    glGenBuffers(1, &shape->vbo);
    glGenBuffers(1, &shape->ebo);

    glBindVertexArray(shape->vao);

    glBindBuffer(GL_ARRAY_BUFFER, shape->vbo);
    glBufferData(GL_ARRAY_BUFFER, vertexBufferSize, vertices, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, shape->ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSize, indices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, position) );
    glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, color) );
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, texCoord) );
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (const void*)offsetof(vertex_t, normal) );

    glBindVertexArray(0);

    return shape;
}

shape_t* Shape_MakeCube()
{
    vertex_t data[] =
    {
        { {-1.0f, +1.0f, +1.0f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.0f, +1.0f, +0.0f} },
		{ {+1.0f, +1.0f, +1.0f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 1.0f}, {+0.0f, +1.0f, +0.0f} },
		{ {+1.0f, +1.0f, -1.0f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {1.0f, 1.0f}, {+0.0f, +1.0f, +0.0f} },
		{ {-1.0f, +1.0f, -1.0f}, {+1.0f, +1.0f, +1.0f, +1.0f}, {1.0f, 0.0f}, {+0.0f, +1.0f, +0.0f} },

		{ {-1.0f, +1.0f, -1.0f}, {+1.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.0f, +0.0f, -1.0f} },
		{ {+1.0f, +1.0f, -1.0f}, {+0.0f, +0.5f, +0.2f, +1.0f}, {0.0f, 1.0f}, {+0.0f, +0.0f, -1.0f} },
		{ {+1.0f, -1.0f, -1.0f}, {+0.8f, +0.6f, +0.4f, +1.0f}, {1.0f, 1.0f}, {+0.0f, +0.0f, -1.0f} },
		{ {-1.0f, -1.0f, -1.0f}, {+0.3f, +1.0f, +0.5f, +1.0f}, {1.0f, 0.0f}, {+0.0f, +0.0f, -1.0f} },

		{ {+1.0f, +1.0f, -1.0f}, {+0.2f, +0.5f, +0.2f, +1.0f}, {0.0f, 0.0f}, {+1.0f, +0.0f, +0.0f} },
		{ {+1.0f, +1.0f, +1.0f}, {+0.9f, +0.3f, +0.7f, +1.0f}, {0.0f, 1.0f}, {+1.0f, +0.0f, +0.0f} },
		{ {+1.0f, -1.0f, +1.0f}, {+0.3f, +0.7f, +0.5f, +1.0f}, {1.0f, 1.0f}, {+1.0f, +0.0f, +0.0f} },
		{ {+1.0f, -1.0f, -1.0f}, {+0.5f, +0.7f, +0.5f, +1.0f}, {1.0f, 0.0f}, {+1.0f, +0.0f, +0.0f} },

		{ {-1.0f, +1.0f, +1.0f}, {+0.7f, +0.8f, +0.2f, +1.0f}, {0.0f, 0.0f}, {-1.0f, +0.0f, +0.0f} },
		{ {-1.0f, +1.0f, -1.0f}, {+0.5f, +0.7f, +0.3f, +1.0f}, {0.0f, 1.0f}, {-1.0f, +0.0f, +0.0f} },
		{ {-1.0f, -1.0f, -1.0f}, {+0.4f, +0.7f, +0.7f, +1.0f}, {1.0f, 1.0f}, {-1.0f, +0.0f, +0.0f} },
		{ {-1.0f, -1.0f, +1.0f}, {+0.2f, +0.5f, +1.0f, +1.0f}, {1.0f, 0.0f}, {-1.0f, +0.0f, +0.0f} },

		{ {+1.0f, +1.0f, +1.0f}, {+0.6f, +1.0f, +0.7f, +1.0f}, {0.0f, 0.0f}, {+0.0f, +0.0f, +1.0f} },
		{ {-1.0f, +1.0f, +1.0f}, {+0.6f, +0.4f, +0.8f, +1.0f}, {0.0f, 1.0f}, {+0.0f, +0.0f, +1.0f} },
		{ {-1.0f, -1.0f, +1.0f}, {+0.2f, +0.8f, +0.7f, +1.0f}, {1.0f, 1.0f}, {+0.0f, +0.0f, +1.0f} },
		{ {+1.0f, -1.0f, +1.0f}, {+0.2f, +0.7f, +1.0f, +1.0f}, {1.0f, 0.0f}, {+0.0f, +0.0f, +1.0f} },

		{ {+1.0f, -1.0f, -1.0f}, {+0.8f, +0.3f, +0.7f, +1.0f}, {0.0f, 0.0f}, {+0.0f, -1.0f, +0.0f} },
		{ {-1.0f, -1.0f, -1.0f}, {+0.8f, +0.9f, +0.5f, +1.0f}, {0.0f, 1.0f}, {+0.0f, -1.0f, +0.0f} },
		{ {-1.0f, -1.0f, +1.0f}, {+0.5f, +0.8f, +0.5f, +1.0f}, {1.0f, 1.0f}, {+0.0f, -1.0f, +0.0f} },
        { {+1.0f, -1.0f, +1.0f}, {+0.9f, +1.0f, +0.2f, +1.0f}, {1.0f, 0.0f}, {+0.0f, -1.0f, +0.0f} },
    };

    GLushort indices[] =  {
        0,   1,  2,  0,  2,  3, // Top
		4,   5,  6,  4,  6,  7, // Front
		8,   9, 10,  8, 10, 11, // Right
		12, 13, 14, 12, 14, 15, // Left
		16, 17, 18, 16, 18, 19, // Back
		20, 22, 21, 20, 23, 22, // Bottom
    };

    GLsizeiptr vertexBufferSize = NUM_ARRAY_ELEMENTS(data) * sizeof(vertex_t);
    GLsizeiptr indexBufferSize = NUM_ARRAY_ELEMENTS(indices) * sizeof(GLushort);

    return Shape_CreateFromRawData(data, vertexBufferSize, indices, indexBufferSize);
}

shape_t* Shape_MakeArrow()
{
    vertex_t data[] =
	{
		// Top side of arrow head
		{ {+0.00f, +0.25f, -0.25f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +1.00f, +0.00f} },
		{ {+0.50f, +0.25f, -0.25f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +1.00f, +0.00f} },
		{ {+0.00f, +0.25f, -1.00f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +1.00f, +0.00f} },
		{ {-0.50f, +0.25f, -0.25f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +1.00f, +0.00f} },
		// Bottom side of arrow head
		{ {+0.00f, -0.25f, -0.25f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, -1.00f, +0.00f} },
		{ {+0.50f, -0.25f, -0.25f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, -1.00f, +0.00f} },
		{ {+0.00f, -0.25f, -1.00f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, -1.00f, +0.00f} },
		{ {-0.50f, -0.25f, -0.25f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, -1.00f, +0.00f} },
		// Right side of arrow tip
		{ {+0.50f, +0.25f, -0.25f}, {+0.6f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {0.83205032f, 0.00f, -0.55470026f} },
		{ {+0.00f, +0.25f, -1.00f}, {+0.6f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {0.83205032f, 0.00f, -0.55470026f} },
		{ {+0.00f, -0.25f, -1.00f}, {+0.6f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {0.83205032f, 0.00f, -0.55470026f} },
		{ {+0.50f, -0.25f, -0.25f}, {+0.6f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {0.83205032f, 0.00f, -0.55470026f} },
		// Left side of arrow tip
		{ {+0.00f, +0.25f, -1.00f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {-0.55708605f, 0.00f, -0.37139067f} },
		{ {-0.50f, +0.25f, -0.25f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {-0.55708605f, 0.00f, -0.37139067f} },
		{ {+0.00f, -0.25f, -1.00f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {-0.55708605f, 0.00f, -0.37139067f} },
		{ {-0.50f, -0.25f, -0.25f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {-0.55708605f, 0.00f, -0.37139067f} },
		// Back side of arrow tip
		{ {-0.50f, +0.25f, -0.25f}, {+0.5f, +0.5f, +0.5f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +0.00f, +1.00f} },
		{ {+0.50f, +0.25f, -0.25f}, {+0.5f, +0.5f, +0.5f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +0.00f, +1.00f} },
		{ {-0.50f, -0.25f, -0.25f}, {+0.5f, +0.5f, +0.5f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +0.00f, +1.00f} },
		{ {+0.50f, -0.25f, -0.25f}, {+0.5f, +0.5f, +0.5f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +0.00f, +1.00f} },
		// Top side of back of arrow
		{ {+0.25f, +0.25f, -0.25f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +1.00f, +0.00f} },
		{ {+0.25f, +0.25f, +1.00f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +1.00f, +0.00f} },
		{ {-0.25f, +0.25f, +1.00f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +1.00f, +0.00f} },
		{ {-0.25f, +0.25f, -0.25f}, {+1.0f, +0.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +1.00f, +0.00f} },
		// Bottom side of back of arrow
		{ {+0.25f, -0.25f, -0.25f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, -1.00f, +0.00f} },
		{ {+0.25f, -0.25f, +1.00f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, -1.00f, +0.00f} },
		{ {-0.25f, -0.25f, +1.00f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, -1.00f, +0.00f} },
		{ {-0.25f, -0.25f, -0.25f}, {+0.0f, +0.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.00f, -1.00f, +0.00f} },
		// Right side of back of arrow
		{ {+0.25f, +0.25f, -0.25f}, {+0.6f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+1.00f, +0.00f, +0.00f} },
		{ {+0.25f, -0.25f, -0.25f}, {+0.6f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+1.00f, +0.00f, +0.00f} },
		{ {+0.25f, -0.25f, +1.00f}, {+0.6f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+1.00f, +0.00f, +0.00f} },
		{ {+0.25f, +0.25f, +1.00f}, {+0.6f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {+1.00f, +0.00f, +0.00f} },
		// Left side of back of arrow
		{ {-0.25f, +0.25f, -0.25f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {-1.00f, +0.00f, +0.00f} },
		{ {-0.25f, -0.25f, -0.25f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {-1.00f, +0.00f, +0.00f} },
		{ {-0.25f, -0.25f, +1.00f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {-1.00f, +0.00f, +0.00f} },
		{ {-0.25f, +0.25f, +1.00f}, {+0.0f, +1.0f, +0.0f, +1.0f}, {0.0f, 0.0f}, {-1.00f, +0.00f, +0.00f} },
		// Back side of back of arrow
		{ {-0.25f, +0.25f, +1.00f}, {+0.5f, +0.5f, +0.5f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +0.00f, +1.00f} },
		{ {+0.25f, +0.25f, +1.00f}, {+0.5f, +0.5f, +0.5f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +0.00f, +1.00f} },
		{ {-0.25f, -0.25f, +1.00f}, {+0.5f, +0.5f, +0.5f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +0.00f, +1.00f} },
		{ {+0.25f, -0.25f, +1.00f}, {+0.5f, +0.5f, +0.5f, +1.0f}, {0.0f, 0.0f}, {+0.00f, +0.00f, +1.00f} },
	};

	GLushort indices[] = {
		0, 1, 2, // Top
		0, 2, 3,
		4, 6, 5, // Bottom
		4, 7, 6,
		8, 10, 9, // Right side of arrow tip
		8, 11, 10,
		12, 15, 13, // Left side of arrow tip
		12, 14, 15,
		16, 19, 17, // Back side of arrow tip
		16, 18, 19,
		20, 22, 21, // Top side of back of arrow
		20, 23, 22,
		24, 25, 26, // Bottom side of back of arrow
		24, 26, 27,
		28, 30, 29, // Right side of back of arrow
		28, 31, 30,
		32, 33, 34, // Left side of back of arrow
		32, 34, 35,
		36, 39, 37, // Back side of back of arrow
		36, 38, 39,
	};

    GLsizeiptr vertexBufferSize = NUM_ARRAY_ELEMENTS(data) * sizeof(vertex_t);
    GLsizeiptr indexBufferSize = NUM_ARRAY_ELEMENTS(indices) * sizeof(GLushort);

    return Shape_CreateFromRawData(data, vertexBufferSize, indices, indexBufferSize);
}

shape_t* Shape_MakeQuad()
{
    vertex_t data[] =
    {
        { {+1.0f, +1.0f, +0.0f}, {+1.0f, +1.0f, +1.0f, +1.0f}, {1.0f, 1.0f}, {+0.0f, +0.0f, +1.0f} },
        { {-1.0f, +1.0f, +0.0f}, {+1.0f, +1.0f, +1.0f, +1.0f}, {0.0f, 1.0f}, {+0.0f, +0.0f, +1.0f} },
        { {+1.0f, -1.0f, +0.0f}, {+1.0f, +1.0f, +1.0f, +1.0f}, {1.0f, 0.0f}, {+0.0f, +0.0f, +1.0f} },
        { {-1.0f, -1.0f, +0.0f}, {+1.0f, +1.0f, +1.0f, +1.0f}, {0.0f, 0.0f}, {+0.0f, +0.0f, +1.0f} },
    };

    GLushort indices[] =
    {
        0, 1, 2, 1, 3, 2
    };

    GLsizeiptr vertexBufferSize = NUM_ARRAY_ELEMENTS(data) * sizeof(vertex_t);
    GLsizeiptr indexBufferSize = NUM_ARRAY_ELEMENTS(indices) * sizeof(GLushort);

    return Shape_CreateFromRawData(data, vertexBufferSize, indices, indexBufferSize);
}

#define BUFFER_SIZE 128

shape_t* Shape_LoadOBJ(const char* path)
{
    vec3_t* vertices = NULL;
    vec2_t* textures = NULL;
    vec3_t* normals = NULL;

    vertex_t* data = NULL;
    GLushort* indices = NULL;

    unsigned int vertices_count = 0, textures_count = 0, normals_count = 0, index_pointer = 0, faces_count = 0;
    int count = 0;
    int texture[3], normal[3], verts[3];

    FILE* file = fopen(path, "r");
    if(file == NULL)
        Util_FatalError(".obj file could not be loaded!");

    char buffer[BUFFER_SIZE];
    while(!feof(file))
    {
        fgets(buffer, BUFFER_SIZE, file);
        switch(buffer[0])
        {
        case 'v':
            if(buffer[1] == 't') {
                textures = (vec2_t*) realloc(textures, sizeof(vec2_t) * (++textures_count) );
                count = sscanf(buffer, "vt %f %f\n", &textures[textures_count-1].x, &textures[textures_count-1].y);
                if(count != 2)
                    Util_FatalError("Bad texture coordinates on .obj file");
            } else if(buffer[1] == 'n') {
                normals = (vec3_t*) realloc(normals, sizeof(vec3_t) * (++normals_count) );
                count = sscanf(buffer, "vn %f %f %f\n", &normals[normals_count-1].x,
                               &normals[normals_count-1].y, &normals[normals_count-1].z);
                if(count != 3)
                    Util_FatalError("Bad normals data on .obj file");
            } else {
                vertices = (vec3_t*) realloc(vertices, sizeof(vec3_t) * (++vertices_count) );
                count = sscanf(buffer, "v %f %f %f\n", &vertices[vertices_count-1].x,
                               &vertices[vertices_count-1].y, &vertices[vertices_count-1].z);
                if(count != 3)
                    Util_FatalError("Bad vertices data on .obj file");
            }
            break;
        case 'f':
            data = (vertex_t*) realloc( data, sizeof(vertex_t) * (++faces_count * 3) );
            indices = (GLushort*) realloc( indices, sizeof(GLushort) * (++faces_count * 3) );

            count = sscanf(buffer, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
                   &verts[0], &texture[0], &normal[0], &verts[1], &texture[1], &normal[1],
                   &verts[2], &texture[2], &normal[2]);
            if(count != 9)
                Util_FatalError("Bad face data on .obj file");

            indices[index_pointer] = index_pointer;
            data[index_pointer].position = vertices[verts[0]-1];
            data[index_pointer].texCoord = textures[texture[0]-1];
            data[index_pointer++].normal = normals[normal[0]-1];

            indices[index_pointer] = index_pointer;
            data[index_pointer].position = vertices[verts[1]-1];
            data[index_pointer].texCoord = textures[texture[1]-1];
            data[index_pointer++].normal = normals[normal[1]-1];

            indices[index_pointer] = index_pointer;
            data[index_pointer].position = vertices[verts[2]-1];
            data[index_pointer].texCoord = textures[texture[2]-1];
            data[index_pointer++].normal = normals[normal[2]-1];

            break;
        default:
            break;
        }
    }

    free(vertices);
    free(normals);
    free(textures);
    fclose(file);

    /*Remember, each face contains 3 vertex -> (faces_count * 3)*/

    GLsizeiptr vertexBufferSize = faces_count * sizeof(vertex_t) * 3;
    GLsizeiptr indexBufferSize = faces_count * sizeof(GLushort) * 3;

    shape_t* shape = Shape_CreateFromRawData(data, vertexBufferSize, indices, indexBufferSize);

    free(data);
    free(indices);

    return shape;
}

void Shape_Free(shape_t* shape)
{
    if(shape)
    {
        glDeleteBuffers(1, &shape->vbo);
        glDeleteBuffers(1, &shape->ebo);
        glDeleteVertexArrays(1, &shape->vao);
        free(shape);
    }
}