Ok, first post. Ive tried to avoid asking for help when i've had problems before and usually managed to solve things on my own but on this, i'm just going round in circles.

I'm trying to teach myself basic directx9 and so far I made a program that takes a .3ds file, extracts only the info I need, stores it in binary to a .sd0 file (my own making but similiar to the .3ds format), and then i made this program, which just tries to extract the info from the .sd0 and load it into a vertex and index buffer for display. I'm not dealing with textures just yet, just the vertex/face data.

The first exception hits on the DrawIndexedPrimitive line, but from what Ive been able to learn i'm overflowing much earlier than that. I just can't find out where. I've tried to do it as a simple DrawPrimitive without indices so i'm assuming it's the vertex data but even so. I did notice that the memcpy was having programs when a vertex in the binary file was of value 0.00f. It was copying across that way in the original converter. I still havent been able to find out why but did put in a really lame hack to get around it (not asking for help on that one, i'll figure it out on my own.

Anyway, i'll post all the code, and yes, i'm a new learner so total apologises if my code makes you want to reach through the screen and throttle me.

sdImport.h

#ifndef _SDIMPORT_H_
#define _SDIMPORT_H_
#define _CRT_SECURE_NO_DEPRECATE_

#include <string>
#include <iostream>
#include <fstream>
#include <Windows.h>

typedef struct chunk
{
    unsigned short ID;
    long size;
} chunk;

typedef struct vertex
{
    float x, y, z;
    DWORD color;
} vertex;

typedef struct face
{
    unsigned short p1, p2, p3;
} face;

typedef struct uvcoord
{
    float u, v;
} uvcoord;

typedef struct texTri
{
    float x, y, z;
    float u, v;
}texTri;

class sdObj
{
public:
    sdObj();
    ~sdObj();
    unsigned char load(std::string const &filename);
    chunk getChunkInfo(int offset, unsigned char *data);
    void testvert();


    bool scan(unsigned char *data);
    int nVerts;
    int nFace;
    long filesize;
    std::string gObjName;
    int objNameSize;
    unsigned char *objData;

    vertex *vert;
    face *facelist;
    short *faceload;
    vertex *vertconv;

protected:
    enum
    {
        CHUNK_MAIN = 0x4D4D,
        CHUNK_OBJ = 0x4D4D,
        CHUNK_TRI = 0x3d3d,
        CHUNK_VERTEX = 0x4110,
        CHUNK_FACELIST = 0x4120,
        CHUNK_FACEDESC = 0x4130,
        CHUNK_UVCOORDLIST = 0x4140,
        CHUNK_SMOOTHGROUP = 0x4150,

        CHUNK_MAT = 0xAFFF,
        CHUNK_MATNAME = 0xA000,
        CHUNK_MATFILENAME = 0xA300
    };
};

#endif

sdImport.cpp

#include <string>
#include <fstream>
#include <vector>
#include <d3d9.h>
#include <d3dx9.h>
#include <sstream>
#include "sdImport.h"
using namespace std;

sdObj::sdObj()
{
    objData = NULL;
    filesize = 0;
    vert = NULL;
    //face = NULL;
    facelist = NULL;
    faceload = NULL;
}

sdObj::~sdObj()
{
    if(objData != NULL)
    {
        delete[] objData;
        objData = NULL;
    }
}

unsigned char sdObj::load(string const &filename)
{
    unsigned char *funcObjData = NULL;

    ifstream infile(filename.c_str(), ios::binary | ios::in);
    if(infile.is_open())
    {
        infile.seekg(0, ios::end);
        filesize = (long)infile.tellg();
        infile.seekg(0, ios::beg);

        if(funcObjData != NULL)
        {
            delete[] funcObjData;
            funcObjData = NULL;
        }
        funcObjData = new unsigned char[filesize];

        infile.read((char*)funcObjData, filesize);
        infile.close();

        if(infile.is_open())
            return false;
    }

    scan(funcObjData);

    return *funcObjData;
}

chunk sdObj::getChunkInfo(int offset, unsigned char *data)
{
    chunk tc;
    memcpy(&tc.ID, &data[offset], 2);
    memcpy(&tc.size, &data[offset+2], 4);

    return tc;
}

