Dynamically Allocated Vertex Arrays

Alright, well, i’m halfway through writing my .ase -> .dans file converter =P… Right now my program reads in Verticies, Faces, Face Normals, and Vert-Normals from an .ase file. Now what i want to be able to do is write a .dans (my own file format) file that has what i want… (the .cpp structure to draw the model). In this new file format i define a model… model has verts, faces, normals… And i use
#define float vect[3];
model->verts = new vect3 [numvertices]
now the problem is, normally when i write code, if i make a vertex array, i use
static float verticies[20][3] = {{x,y,z}, {x,y,z}…} for the 20 or so verticies i have. But the problem here is, this is being put into a class (model). And this model is being dynamically defined at the beginning of the file by a “new” command. How can i define a whole array at one time?
Is it something like:
model->verts[][] = {{x,y,z}, {x,y,z},…}
???
just leave those brackets blank?
Thanks a bunch for all the help up to here on my program, and Thanks in advance just for reading to here! =P
Thanks!
Dan

That’s a good one… I don’t think you can fill a dynamic array in one go. You can only give it a value at declaration. Note, my book doesn’t tell explicitly this isn’t possible, but it only mentions this CAN be done at declaration. (no mention of such a definition)

Still, I don’t think this should be an issue, since you are using it in a fileloader anyway, so I guess you fill the array in a loop.

[This message has been edited by Structural (edited 12-12-2002).]

i dont know if this helps but…

int sqrs[][2] =
{
1,1
2,4
3,9
4,16
};

is an example in my book.

But the problem is, i want it to write a code that i just need to link to later… so my loader to drop the whole c++ code to draw it… make arrays from itself… (kinda)
the problem is, i have to use a “new” command so, its declared first, THEN i want to set the whole array, in one go…
anyone?
beuler? beuler? beuler?

You can only use brackets to initialize on stack arrays, example:

int array[] = { 1, 2, 3, 4 };

When using dynamic arrays (or on stack arrays using non-constant values) you have to use something else such as loops.

But note that if you want to convert a model directly into C++ code then you can use the on-stack system. But this isn’t such a good idea with large models.

Why do you want to make such a converter anyway? Wouldn’t it be easier to have your program loading the .ase files at runtime?

im loading in HUGE models… or well, not huge, just really complex… (ex: a soccer ball, it has 72201 verts, and like 140,000 faces… plus the normals) when i run it to bring in all that, it takes like 2-2.5 min to load just the verts… if it converts, i can then just link to a .cpp doc to draw it…
or am i way off base on this one?

I think you should try to improve your loader instead of trying to convert your model into cpp files. The later solution isn’t really flexible.

You should try to make those 2-2.5 mins taken by your loader more like 2-2.5 seconds.

If i post my code up here, is it possible for u to look over it? mabey tell me where my laggyness comes in?

***(HEADER FILE)***(ase.cpp)
#include <math.h>
#include <iostream.h>
#include <fstream.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define NUM_VERTEX “*MESH_NUMVERTEX”
#define NUM_FACES “*MESH_NUMFACES”
#define VERTEX “*MESH_VERTEX”
#define MESHFACE “*MESH_FACE”
#define VERTNORM “*MESH_VERTEXNORMAL”
#define FACENORM “*MESH_FACENORMAL”

typedef float vect1;

typedef vect1 vect3[3];

typedef struct
{
int vertIndex[3]; // pt a,pt b,pt c,
int edgeflag[3]; //edge a-b,edge b-c,edge c-a
int coordIndex[3]; // indicies for the tex coords to texture this face
vect3 normal[4]; // normal for each vertex and face(in vector form).
} triangle_t; // normal[1] is face, 2-pt a, 3-pt b, 4-pt c

typedef struct
{
int numVertex; // number of verts in the model
int numFaces; // number of faces in the model
int numTexFaces; // number of textured faces in model
int numTexVertex; // number of texture coords
int normals; // do we have normal information?
vect3 *verts; // model verts
vect3 *texVerts; // texture coords
vect3 *vertNorms; // vertex normals
triangle_t *faces; // faces of model
//texture_t texture; // texture information
} model;

(RUN FILE)
#include <math.h>
#include <iostream.h>
#include <fstream.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//#include <glut.h>
#include “ase.cpp”

model incmodel;

