0

Overview

I've been working on an OpenGL 3.3 rendering engine, the good news is that if i hard code values for objects they will render perfectly. The bad news is that when trying to load a .obj file i run into serious issues.

I use GLFW, GLM, and GLEW not that this matters, it just may help.

N.B. My .obj loader is based off of the one found here.

The Problem

When i run my code, simply i get the error:

Debug Assertion Failed!
Line: 1201
Expression: vector subscript out of range

HOW DO I FIX THIS?!

I have debugged the code and i know which lines are causing the error but on further digging i found that its trying to index a vector of subscript '0', so i tried to initialize some values to the container but the error persisted.

The Code

Here is all the code, please scroll down to see the specifics of it.

OBJLoader.cpp

bool OBJLoader::loadGLDataFromOBJ(){

    bool processed = false;
    while (true){

        char currentLine[128];
        int res = fscanf(file, "%s", currentLine);
        if (res == EOF){

            break;
        }

        if (strcmp(currentLine, "v") == 0){
            Vector3f vertex;
            fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
            raw_vPositions.push_back(vertex);
        }
        else if (strcmp(currentLine, "vt") == 0){
            Vector2f uv;
            fscanf(file, "%f %f\n", &uv.x, &uv.y);
            raw_vTextureCoords.push_back(uv);
        }
        else if (strcmp(currentLine, "vn") == 0){
            Vector3f normal;
            fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
            raw_vNormals.push_back(normal);
        }
        else if (strcmp(currentLine, "f") == 0){
            unsigned int vertexData1[3], vertexData2[3], vertexData3[3];
            int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n",
                &vertexData1[0], &vertexData1[0], &vertexData1[0],
                &vertexData2[1], &vertexData2[1], &vertexData2[1],
                &vertexData3[2], &vertexData3[2], &vertexData3[2]);
            if (matches != 9){
                printf("File can't be read by our simple parser : ( Try exporting with other options\n");
                return false;
            }

            if (!processed){
                gl_vTextureCoords.resize(raw_vPositions.size() * 2);
                gl_vNormals.resize(raw_vPositions.size() * 3);
                processed = true;
            }

            processVertex(vertexData1);
            processVertex(vertexData2);
            processVertex(vertexData3);
        }
    }

    gl_vPositions.resize(raw_vPositions.size() * 3);
    gl_vIndexBuffer.resize(indices.size());

    int vertexPointer = 0;
    for (int i = 0; i < raw_vPositions.size(); i++){
        gl_vPositions[vertexPointer++] = raw_vPositions[i].x;
        gl_vPositions[vertexPointer++] = raw_vPositions[i].y;
    }

    for (int j = 0; j < indices.size(); j++) gl_vIndexBuffer[j] = indices[j];

    return true;
}

void OBJLoader::processVertex(unsigned int vertexData[]){
    int currentVertexPointer = *(vertexData) - 1;
    indices.push_back(currentVertexPointer);

    Vector2f currentTexture = raw_vTextureCoords[*(vertexData+1) - 1];
    gl_vTextureCoords[currentVertexPointer * 2] = currentTexture.x;
    gl_vTextureCoords[currentVertexPointer * 2 + 1] = currentTexture.y;

    Vector3f currentNormal = raw_vNormals[*(vertexData + 2) - 1];
    gl_vNormals[currentVertexPointer * 3] = currentNormal.x;
    gl_vNormals[currentVertexPointer * 3 + 1] = currentNormal.y;
    gl_vNormals[currentVertexPointer * 3 + 2] = currentNormal.z;

}


bool OBJLoader::loadOBJFromFile(const char* filePath){
    file = fopen(filePath, "r");
    if (!file){
        printf("Impossible to open the file !\n");
        return false;
    }
    else{
        printf("File opened: %s", filePath);
    }
    return true;
}



std::vector<float> OBJLoader::getPositions(){
    return this->gl_vPositions;
}
std::vector<float> OBJLoader::getTextureCoords(){
    return this->gl_vTextureCoords;
}
std::vector<float> OBJLoader::getNormals(){
    return this->gl_vNormals;
}
std::vector<unsigned short> OBJLoader::getIndexData(){
    return this->gl_vIndexBuffer;
}

OBJLoader.h

#include "glm/glm.hpp"
#include <vector>

typedef glm::vec3 Vector3f;
typedef glm::vec2 Vector2f;

typedef std::vector<Vector3f> List_Vec3;
typedef std::vector<Vector2f> List_Vec2;
typedef std::vector<unsigned short> List_Int;