bool sdObj::scan(unsigned char *data)
{
    chunk info;
    int offset = 0;
    memcpy(&info.ID, &data[offset], 2);
    memcpy(&info.size, &data[offset+2], 4);
    if(info.ID != CHUNK_OBJ)
        return false;
    if(info.size != filesize)
        return false;

    //offset = 6;

    while (offset < filesize)
    {
        info = getChunkInfo(offset, data);

        switch(info.ID)
        {
            case CHUNK_OBJ:
            {
                unsigned char* objname;
                objname = new unsigned char;

                int nameoff = offset + 6;
                char c = 0;         
                string name;

                do 
                {
                    memcpy (&c, &data[nameoff] , 1);
                    name += c;
                    nameoff++;
                }
                while(c != 0x00);

                offset += nameoff;
                break;
            }
            case CHUNK_TRI:
            {
                offset += 6;
                break;
            }
            case CHUNK_VERTEX:
            {
                short nVert;
                int vertoff = offset + 6;

                memcpy (&nVert, &data[vertoff], 2);

                vertoff += 2;
                int vertplus = sizeof(float);

                vert = new vertex[nVert];

                    for(int i = 0; i < nVert; i++)
                    {
                        memcpy(&vert[i].x, 
                               &data[vertoff], 
                               sizeof(float));
                        vertoff += vertplus;

                        memcpy(&vert[i].y, 
                               &data[vertoff], 
                               sizeof(float));
                        vertoff += vertplus;

                        memcpy(&vert[i].z, 
                               &data[vertoff], 
                               sizeof(float));
                        vertoff += vertplus;

                        vert[i].color = D3DCOLOR_XRGB(0, 255, 0);
                    }

                    nVerts = nVert;

                    testvert();

                offset = vertoff;
                break;
            }
            case CHUNK_FACELIST:
            {
                short nFaces;
                int faceoff = offset + 6;
                short faceinfo = 0;

                int faceplus = sizeof(unsigned short);

                memcpy(&nFaces, &data[faceoff], 2);
                faceoff += 2;

                facelist = new face[nFaces];

                nFace = nFaces;
                unsigned short facecheck = 0;

                faceload = new short[nFaces];

                for(int i = 0; i < nFaces; i++)
                {
                    memcpy(&facelist[i].p1, 
                           &data[faceoff], 
                           sizeof(unsigned short));
                    faceload[facecheck] = facelist[i].p1;
                    faceoff += sizeof(unsigned short);

                    facecheck++;

                    memcpy(&facelist[i].p2, 
                           &data[faceoff], 
                           sizeof(unsigned short));
                    faceload[facecheck] = facelist[i].p2;
                    faceoff += sizeof(unsigned short);

                    facecheck++;

                    memcpy(&facelist[i].p3, 
                           &data[faceoff], 
                           sizeof(unsigned short));
                    faceload[facecheck] = facelist[i].p3;
                    faceoff += sizeof(unsigned short);

                    facecheck++;

                    faceoff += sizeof(short);
                }

                offset = faceoff;
                break;
            }
            case CHUNK_FACEDESC:
            {
                offset += info.size;
                break;
            }
            case CHUNK_UVCOORDLIST:
            {
                offset += info.size;
                break;
            }
            case CHUNK_MAT:
            {
                offset += 6;
                break;
            }
            case CHUNK_MATNAME:
            {
                offset += info.size;
                break;
            }
            case CHUNK_MATFILENAME:
            {
                offset += info.size;
                break;
            }
            default:
            {
                offset += info.size;
                break;
            }
        }
    }
    return true;
}

void sdObj::testvert()
{
        stringstream ss (stringstream::in | stringstream::out);

        string check;
        for(int i=0; i < nVerts; i++)
        {
            ss << vert[i].x;
            check = ss.str();

            string::size_type pos = check.find("e");

            if (string::npos != pos)
            {
                vert[i].x = 0.00f;
            }

            ss << vert[i].y;
            check = ss.str();

            pos = check.find("e");

            if (string::npos != pos)
            {
                vert[i].y = 0.00f;
            }

            ss << vert[i].z;
            check = ss.str();

            pos = check.find("e");

            if (string::npos != pos)
            {
                vert[i].z = 0.00f;
            }
        }
}

dxInit.h

#ifndef _DX_INIT_H_
#define _DX_INIT_H_

#include <d3d9.h>
#include <d3dx9.h>
#include "sdImport.h"

#define CUSTOM_FVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)

class dxInit
{
public:

    dxInit();
    ~dxInit();
    bool setDev(int width, int height, HWND hwnd, bool bFullscreen);
    bool render();
    bool setVBuffer();
    bool setIBuffer();

    bool setViewMatrix();
    bool setProjectionMatrix();
    bool setWorldMatrix();

    sdObj sd;

private:

    LPDIRECT3D9 pD3D;
    LPDIRECT3DDEVICE9 pDevice;
    LPDIRECT3DVERTEXBUFFER9 pVBuffer;
    LPDIRECT3DINDEXBUFFER9 pIBuffer;

    int dxScreenW, dxScreenH;
};

#endif

dxImport.cpp

#include <d3d9.h>
#include <d3dx9.h>
#include <string>
#include "dxInit.h"
#include "sdImport.h"


using namespace std;

#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")

dxInit::dxInit()
{
    pD3D = NULL;
    pDevice = NULL;
    pVBuffer = NULL;
    pIBuffer = NULL;
}

dxInit::~dxInit()
{
    pIBuffer->Release();
    pVBuffer->Release();
    pDevice->Release();
    pD3D->Release();
}

bool dxInit::setDev(int width, int height, HWND hwnd, bool bFullscreen)
{

    dxScreenW = width;
    dxScreenH = height;


    pD3D = Direct3DCreate9(D3D_SDK_VERSION);

    D3DPRESENT_PARAMETERS pD3Dpp;

    ZeroMemory(&pD3Dpp, sizeof(pD3Dpp));

    pD3Dpp.Windowed = !bFullscreen;
    pD3Dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    pD3Dpp.hDeviceWindow = hwnd;
    pD3Dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    pD3Dpp.BackBufferWidth = dxScreenW;
    pD3Dpp.BackBufferHeight = dxScreenH;
    pD3Dpp.EnableAutoDepthStencil = TRUE;
    pD3Dpp.AutoDepthStencilFormat = D3DFMT_D16;

    if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT,
                                 D3DDEVTYPE_HAL,
                                 hwnd,
                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                 &pD3Dpp,
                                 &pDevice)))
    {
        return false;
    }

    setVBuffer();
    setIBuffer();

    pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
    pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
    pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

    return true;
}