bool aseGetInfo(FILE *s, model *p){ //Get # of verticies, and
rewind (s); //define array sizes accordingly
char info[255];
while (!feof (s)){
fscanf(s, “%s”, &info);
if (!strcmp (info, NUM_VERTEX)){
fscanf(s, “%i”, &p->numVertex);
cout << NUM_VERTEX << " " << p->numVertex << endl;
p->verts = new vect3 [p->numVertex];
}
else if (!strcmp (info, NUM_FACES)){
fscanf(s, “%i”, &p->numFaces);
cout << NUM_FACES << " " << p->numFaces << endl;
p->faces = new triangle_t [p->numFaces];
}
}
return 1;
}

void aseGetVertex(FILE *s, model *p){ //Get each individual vertex
rewind (s); //from the file.
char info[255];
int index;
while (!feof (s)){
fscanf(s, “%s”, &info);
if (!strcmp (info, VERTEX)){
fscanf(s, “%i”, &index);
fscanf(s, “%f”, &p->verts[index][0]);
fscanf(s, “%f”, &p->verts[index][2]);
fscanf(s, “%f”, &p->verts[index][1]);
cout << “Vertex: " << index << " (” << p->verts[index][0] << “,” << p->verts[index][1] << “,” << p->verts[index][2] << “)” << endl;
// ABOVE LINE PROVES IT PULLS IN RIGHT!!!
}
}
}

void aseGetFaces(FILE *s, model *p){ //Get each face from the
rewind(s); //file.
char info[255];
int index;
while (!feof (s)){
fscanf(s, “%s”, &info);
if (!strcmp (info, MESHFACE)){
fscanf (s, “%d:”, &index);
fscanf (s, " A: %d B: %d C: %d AB: %d BC: %d CA: %d",
&p->faces[index].vertIndex[0],
&p->faces[index].vertIndex[1],
&p->faces[index].vertIndex[2],
&p->faces[index].edgeflag[0],
&p->faces[index].edgeflag[1],
&p->faces[index].edgeflag[2]);
/cout << "Face " << index << " made up of verticies " << p->faces[index].vertIndex[0] << ", " << p->faces[index].vertIndex[1] << ", and " << p->faces[index].vertIndex[2] << “.” << endl;
cout << "Side AB is ";
if (p->faces[index].vertIndex[3] == 1){
cout << "drawn. ";
}
else{
cout << "not drawn. ";
}
cout << "Side BC is ";
if (p->faces[index].vertIndex[4] == 1){
cout << "drawn. ";
}
else{
cout << "not drawn. ";
}
cout << "Side CA is ";
if (p->faces[index].vertIndex[5] == 1){
cout << "drawn. ";
}
else{
cout << "not drawn. ";
}
cout << endl;
/ //ALL THIS PROVES IT PULLS IN RIGHT!!!
}
}
}

void aseGetNormals(FILE *s, model *p){
rewind(s);
char info[255];
int index1, index2;
while (!feof (s)){
fscanf(s, “%s”, &info);
if (!strcmp (info, FACENORM)){
fscanf(s, “%d”, &index1);
//cout << index1 << endl;

		fscanf(s, "%f %f %f",
		&p-&gt;faces[index1].normal[0][0],
		&p-&gt;faces[index1].normal[0][2],
		&p-&gt;faces[index1].normal[0][1]);
		cout &lt;&lt; "The Normal vect. for face " &lt;&lt; index1 &lt;&lt; " is (" &lt;&lt; p-&gt;faces[index1].normal[0][0] &lt;&lt; "," &lt;&lt; p-&gt;faces[index1].normal[0][1] &lt;&lt; "," &lt;&lt; p-&gt;faces[index1].normal[0][2] &lt;&lt; ")" &lt;&lt; endl;
		
		fscanf(s, "%s", &info);
		fscanf(s, "%d", &index2);
		fscanf(s, "%f %f %f",
		&p-&gt;faces[index1].normal[1][0],
		&p-&gt;faces[index1].normal[1][2],
		&p-&gt;faces[index1].normal[1][1]);
		cout &lt;&lt; "Face " &lt;&lt; index1 &lt;&lt; " vertex " &lt;&lt; index2 &lt;&lt; " is, (" &lt;&lt; p-&gt;faces[index1].normal[1][0] &lt;&lt; "," &lt;&lt; p-&gt;faces[index1].normal[1][1] &lt;&lt; "," &lt;&lt; p-&gt;faces[index1].normal[1][2] &lt;&lt; ")" &lt;&lt; endl;
		
		fscanf(s, "%s", &info);
		fscanf(s, "%d", &index2);
		fscanf(s, "%f %f %f",
		&p-&gt;faces[index1].normal[2][0],
		&p-&gt;faces[index1].normal[2][2],
		&p-&gt;faces[index1].normal[2][1]);
		cout &lt;&lt; "Face " &lt;&lt; index1 &lt;&lt; " vertex " &lt;&lt; index2 &lt;&lt; " is, (" &lt;&lt; p-&gt;faces[index1].normal[2][0] &lt;&lt; "," &lt;&lt; p-&gt;faces[index1].normal[2][1] &lt;&lt; "," &lt;&lt; p-&gt;faces[index1].normal[2][2] &lt;&lt; ")" &lt;&lt; endl;
		
		fscanf(s, "%s", &info);
		fscanf(s, "%d", &index2);
		fscanf(s, "%f %f %f",
		&p-&gt;faces[index1].normal[3][0],
		&p-&gt;faces[index1].normal[3][2],
		&p-&gt;faces[index1].normal[3][1]);
		cout &lt;&lt; "Face " &lt;&lt; index1 &lt;&lt; " vertex " &lt;&lt; index2 &lt;&lt; " is, (" &lt;&lt; p-&gt;faces[index1].normal[3][0] &lt;&lt; "," &lt;&lt; p-&gt;faces[index1].normal[3][1] &lt;&lt; "," &lt;&lt; p-&gt;faces[index1].normal[3][2] &lt;&lt; ")" &lt;&lt; endl;

	}


}

}

