Search code examples
c++pointersbinaryfstreamshort

can't copy shorts into dynamic array C++


I've been trying to load a 3d model format into C++, but I'm having a problem with it. Everything goes okay except for the indicies array of shorts... When I try and load one model, the first 2 spaces in the array are incorret... if I load a second model; more of the shorts are wrong further into the model data...

Here is my header file:

#ifndef MODELDATA_H
#define MODELDATA_H

#include <GL/glu.h>
#include <string>

using namespace std;


class modelData
{
    public:
    modelData();
    virtual ~modelData();

    short m_vert_count;
    short m_ind_count;
    short m_tid;
    GLfloat *m_verts;
    GLfloat *m_tex;
    GLint *m_ind;

    void loadModel(string input);
    void draw();

    protected:
    private:
};

#endif // MODELDATA_H

And here is my cpp file:

#include "modelData.h"
#include <GL/glu.h>
#include <fstream>
#include <string.h>
#include <iostream>

using namespace std;

modelData::modelData()
{
    //ctor
    m_verts = NULL;
    m_tex = NULL;
    m_ind = NULL;
    m_ind_count = 0;
    m_vert_count = 0;
}

modelData::~modelData()
{
    //dtor
    delete[] m_verts;
    delete[] m_tex;
    delete[] m_ind;
    m_ind_count = 0;
    m_vert_count = 0;
}

void modelData::loadModel(string input)
{
    short temp;
    char *newInput = new char[input.size()+1];
    newInput[input.size()]=0;
    memcpy(newInput,input.c_str(),input.size());
    ifstream a_file( newInput,  ios::binary | ios::in );
    delete newInput;

    a_file.seekg( 0, ios::beg );
    if ( ! a_file.read( reinterpret_cast<char*>( & m_vert_count ), sizeof( short ) ) )
    {
        cout << "Error reading from file: can't attain vertex buffer size" << endl;
        return;
    }

    if ( ! a_file.read( reinterpret_cast<char*>( & m_ind_count ), sizeof( short ) ) )
    {
        cout << "Error reading from file: can't attain index buffer size" << endl;
        return;
    }

    m_verts = new GLfloat[m_vert_count];
    m_ind = new GLint[m_ind_count];
    m_tex = new GLfloat[m_vert_count];

    for (int i = 0; i < m_vert_count; i++)
    {
        if ( ! a_file.read( reinterpret_cast<char*>( & m_verts[i] ), sizeof( float ) ) )
        {
            cout << "Error reading from file: can't attain vertex buffer" << endl;
            return;
        }
    }

    for (int i = 0; i < ((m_vert_count)/3)*2; i++)
    {
        if ( ! a_file.read( reinterpret_cast<char*>( & m_tex[i] ), sizeof( float ) ) )
        {
            cout << "Error reading from file: can't attain texcoord buffer" << endl;
            return;
        }
    }
    for (int i = 0; i < m_ind_count; i++)
    {
        if ( ! a_file.read( reinterpret_cast<char*>( & m_ind[i] ), sizeof( short ) ) )
        {
            cout << "Error reading from file: can't attain index buffer" << endl;
            return;
        }
    }


    cout << m_vert_count << "   " << m_ind_count << endl;
    cout << "Model successfully loaded from " << input << "  ...Jolly good." << endl;

}

void modelData::draw()
{
    glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(3,GL_FLOAT,0,m_verts);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2,GL_FLOAT,0,m_tex);
    glDrawElements(GL_TRIANGLES,m_ind_count,GL_UNSIGNED_INT,m_ind);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);

}

I hope the code isn't too long or too messy, I just really don't know what's happening... as far as I can tell; m_verts[] and m_tex[] look like they get filled fine, but m_ind[] keeps having wrong numbers pop up every so often through the array... Am I allocating the Array incorrectly? Am I not cleaning up something I should of?

Oh, and I don't think this is causing the problem, but you'll notice I haven't added anything to hadle big or little endian conversion... this is because I'm using an intel machine which seems to always assume little endian and my android game engine uses little endian... so I don't think that's the problem...

Any help or suggestions would be great. Thanks for reading.


Solution

  • If I can see right, m_ind is typed as an array of GLints, but you're reading into it as if it was an array of shorts. On most platforms, this means the upper two bytes of the value are pretty much random.

    If your data stream actually contains shorts, this would be the safe way to read them:

    for (int i = 0; i < m_ind_count; i++)
    {
        short val;
        if ( ! a_file.read( reinterpret_cast<char*>( & val ), sizeof( short ) ) )
        {
            cout << "Error reading from file: can't attain index buffer" << endl;
            return;
        }
        m_ind[i] = val;
    }
    

    A few unrelated notes:

    o This:

    char *newInput = new char[input.size()+1];
    newInput[input.size()]=0;
    memcpy(newInput,input.c_str(),input.size());
    ifstream a_file( newInput,  ios::binary | ios::in );
    delete newInput;
    

    is just a really complicated way of saying this:

    ifstream a_file(input.c_str(), ios::binary | ios::in);
    

    o I strongly suggest using std::vector instead of manually dynamically allocating and deallocating your arrays.