bool dxInit::render()
{
    if(FAILED(pDevice->Clear(0, 
                             NULL, 
                             D3DCLEAR_TARGET, 
                             D3DCOLOR_XRGB(0, 0, 0), 
                             1.0f, 
                             0)))
        return false;

    if(FAILED(pDevice->Clear(0, 
                             NULL, 
                             D3DCLEAR_ZBUFFER, 
                             D3DCOLOR_XRGB(0, 0, 0), 
                             1.0f, 
                             0)))
        return false;

    pDevice->SetFVF(CUSTOM_FVF);

    setViewMatrix();
    setProjectionMatrix();
    setWorldMatrix();

    if(FAILED(pDevice->SetStreamSource(0, pVBuffer, 0, sizeof(vertex))))
        return false;

    if(FAILED(pDevice->SetIndices(pIBuffer)))
        return false;

    if(FAILED(pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, sd.nVerts, 0, sd.nFace)))
        return false;

    pDevice->BeginScene();
    pDevice->EndScene();
    pDevice->Present(NULL, NULL, NULL, NULL);

    return true;
}

bool dxInit::setVBuffer()
{
    if(FAILED(pDevice->CreateVertexBuffer(sd.nVerts * sizeof(vertex),
                                          D3DUSAGE_WRITEONLY,
                                          CUSTOM_FVF,
                                          D3DPOOL_MANAGED,
                                          &pVBuffer,
                                          NULL)))
        return false;

    void *pvoid;

    if(FAILED(pVBuffer->Lock(0,0, (void**)&pvoid, 0)))
        return false;

    memcpy(pvoid, sd.vert, sizeof(sd.vert));

    if(FAILED(pVBuffer->Unlock()))
        return false;

    return true;
}

bool dxInit::setIBuffer()
{
    if(FAILED(pDevice->CreateIndexBuffer(sd.nFace * sizeof(short),
                                         0,
                                         D3DFMT_INDEX16,
                                         D3DPOOL_MANAGED,
                                         &pIBuffer,
                                         NULL)))
        return false;

    void *pvoid;

    if(FAILED(pIBuffer->Lock(0,0, (void**)&pvoid, 0)))
        return false;

    memcpy(pvoid, sd.faceload, sizeof(sd.faceload));

    if(FAILED(pIBuffer->Unlock()))
        return false;

    return true;
}

bool dxInit::setViewMatrix()
{
    D3DXMATRIX matView;
    D3DXMatrixLookAtLH(&matView, 
                       &D3DXVECTOR3(0.0f, 8.0f, 60.0f),  //camera
                       &D3DXVECTOR3(0.0f, 0.0f, 0.0f),   // look at
                       &D3DXVECTOR3(0.0f, 1.0f, 0.0f));  // up direction
    if(FAILED(pDevice->SetTransform(D3DTS_VIEW, &matView)))
        return false;

    return true;
}

bool dxInit::setProjectionMatrix()
{
    D3DXMATRIX matProjection;
    D3DXMatrixPerspectiveFovLH(&matProjection,
                               D3DXToRadian(45),
                               (float)dxScreenW / (float)dxScreenH,
                               1.0f,
                               100.0f);
    if(FAILED(pDevice->SetTransform(D3DTS_PROJECTION, &matProjection)))
        return false;

    return true;
}

bool dxInit::setWorldMatrix()
{
    static float index = 0.0f;
    D3DXMATRIX matRotateY;
    D3DXMatrixRotationY(&matRotateY, index);
    if(FAILED(pDevice->SetTransform(D3DTS_WORLD, &(matRotateY))))
        return false;

    return true;
}

I didn't post the winclude.h/cpp files, as I can't see how they're relevant, but if you need them let me know.

Also, the .sd0 format i made is kinda lame, very similar to the .3ds format.
Works in chunks. 2 bytes for chunk code, 4 for size of chunk. Then any data within that chunk.

4D4D is the main obj chunk (one obj per file), followed by size of file and the object name (null terminated string)
3D3D is the trimesh subchunk of obj. only contains subchunks.
Then 4110, 4120, 4130 and 4140 are the vertex, face, face description and uv coordinate subchunks of tri.

AFFF is a material subchunk of obj, contains only subchunks.
A000, and A300 are the material name and material filename subchunks of mat.

The errors produced are:
First-chance exception at 0x7c812afb in DX3DImport.exe: Microsoft C++ exception: long at memory location 0x0012faa0
HEAP[DragDrapTest.exe]: Invalid Address specified to RtlValidateHeap( 00360000, 00366BC0 )

Finally and I can't iterate this enough, my code is so sloppy i'm a little embarressed to be presenting it, but to learn, I must accept that I am crap and move on from there.