void aseWriteVerticies(FILE *s, model *p, char *mn){
fprintf(s, "#ifndef vect1
typedef float vect1;
#endif

#ifndef vect3
typedef vect1 vect3[3];
#endif

#ifndef triangle
typedef vect1 triangle[3];
#endif

");
fprintf(s, "#ifndef %smodel
typedef struct
{
", mn);
fprintf(s, " vect3 verticies[%i] = {
", p->numVertex);
for (int a=0; a<(p->numVertex-1); a++){
fprintf(s, "{%f,%f,%f}, ", p->verts[a][0], p->verts[a][1], p->verts[a][2]);
if (a%2 == 0){
fprintf(s, "
");
}
}
fprintf(s, "{%f,%f,%f}};
", p->verts[p->numVertex-1][0], p->verts[p->numVertex-1][1], p->verts[p->numVertex-1][2]);

fprintf(s, "	triangle faces[%i] = {
", p-&gt;numFaces);
for (a=0; a&lt;(p-&gt;numFaces-1); a++){
	fprintf(s, "{%i,%i,%i}, ", p-&gt;faces[a].vertIndex[0], p-&gt;faces[a].vertIndex[1], p-&gt;faces[a].vertIndex[2]);
	if (a%2 == 0){
		fprintf(s, "
");
	}
}
fprintf(s, "{%i,%i,%i}};

", p->faces[p->numFaces-1].vertIndex[0], p->faces[p->numFaces-1].vertIndex[1], p->faces[p->numFaces-1].vertIndex[2]);

fprintf(s, "	vect3 facenormal[%i] = {
", p-&gt;numFaces);
for (a=0; a&lt;(p-&gt;numFaces-1); a++){
	fprintf(s, "{%f,%f,%f}, ", p-&gt;faces[a].normal[0][0], p-&gt;faces[a].normal[0][1], p-&gt;faces[a].normal[0][2]);
	if (a%2 == 0){
		fprintf(s, "
");
	}
}
fprintf(s, "{%f,%f,%f}};

", p->faces[p->numFaces-1].normal[0][0], p->faces[p->numFaces-1].normal[0][1], p->faces[p->numFaces-1].normal[0][2]);

//	float facenormal;
float normal1;
float normal2;
float normal3;
float edgeflags;

} %smodel;
#endif
", mn, mn);
fprintf(s, "%smodel (%s);
", mn, mn);
/fprintf(s, "%s->verticies = new vect3 [%i];
", mn, p->numVertex);
fprintf(s, "%s->faces = new triangle [%i];
", mn, p->numFaces);
fprintf(s, "%s->edgeflags = new triangle [%i];
", mn, p->numFaces);
fprintf(s, "%s->facenormal = new vect3 [%i];
", mn, p->numFaces);
fprintf(s, "%s->normal1 = new vect3 [%i];
", mn, p->numFaces);
fprintf(s, "%s->normal2 = new vect3 [%i];
", mn, p->numFaces);
fprintf(s, "%s->normal3 = new vect3 [%i];
", mn, p->numFaces);
/

}

void aseLoad(char *name, model *p){
FILE *s;
if (!(s = fopen (name, “r”)))
{
printf ("Error: ‘%s’ not found!
", name);
}
else{
aseGetInfo(s, &incmodel);
aseGetVertex(s, &incmodel);
aseGetFaces(s, &incmodel);
aseGetNormals(s, &incmodel);
fclose(s);
}
}

void aseWrite(model *p){
char newfn[255], modelname[255];
printf("What file do you want the information converted to? (.dan): ");
cin >> newfn;
printf("What do you want this model called? ");
cin >> modelname;
FILE *s;
if (!(s = fopen (newfn, “w”)))
printf("Error: ‘%s’ could not be opened for writing.
“, newfn);
else{
printf(”’%s’ Created for writing, Writing ‘%s’ now…
", newfn, modelname);
aseWriteVerticies(s, &incmodel, modelname);
}
}

void main(){

char fn[255];
model incmodel;
cout &lt;&lt; "FileName? (.ase): ";
cin &gt;&gt; fn;
aseLoad(fn, &incmodel);
aseWrite(&incmodel);

}

WOW!!!
Just an idea, but, next time just put a link to your file instead of posting it all.

Anyway, even if I don’t know ASE file format by heart I can see several weaknesses.

  • You’re doing multiple passes (readings) on the file. At the beginning of every functions retrieving data you rewind the file.
    AFAIK you don’t have to, you can parse it only one time and get all the data you need.
    File reading is slow, so avoid doing useless reading.

  • You’re reading and comparing a lot of strings when you don’t have to. You can actually quickly know when you can discard a line or a complete block of data delimited by brackets. Discarding such blocks can be done via something like this:
    while (File.get© && (c != ’
    ')); // skip a line
    while (File.get© && (c != ‘}’)); // skip a block of data
    (with “c” being a “char” and File being an “istream” such as “cin”)

  • You’re using “cout” for debug purpose, but cout slows down a lot your program. (it’s probably what’s slowing down the most your loader!)
    You should only use such tricks to debug your program when you’re actually debugging it.
    Either use the “#ifdef DEBUG” method (Visual C++ defines _DEBUG when you’re in Debug mode, and of course doesn’t define it in Release mode. Also don’t forget to use the Release mode to turn on the optimizations of the compiler).
    Or use a global constant that you can manually switch (e.g. at global scope: “const bool DebugVerbose = true;” and in your functions: "if (DebugVerbose) cout << “…”; ")

  • Last thing I’d say would be to use C++ standard library to handle I/O instead of fscanf and so.
    std::string, std::getline(istream, string, delimiter), operator >>, etc… are more than welcome when writing a text file parser.
    If you don’t know the C++ standard library, then I would say you have now a reason to learn it.

[This message has been edited by GPSnoopy (edited 12-15-2002).]

Thanks a bunch for the help man!
Yes, the couts are just for debug purposes
i like the idea about not rewinding every time… which ill most definatly use…
also, the idea with dropping whole lines at a time is good, very good… ill use that too =P… but as for the not using fscanf, i dunno man, i like it, nice and easy to use, unless u say the other way is a hell of a lot faster/easier once i know it…
Thanks again

I think you need a dll like unit which all of your data is in it.
The idea is same.You need a precompiled data
and dll provides it.But this is not solve your speed problem.

The C++ standard library is particulary helpful with text handling (among other things). It makes your life a lot easier.
Note that I didn’t say you should drop fscanf if you feel confident with it; as learning the C++ std lib takes a while if you want to use it correctly, but you certainly won’t regret it.

To give you an idea, the following program (without the #include and function headers) reads all the line from a file, sorts them and outputs them on “cout”:

vector Lines;
string Line;

while (getline(File, Line))
Lines.push_back(Line);

sort(Lines.begin(), Lines.end());
copy(Lines.begin(), Lines.end(), ostream_iterator(cout, "
"));

But don’t let this C++ programming influences you.
The most important is still the way you do things in your algorithms.
If something isn’t fast enough for you: improve, rethink, improve, rethink, improve, etc…
I hope the points mentioned in upper posts will help you with your loader.