class OBJLoader{
private:
    //These will be populated and then outputted to the user.
    std::vector<unsigned short> gl_vIndexBuffer = std::vector<unsigned short>(10);
    std::vector<float> gl_vPositions = std::vector<float>(10);
    std::vector<float> gl_vTextureCoords = std::vector<float>(10);
    std::vector<float> gl_vNormals = std::vector<float>(10);

    //These come from the obj file.
    List_Int indices;
    List_Vec3 raw_vPositions;
    List_Vec2 raw_vTextureCoords;
    List_Vec3 raw_vNormals;

    FILE* file; //The file of the obj.

    //Private functions
    bool loadOBJFromFile(const char* filePath); //Populates the file.
    bool loadGLDataFromOBJ();

    void processVertex(unsigned int[]);

public:
    OBJLoader(){}; //The default constructor.

    bool loadGLDataFromFile(const char* filePath); //Returns true if data loaded.

    std::vector<float> getPositions();
    std::vector<float> getTextureCoords();
    std::vector<float> getNormals();
    std::vector<unsigned short> getIndexData();

};

Detail

Its this function that seems to be giving me grief:

void OBJLoader::processVertex(unsigned int vertexData[]){
    int currentVertexPointer = *(vertexData) - 1;
    indices.push_back(currentVertexPointer);

    Vector2f currentTexture = raw_vTextureCoords[*(vertexData+1) - 1];
    gl_vTextureCoords[currentVertexPointer * 2] = currentTexture.x;
    gl_vTextureCoords[currentVertexPointer * 2 + 1] = currentTexture.y;

    Vector3f currentNormal = raw_vNormals[*(vertexData + 2) - 1];
    gl_vNormals[currentVertexPointer * 3] = currentNormal.x;
    gl_vNormals[currentVertexPointer * 3 + 1] = currentNormal.y;
    gl_vNormals[currentVertexPointer * 3 + 2] = currentNormal.z;
}

And more specifically these lines:

gl_vTextureCoords[currentVertexPointer * 2] = currentTexture.x;
gl_vTextureCoords[currentVertexPointer * 2 + 1] = currentTexture.y;

gl_vNormals[currentVertexPointer * 3] = currentNormal.x;
gl_vNormals[currentVertexPointer * 3 + 1] = currentNormal.y;
gl_vNormals[currentVertexPointer * 3 + 2] = currentNormal.z;

For some reason if i keep stepping over the while loop it breaks on its first iteration, and on inspecting the value of the subscript, it equated to 0, so therefore it is calling something like:

gl_vTextureCoords[0] = currentTexture.x;
gl_vTextureCoords[1] = currentTexture.y;

Which in both theory and practice should exist. In class i defined that the vectors would be initialized with 10 empty values, and in the run when the loop has reached its 'f' values, it resizes the lists anyway so why is zero such a hard number?

genpfault
  • 51,148
  • 11
  • 85
  • 139

1 Answers1

1

The error is here

unsigned int vertexData1[3], vertexData2[3], vertexData3[3];
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n",
   &vertexData1[0], &vertexData1[0], &vertexData1[0],
   &vertexData2[1], &vertexData2[1], &vertexData2[1],
   &vertexData3[2], &vertexData3[2], &vertexData3[2]);

I am pretty sure you meant something like:

unsigned int vertexData1[3], vertexData2[3], vertexData3[3];
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n",
   &vertexData1[0], &vertexData1[1], &vertexData1[2],
   &vertexData2[0], &vertexData2[1], &vertexData2[2],
   &vertexData3[0], &vertexData3[1], &vertexData3[2]);

or maybe:

unsigned int vertexData1[3], vertexData2[3], vertexData3[3];
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n",
   &vertexData1[0], &vertexData2[0], &vertexData3[0],
   &vertexData1[1], &vertexData2[1], &vertexData3[1],
   &vertexData1[2], &vertexData3[2], &vertexData3[2]);

This is a good example of why old-school "C" style programming is a dying art -- it is far too easy to make simple mistakes with hard-to-diagnose consequences.

Wheezil
  • 3,157
  • 1
  • 23
  • 36
  • Okay, you were right thank you, this has solved the subscript error, but my object is not rendering properly and i'm pretty sure i have all the points loaded, the only change i have made to my code is replacing what you told me to with the 'first' example. Here is what my object looks like [link]http://imgur.com/HGCwTbo It should be looking something like this [link]http://imgur.com/Gjd75vx – Zandro Fargnoli Mar 18 '15 at 13:15
  • Looks like this shoild be another question – Wheezil Mar 20 '15 at 00:22