Any help you can provide will be gratefully accepted.

edit - Just uploaded the .sd0 file incase you need it. - http://www.yunaco.com/dawnstar.sd0

DeanMSands3 commented: Holy crap! A new beginner who uses CODE tags! It's a miracle! Please stay! +4

Recommended Answers

All 9 Replies

Ive narrowed it down a little. I commented out all the sdImport.cpp code except the class constructor and deconstructor, and then set fixed code vertex and index data into the setVBuffer and setIBuffer functions and i'm still getting the first exceptions. So the problem has to be somewhere in dxInit.h/cpp.

This doesn't mean my sdImport doesn't have errors, it just means these are not the errors I am looking for. waves jedi hand

After further investigation, I realised I was running BeginScene() AFTER setting all the data, after fixing that, I am now getting the hardcoded model to display, but not the import.

Also, no matter which I use, it still crashes with a first exception when I close the window.

It points to this line in the file dbgdel.cpp -> _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));

I believe the problem is somewhere with the Lock() functions, but I still can't see where.

First of all, welcome to Daniweb!

Second, your code is not remotely as horrible as you say it is (I've seen a lot worse). It is pretty good overall, with a few issues to solve.

Ok, so, on to the issues:

1)
You have a memory leak in the load function. The function allocates an array of unsigned chars for dumping the file content into, before scanning it. That array is never deallocated. The load function really should have the type bool as output (you even have a return false; statement), and there is no point in returning an unsigned char. Also, because you have two exit points (one from an error, returning false, and one from reaching the end without errors), you would need to delete the array at both of these points. That is annoying to do, it is much easier to use an STL container instead to store the array, this way, it will automatically be cleaned up when you exit the function (from whichever exit-point). So, this corrected version would make more sense:

bool sdObj::load(string const &filename)  // return 'bool'
{
    //unsigned char *funcObjData = NULL;
    vector< unsigned char > funcObjData;  // use a vector container instead of array.

    ifstream infile(filename.c_str(), ios::binary | ios::in);

    if(!infile.is_open())
        return false;     // this is a fail, right?

    infile.seekg(0, ios::end);
    filesize = (long)infile.tellg();
    infile.seekg(0, ios::beg);

    /*if(funcObjData != NULL)
    {
        delete[] funcObjData;
        funcObjData = NULL;
    }*/ // This check is not useful because funcObjData is local.
        // Your compiler should have warned you that this if-statement
        //  would never execute because funcObjData was set to NULL at the 
        //  start of the function-body.

    //funcObjData = new unsigned char[filesize];
    funcObjData.resize(filesize);   // much nicer, isn't it?
    infile.read((char*)&funcObjData[0], filesize);  // notice &funcObjData[0] to get the pointer.
    infile.close();
    if(infile.is_open())
        return false;     // the vector container is automatically cleaned up.

    return scan(&funcObjData[0]);   // same here, &funcObjData[0] for pointer.
    // the vector container is automatically cleaned up.
}

2)
I would say that the function scan() really should be a private function because it only makes sense being called internally (by another member function, like it is done in the load() function). And so you should all your data members (all those pointers).

3)
You have memory leaks all over the place. Essentially, your sdObj class allocates a lot of dynamic memory, but never frees anything (except for objData, whose allocation I cannot find). Technically, all of these data members are actually pointers to arrays that you allocate somewhere in the scan() function. Those need to be deleted in the destructor. And, by the way, if a pointer is NULL, deleting it will have no effect, so you don't have to check that a pointer is not NULL before deleting it, you can just delete it. So, a more reasonable destructor would be this:

sdObj::~sdObj()
{
    delete[] objData;
    delete[] vert;
    delete[] facelist;
    delete[] faceload;
    delete[] vertconv;
}

However, since these are all arrays, you might as well use the same trick as I did in the load() function, and use STL containers instead, in particular, the std::vector class. Because the vector container is automatic (like all classes should be in C++), the memory that it points to will be automatically cleaned-up when your sdObj object is destroyed, so, you won't even need to define a destructor at all (all is automatic). So, you could define your data members as:

std::vector<unsigned char> objData;
std::vector<vertex> vert;
std::vector<face> facelist;
std::vector<short> faceload;
std::vector<vertex> vertconv;

And then, you use the same code as in my corrected load function to resize and fill in the data.

4)
Both classes, dxInit and sdObj, hold resources. The former holds pointers to these DirectX components. The latter holds pointers to dynamically allocated memory (unless you make the switch to vector containers, as recommended). And yet, you didn't define a copy-constructor or copy-assignment operator for any of them. This means that as soon as you copy or assign an object of either of these classes, you are doomed for a heap corruption problem down-the-line (when the second copy gets deleted or destroyed). Basically, you need to define these copy-constructor and copy-assignment operators. Look it up, or better yet, read my tutorial on resource-holding classes. The rule is generally simple, if you need a destructor (because you have resources to clean up), then you almost certainly also need a copy-constructor and copy-assignment operator (this is sometimes called the rule-of-three, but now, with the new C++ standard, it's really the rule of 5, or the Big Five (as in my tutorial)).

5)
There are problems in your code about misunderstanding what the sizeof() operator does. The sizeof operator only gives you the size of the type that it is given, or the size of the type of the variable that it is given. So, you have code like this:

memcpy(pvoid, sd.vert, sizeof(sd.vert));

Where, of course, I'm guessing that you think that sizeof(sd.vert) is going to give you the overall size of the chunk of memory that sd.vert points to. That's not the case. This expression will only give you the size of the pointer type (the type of sd.vert, which is vertex*), so, it is equivalent to sizeof(vertex*), which is really only going to be either 4 or 8 depending on your platform (32bit or 64bit). To get the actual size of the chunk of memory to copy, you need to use, in this case, the expression sd.nVerts * sizeof(vertex) (or, if you go for the switch to std::vector, then it would be sd.vert.size() * sizeof(vertex)).

I'm sure there are more issues, but I think this covers the main things, and I'm pretty sure that your bug will be solved if you implement the above recommendations. Other than that, the design is OK (not great, but OK, and, of course, when dealing with DirectX, you can't really work miracles either, because it is a rather unfortunately poorly designed library, and certainly not an example to follow when learning OOP).

Finally and I can't iterate this enough, my code is so sloppy i'm a little embarressed to be presenting it, but to learn, I must accept that I am crap and move on from there.

Don't be embarrassed. We're all on the same boat, strolling along the learning curve. One thing that you must learn pretty quickly is that as much as you might have progressed since you first started, there is always much more to learn ahead of you, and there are always people who know way more than you do. Learning to program is a very humbling experience, so you need to get rid of any pride or arrogance pretty early on, accept criticism and welcome it, and never assume that your solution is the best, always look around and ask around (on Daniweb, of course!).

This is hugely helpful thank you.
I've gone through and made the changes you recommend, but I would ask for some advice.
I did look through google (spent the last few hours trying to find the answer on my own), but no luck so far.

Previously I was extracting the vertex information from unsigned char *data via memcpy, but it doesn't like vector for some reason.

memcpy(&vert[i].x, &data[vertoff], sizeof(float));

vert is now defined (as you suggested) as: std::vector<vertex> vert;
and data is defined in the function specification as: bool scan( std::vector< unsigned char > data );

and yet when I step through my code in debug, it's always the first memcpy that breaks. Is there a specific way I should be using with vectors?
I looked at push and pop, aswell as swap, but I'm not sure if they're what i'm looking for. This is my first time using vectors. Heh, i guess it's 'pop'ing my cherry :p canned audience laughter

First of all, the scan() function should take the vector by reference, to avoid unnecessary copying. That is, as so:

bool scan( std::vector< unsigned char >& data );  // notice the '&' here.

If the memcpy "breaks" (would be useful to know what the error is!), it is most likely a problem of bounds. Did you use the resize() function before doing the memcpy, to make sure the vector has the needed size for the elements that you are copying into it. Also, when reading binary data from a file, you need to make sure the endianness is correct and that you use "fixed-size integer types". Types like short or int are not fixed in size (the size varies between platforms), you should use types in the header <stdint.h> which include types like int16_t or uint32_t, for 16-bit signed integers and 32-bit unsigned integers, respectively.

If I remember correctly, the 3ds file format has a "chunk-size" field, I hope that your file format has that too because it is very important. You should make sure to check that your mem-copies do not exceed the chunk-size, to make sure things are consistent all the time.

Thank you so much, all you help is amazing. I've got the scan function working properly, i've moved to fixed sizes as you suggested. And yes, my sd0 format does use a chunk id/chunk size system :)

Now ive just gotta figure out why it's bitching because the void pointer pvoid isn't initialized. I've yet to see an example of someone elses code where they do initialise it. Anyway, back to google. Learning curve ahoy! :p

Ok, well, I solved the void pointer problem, it had nothing to do with the pointer, instead, whenever I tried to pass in a value from the sd object it would corrupt the entire object. I have no idea how or why, it makes no sense. I got around it by simply passing off the data into a local variable/vector and using that instead.

Now i have an entirely different problem, and i've run outta ideas on what might be wrong. I'll use this thread seeing as it's the same program, might aswell keep it all in one place.

Basically, the program gives a first exception on the DrawIndexedPrimitive line, but i've run it though step by step in debug, and i really dont understand why I'm getting this specific error.

Anyway, the code.

sdImport.h

#ifndef _SDIMPORT_H_
#define _SDIMPORT_H_
#define _CRT_SECURE_NO_DEPRECATE_

#include <string>
#include <iostream>
#include <fstream>
#include <Windows.h>
#include <vector>
#include <stdint.h>

typedef struct chunk
{
    uint16_t ID;
    long size;
} chunk;

typedef struct vertex
{
    float x, y, z;
    DWORD color;
} vertex;

typedef struct face
{
    uint16_t p1, p2, p3;
} face;

typedef struct uvcoord
{
    float u, v;
} uvcoord;

typedef struct texTri
{
    float x, y, z;
    float u, v;
}texTri;

class sdObj
{
public:
    sdObj();
    ~sdObj();
    bool load( std::string const &filename );
    chunk getChunkInfo( int32_t offset, std::vector< uint8_t >& data );
    void testvert();

    bool scan( std::vector< uint8_t >& data );
    int32_t nVerts;
    int32_t nFace;
    long filesize;
    std::string gObjName;
    int32_t objNameSize;
    uint8_t *objData;

    std::vector< vertex > vert;
    std::vector< face > facelist;
    std::vector< int16_t > faceload;
    std::vector< vertex > vertconv;

protected:
    enum
    {
        CHUNK_MAIN = 0x4D4D,
        CHUNK_OBJ = 0x4D4D,
        CHUNK_TRI = 0x3d3d,
        CHUNK_VERTEX = 0x4110,
        CHUNK_FACELIST = 0x4120,
        CHUNK_FACEDESC = 0x4130,
        CHUNK_UVCOORDLIST = 0x4140,
        CHUNK_SMOOTHGROUP = 0x4150,

        CHUNK_MAT = 0xAFFF,
        CHUNK_MATNAME = 0xA000,
        CHUNK_MATFILENAME = 0xA300
    };
};

#endif

sdImport.cpp

#include <string>
#include <fstream>
#include <vector>
#include <d3d9.h>
#include <d3dx9.h>
#include <sstream>
#include <stdint.h>
#include "sdImport.h"
using namespace std;

sdObj::sdObj()
{

}

sdObj::~sdObj()
{

}

bool sdObj::load(string const &filename)
{
    vector <uint8_t> funcObjData;

    ifstream infile(filename.c_str(), ios::binary | ios::in);
    if(!infile.is_open())
        return false;

        infile.seekg(0, ios::end);
        filesize = (long)infile.tellg();
        infile.seekg(0, ios::beg);

        funcObjData.resize(filesize);

        infile.read((char*)&funcObjData[0], filesize);
        infile.close();

        if(infile.is_open())
            return false;

    return scan(funcObjData);
}

chunk sdObj::getChunkInfo(int32_t offset, vector< uint8_t >& data)
{
    chunk tc;
    memcpy(&tc.ID, &data[offset], 2);
    memcpy(&tc.size, &data[offset+2], 4);

    return tc;
}

bool sdObj::scan( vector< uint8_t >& data )
{
    chunk info;
    int offset = 0;
    memcpy(&info.ID, &data[offset], 2);
    memcpy(&info.size, &data[offset+2], 4);
    if(info.ID != CHUNK_OBJ)
        return false;
    if(info.size != filesize)
        return false;

    //offset = 6;

    while (offset < filesize)
    {
        info = getChunkInfo(offset, data);

        switch(info.ID)
        {
            case CHUNK_OBJ:
            {
                int32_t nameoff = offset + 6;
                int8_t c = 0;           
                string name;

                do 
                {
                    memcpy (&c, &data[nameoff] , 1);
                    name += c;
                    nameoff++;
                }
                while(c != 0x00);

                offset += nameoff;
                break;
            }
            case CHUNK_TRI:
            {
                offset += 6;
                break;
            }
            case CHUNK_VERTEX:
            {
                int16_t nVert;
                int32_t vertoff = offset + 6;

                memcpy (&nVert, &data[vertoff], 2);

                vertoff += 2;
                int32_t vertplus = sizeof(float);

                string veccopy;
                stringstream cs (stringstream::in | stringstream::out);
                vert.resize(nVert);

                    for(int32_t i = 0; i < nVert; i++)
                    {
                        memcpy(&vert[i].x, &data[vertoff], sizeof(float));
                        vertoff += vertplus;

                        memcpy(&vert[i].y, &data[vertoff], sizeof(float));
                        vertoff += vertplus;

                        memcpy(&vert[i].z, &data[vertoff], sizeof(float));
                        vertoff += vertplus;

                        vert[i].color = D3DCOLOR_XRGB(0, 255, 0);
                    }

                    nVerts = nVert;

                    testvert();

                offset = vertoff;
                break;
            }
            case CHUNK_FACELIST:
            {
                int16_t nFaces;
                int32_t faceoff = offset + 6;
                int16_t faceinfo = 0;

                int32_t faceplus = sizeof(unsigned short);

                memcpy(&nFaces, &data[faceoff], 2);
                faceoff += 2;

                nFace = nFaces;
                uint16_t facecheck = 0;

                facelist.resize(nFace);

                for(int32_t i = 0; i < nFaces; i++)
                {
                    memcpy(&facelist[i].p1, &data[faceoff], sizeof(unsigned short));
                    //faceload[facecheck] = facelist[i].p1;
                    faceoff += sizeof(unsigned short);

                    //facecheck++;

                    memcpy(&facelist[i].p2, &data[faceoff], sizeof(unsigned short));
                    //faceload[facecheck] = facelist[i].p2;
                    faceoff += sizeof(unsigned short);

                    //facecheck++;

                    memcpy(&facelist[i].p3, &data[faceoff], sizeof(unsigned short));
                    //faceload[facecheck] = facelist[i].p3;
                    faceoff += sizeof(unsigned short);

                    //facecheck++;

                    faceoff += sizeof(short);
                }

                offset = faceoff;
                break;
            }
            case CHUNK_FACEDESC:
            {
                offset += info.size;
                break;
            }
            case CHUNK_UVCOORDLIST:
            {
                offset += info.size;
                break;
            }
            case CHUNK_MAT:
            {
                offset += 6;
                break;
            }
            case CHUNK_MATNAME:
            {
                offset += info.size;
                break;
            }
            case CHUNK_MATFILENAME:
            {
                offset += info.size;
                break;
            }
            default:
            {
                offset += info.size;
                break;
            }
        }
    }
    return true;
}

void sdObj::testvert()
{
    string filename = "c:\\vertout.txt";
    ofstream outfile(filename.c_str(), ios::out | ios::ate);
    if(outfile.is_open())
    {
        stringstream ss (stringstream::in | stringstream::out);

        string check;
        for(int32_t i=0; i < nVerts; i++)
        {
            ss << vert[i].x;
            check = ss.str();

            string::size_type pos = check.find("e");

            if (string::npos != pos)
            {
                vert[i].x = 0.00f;
            }

            ss.clear();
            ss.str("");

            outfile << vert[i].x << " _ ";

            ss << vert[i].y;
            check = ss.str();

            pos = check.find("e");

            if (string::npos != pos)
            {
                vert[i].y = 0.00f;
            }

            ss.clear();
            ss.str("");

            outfile << vert[i].y << " _ ";

            ss << vert[i].z;
            check = ss.str();

            pos = check.find("e");

            if (string::npos != pos)
            {
                vert[i].z = 0.00f;
            }

            ss.clear();
            ss.str("");

            outfile << vert[i].z << " _ ";
            outfile << vert[i].color << "\n";
        }
    }
    outfile.close();
}

dxInit.h

#ifndef _DX_INIT_H_
#define _DX_INIT_H_

#include <d3d9.h>
#include <d3dx9.h>
#include <vector>
#include <stdint.h>
#include "sdImport.h"
#define _CRT_SECURE_NO_DEPRECATE_

class dxInit
{
public:

    dxInit();
    ~dxInit();
    bool setDev(int32_t width, int32_t height, HWND hwnd, bool bFullscreen);
    bool render();
    bool setVBuffer();
    bool setIBuffer();

    bool setViewMatrix();
    bool setProjectionMatrix();
    bool setWorldMatrix();

    sdObj sd;

private:

    LPDIRECT3D9 pD3D;
    LPDIRECT3DDEVICE9 pDevice;
    LPDIRECT3DVERTEXBUFFER9 pVBuffer;
    LPDIRECT3DINDEXBUFFER9 pIBuffer;

    std::vector< vertex > tempvert;
    std::vector< face > faceload;

    int32_t dxScreenW, dxScreenH;
};

#endif

dxInit.cpp

#include <d3d9.h>
#include <d3dx9.h>
#include <string>
#include <stdint.h>
#include "dxInit.h"
#include "sdImport.h"

using namespace std;

#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")

#define CUSTOM_FVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)

dxInit::dxInit()
{

}

dxInit::~dxInit()
{
    pIBuffer->Release();
    pVBuffer->Release();
    pDevice->Release();
    pD3D->Release();
}

bool dxInit::setDev(int32_t width, int32_t height, HWND hwnd, bool bFullscreen)
{

    dxScreenW = width;
    dxScreenH = height;

    pD3D = Direct3DCreate9(D3D_SDK_VERSION);

    D3DPRESENT_PARAMETERS pD3Dpp;

    ZeroMemory(&pD3Dpp, sizeof(pD3Dpp));

    pD3Dpp.Windowed = !bFullscreen;
    pD3Dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    pD3Dpp.hDeviceWindow = hwnd;
    pD3Dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    pD3Dpp.BackBufferWidth = dxScreenW;
    pD3Dpp.BackBufferHeight = dxScreenH;
    pD3Dpp.EnableAutoDepthStencil = TRUE;
    pD3Dpp.AutoDepthStencilFormat = D3DFMT_D16;

    if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT,
                                 D3DDEVTYPE_HAL,
                                 hwnd,
                                 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                 &pD3Dpp,
                                 &pDevice)))
    {
        return false;
    }

    setVBuffer();
    setIBuffer();

    pDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
    pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
    pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

    return true;
}

bool dxInit::render()
{
    if(FAILED(pDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0)))
        return false;

    if(FAILED(pDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0)))
        return false;

    pDevice->BeginScene();

    pDevice->SetFVF(CUSTOM_FVF);

    setViewMatrix();
    setProjectionMatrix();
    setWorldMatrix();

    if(FAILED(pDevice->SetStreamSource(0, pVBuffer, 0, sizeof(vertex))))
        return false;

    if(FAILED(pDevice->SetIndices(pIBuffer)))
        return false;

    int16_t tempvsize, tempfsize;

    tempvsize = sd.nVerts;
    tempfsize = sd.nFace;

    if(FAILED(pDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, tempvsize, 0, tempfsize)))
        return false;

    pDevice->EndScene();
    pDevice->Present(NULL, NULL, NULL, NULL);

    return true;
}

bool dxInit::setVBuffer()
{
    int32_t vertsize = sd.nVerts;
    if(FAILED(pDevice->CreateVertexBuffer(vertsize * sizeof(vertex),
                                          0,
                                          CUSTOM_FVF,
                                          D3DPOOL_MANAGED,
                                          &pVBuffer,
                                          NULL)))
        return false;

    void *pVoid;

    if(FAILED(pVBuffer->Lock(0, 0, (void**)&pVoid, 0)))
        return false;

    int32_t memcpysize = sd.vert.size() * sizeof(vertex);
    tempvert = sd.vert;

    memcpy(pVoid, &tempvert, memcpysize);


    if(FAILED(pVBuffer->Unlock()))
        return false;

    return true;
}

bool dxInit::setIBuffer()
{
    int32_t facesize = sd.nFace;
    if(FAILED(pDevice->CreateIndexBuffer(facesize * 3 * sizeof(face),
                                         0,
                                         D3DFMT_INDEX16,
                                         D3DPOOL_MANAGED,
                                         &pIBuffer,
                                         NULL)))
        return false;

    void *pvoid;

    if(FAILED(pIBuffer->Lock(0,0, (void**)&pvoid, 0)))
        return false;

    faceload = sd.facelist;

    memcpy(pvoid, &faceload, facesize * sizeof(face));

    if(FAILED(pIBuffer->Unlock()))
        return false;

    return true;
}

bool dxInit::setViewMatrix()
{
    D3DXMATRIX matView;
    D3DXMatrixLookAtLH(&matView, 
                       &D3DXVECTOR3(0.0f, 8.0f, 110.0f),  //camera
                       &D3DXVECTOR3(0.0f, 0.0f, 0.0f),   // look at
                       &D3DXVECTOR3(0.0f, 1.0f, 0.0f));  // up direction
    if(FAILED(pDevice->SetTransform(D3DTS_VIEW, &matView)))
        return false;

    return true;
}

bool dxInit::setProjectionMatrix()
{
    D3DXMATRIX matProjection;
    D3DXMatrixPerspectiveFovLH(&matProjection,
                               D3DXToRadian(45),
                               (float)dxScreenW / (float)dxScreenH,
                               1.0f,
                               1000.0f);
    if(FAILED(pDevice->SetTransform(D3DTS_PROJECTION, &matProjection)))
        return false;

    return true;
}

bool dxInit::setWorldMatrix()
{
    static float index = 0.0f;
    D3DXMATRIX matRotateY;
    D3DXMatrixRotationY(&matRotateY, index);
    if(FAILED(pDevice->SetTransform(D3DTS_WORLD, &(matRotateY))))
        return false;

    return true;
}

The error is as follows:

Direct3D9: (INFO) :HalDevice Driver Style 9

Direct3D9: (ERROR) :Invalid index in the index stream: 23784

First-chance exception at 0x7c812afb in DragDrapTest.exe: Microsoft C++ exception:
long at memory location 0x0012f9f8..
Direct3D9: (ERROR) :DrawIndexedPrimitive failed.

Thing is, there isn't an index of 23784.
The model has 42 vertices and 80 faces.

I really don't get where this problems coming from.
Im still using the test sd0 file linked in the first post.

Any help anyone can provide, even if it's just a pointer in the right direction, would be gratefully recieved.

What is more surprising is that it even makes it as far to DrawIndexedPrimitives.

Your code to initialize the VBuffer and IBuffer are completely wrong. The only reason why using this temporary vector "solved" the problem, it because it displaced the memory corruption problem to somewhere that didn't matter as much. That's the nasty thing with memory corruption problems, is that most of the time "fixes" only move the problem elsewhere.

In any case, here is exactly the code that you should use to initialize your VBuffer and IBuffer:

// Here is the VBuffer copying part, (after creating it):

void *pVoid;
if(FAILED(pVBuffer->Lock(0, 0, (void**)&pVoid, 0)))
    return false;

memcpy(pVoid, &(sd.vert[0]), sd.vert.size() * sizeof(vertex));


// Here is the IBuffer copying part, (after creating it):

void *pvoid;
if(FAILED(pIBuffer->Lock(0,0, (void**)&pvoid, 0)))
    return false;

memcpy(pvoid, &(sd.facelist[0]), sd.facelist.size() * sizeof(face));

Another alternative if the above gives you problems (it shouldn't), which is this:

// Here is the VBuffer copying part, (after creating it):

vertex *pVertex; 
if(FAILED(pVBuffer->Lock(0, 0, (void**)&pVertex, 0)))
    return false;

std::copy(sd.vert.begin(), sd.vert.end(), pVertex);  // needs: #include <algorithm>


// Here is the IBuffer copying part, (after creating it):

face *pFaces;
if(FAILED(pIBuffer->Lock(0,0, (void**)&pFaces, 0)))
    return false;

std::copy(sd.facelist.begin(), sd.facelist.end(), pFaces);  // needs: #include <algorithm>

The error that you got comes from the fact that the copying methods you used were so corrupt that they filled the pVBuffer and pIBuffer with junk garbage values. So, as soon as you call DrawIndexedPrimitives, it would use these garbage values and fail with an error.

commented: Clear and concise. Couldn't ask for a more helpful person. +0

Oh dear god thank you. I just got the sphere rendered for the first time, no bugs.
You've been absolutely amazing, thank you :)

Incidentally the first of the two options worked. Didn't try the second. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.