Sign in to follow this  
adam17

MSVC++ Grammar issues?!?!

Recommended Posts

has anybody EVER experienced a problem with MS visual c++ finding errors in your code? for example my program is console based and can output anything just fine except ONE LINE of code. the program crashes on some weird things like if there is an extra space between "<< endl;" or something like it. everything compiles fine. my program just crashes. any ideas? should i reinstall msvc++?

Share this post


Link to post
Share on other sites
Sometimes if you are playing with pointers and manage to
corrupt your heap, the program will crash in odd places seemingly
unrelated to your code. Say, if you allocate memory in a constructor
and declare a global object as follows:


class CMyClass {
public:
int *Data;
MyClass() { Data = new int[50]; }
};

// Global Declaration //
CMyClass MyObject; // <-- Badness ensues since MyObject.Data //
// not actually alloc'd //



I did this once, and my program crashed when I stepped into a totally
unrelated and very inane looking line of code. Took quite awhile to find
the error, since I was not aware of this behavior in global objects.

Share this post


Link to post
Share on other sites
If you post the code here, we can take a look at it. You can try reinstalling MSVC++, but chances are very high that your code is at fault rather than the compiler. The chances of something that particular messing up in an install is highly unlikely :-) It probably just appears that an extra space causes the error, when in fact it may just be a seg fault that occurs randomly due to an error elsewhere in your code. To make sure this is the case, try the most basic of program (eg such a cout) and see if it induces the space error consistently.

This probably also belongs in a more appropriate forum, such as General Programming.

Share this post


Link to post
Share on other sites
<not directly relating to the OP's question>

Quote:
Original post by Cryoknight
Sometimes if you are playing with pointers and manage to
corrupt your heap, the program will crash in odd places seemingly
unrelated to your code. Say, if you allocate memory in a constructor
and declare a global object as follows:


class CMyClass {
public:
int *Data;
MyClass() { Data = new int[50]; }
};

// Global Declaration //
CMyClass MyObject; // <-- Badness ensues since MyObject.Data //
// not actually alloc'd //



I did this once, and my program crashed when I stepped into a totally
unrelated and very inane looking line of code. Took quite awhile to find
the error, since I was not aware of this behavior in global objects.


Global objects will be instantiated properly. The problem here is likely that you had a second static object depend on MyObject being initialised. Static initialisation order between translation units is not defined.
// file1.h
class Test1
{
public:
Test1()
:
pointer(new int)
{
*pointer = 7;
}
int* pointer;
};
extern Test1 object1;

// file2.h
#include <iostream>
#include "file1.h"

class Test2
{
public:
Test2(Test1 object)
:
pointer(object.pointer)
{
std::cout << *pointer << '\n';
}
int* pointer;
};

// file1.cpp
#include "file1.h"

Test1 object1;

//file2.cpp
#include "file2.h"

Test2 object2;


Under BCC if I compile (after adding a main function) as:
bcc32 file1.cpp file2.cpp

I get the output 7, but if I compile as:
bcc32 file2.cpp file1.cpp

I get an illegal operation, because the Borland compiler happens to instantiate global objects in the order it sees them. Therefore if I compile file1.cpp before file2.cpp then object1 is instantiated before object 2, but if I compile file2.cpp before file1.cpp then object2 is instantiated before object1. Since object2 depends on object1 being instantiated this causes a run-time error.

</not directly relating to the OP's question>

OP: Is your code entirely deterministic? I.e. does it always have exactly the same data, with nothing that could vary between runs (time, user input, random numbers etc.). If so, then I would recommend a reinstall, since fully deterministic programs should be identical regardless of whitespace in the source. If it's not fully deterministic then you've almost certainly got a heap or stack corrupting bug in there somewhere. I believe Visual C++ should be able to catch these in debug mode (don't use it, so I don't know the details).

Enigma

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
sure i can post the code

this is main.cpp


#include <iomanip.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <fstream.h>
#include <vector>
using namespace std;


bool ImportLDM(char* filename);

FILE* infile;

///////////////////////////////////////////////////////
///////////////////MESH DEFINITIONS////////////////////
///////////////////////////////////////////////////////
typedef struct _point3
{
float x, y, z;
vector<int> face; //stores adjacent face indices
} point3;

typedef struct _polygon
{
//point3 face_ind;
point3 v1, v2, v3;
point3 fnormal;
point3 vn1, vn2, vn3;

int matid;
int smoothgroup;
} polygon;

struct _mesh
{
int NumVert;
int NumFace;
vector<point3> Vert; //stores all of the vertex information
vector<point3> Face; //stores all of the face winding info

vector<polygon> polys;
};
_mesh mesh;
///////////////////////////////////////////////////////
///////////////////MESH DEFINITIONS////////////////////
///////////////////////////////////////////////////////

void main()
{
char filename[256];

printf("input a filename with extension...\n");
scanf("%s", filename);

if(ImportLDM(filename) == true)
printf("\nfile opens!\n");
else
printf("file not found!\n");
}

void CalVertexNormals()
{
cout << "\ndefining vert_face...";
vector< vector<int> > vert_face;
cout << "\nresizing vert_face...";
vert_face.resize(mesh.NumVert);

cout << "\ncalculating vertex normals...";

for(int x=0; x<mesh.NumVert; x++)
{
cout << "starting face loop...\n";
for(int y=0; y<mesh.NumFace; y++)
{
if(mesh.Face[y].x == x)
{
vert_face.resize(vert_face.capacity());
vert_face[y][vert_face.capacity()] = x;
}
if(mesh.Face[y].y == x)
{
vert_face.resize(vert_face.capacity());
vert_face[y][vert_face.capacity()] = x;
}
if(mesh.Face[y].z == x)
{
vert_face.resize(vert_face.capacity());
vert_face[y][vert_face.capacity()] = x;
}
}
}

cout << "Vertex->Face Associations" << endl;
for(x=0; x<mesh.NumVert; x++)
{
for(int y=0; y<vert_face[x].capacity(); y++)
{
cout << vert_face[x][y] << ' ';
}
cout << endl;
}
}

bool ImportLDM(char* filename)
{
char sdummy[256];
char cdummy;
int mode = 0; //0-vertex 1-face 2-normal 3-material ID 4-smoothgroup
int count = 0;

infile = fopen(filename, "r");
if(infile == false)
return false;
fseek(infile, 0L, SEEK_SET);

fscanf(infile, "%i %i", &mesh.NumVert, &mesh.NumFace);
fscanf(infile, "%s", &sdummy);

mesh.Vert.resize(mesh.NumVert*3);
mesh.Face.resize(mesh.NumFace*3);

while(!feof(infile))
{
cdummy = fgetc(infile);
switch(cdummy)
{
/***set modes for reading data***/
/*******and reset counter********/
case 'v' : mode=0; count=0; break;
case 'f' : mode=1; count=0; break;
case 'n' : mode=2; count=0; mesh.polys.resize(mesh.NumFace); break;
case 'm' : mode=3; count=0; mesh.polys.resize(mesh.NumFace); break;
case 's' : mode=4; count=0; mesh.polys.resize(mesh.NumFace); break;
/********************************/

case '[' :
switch(mode)
{
case 0: fscanf(infile, "%f,%f,%f]", &mesh.Vert[count].x, &mesh.Vert[count].y, &mesh.Vert[count].z);
count++;
break;
case 1: fscanf(infile, "%f,%f,%f]", &mesh.Face[count].x, &mesh.Face[count].y, &mesh.Face[count].z);
mesh.Face[count].x--; mesh.Face[count].y--; mesh.Face[count].z--;
count++;
break;
case 2: fscanf(infile, "%f,%f,%f]", &mesh.polys[count].fnormal.x, &mesh.polys[count].fnormal.y, &mesh.polys[count].fnormal.z);
count++;
break;
}
break;

case '#' :
if(mode == 4)
{
fscanf(infile, "{%i}", &mesh.polys[count].smoothgroup);
cout << mesh.polys[count].smoothgroup << endl;
count++;
}
break;

default:
switch(mode)
{
case 3: fscanf(infile, "%i", &mesh.polys[count].matid);
count++;
break;
}
}
}

cout << "vertices:\n";
for(int x=0; x<mesh.NumVert; x++)
cout << mesh.Vert[x].x << ' ' << mesh.Vert[x].y << ' ' << mesh.Vert[x].z << endl;
cout << "indices:\n";
for(x=0; x<mesh.NumFace; x++)
cout << mesh.Face[x].x << ' ' << mesh.Face[x].y << ' ' << mesh.Face[x].z << endl;
cout << "face normals:\n";
for(x=0; x<mesh.NumFace; x++)
cout << mesh.polys[x].fnormal.x << ' ' << mesh.polys[x].fnormal.y << ' ' << mesh.polys[x].fnormal.z << endl;
cout << "matid:\n";
for(x=0; x<mesh.NumFace; x++)
cout << mesh.polys[x].matid << ' ';
cout << endl << "smoothgroups:" << endl;
for(x=0; x<mesh.NumFace; x++)
cout << mesh.polys[x].smoothgroup << " ";

fclose(infile);

CalVertexNormals();

return true;
}



this is test.txt

8 12
v
[-15,-10,0]
[15,-10,0]
[-15,10,0]
[15,10,0]
[-15,-10,40]
[15,-10,40]
[-15,10,40]
[15,10,40]

f
[1,3,4]
[4,2,1]
[5,6,8]
[8,7,5]
[1,2,6]
[6,5,1]
[2,4,8]
[8,6,2]
[4,3,7]
[7,8,4]
[3,1,5]
[5,7,3]

n
[0,0,-1]
[0,0,-1]
[0,0,1]
[0,0,1]
[0,-1,0]
[0,-1,0]
[1,0,0]
[1,0,0]
[0,1,0]
[0,1,0]
[-1,0,0]
[-1,0,0]

m
2
2
1
1
5
5
4
4
6
6
3
3

s
#{2}
#{2}
#{3}
#{3}
#{4}
#{4}
#{5}
#{5}
#{6}
#{6}
#{7}
#{7}



this is a console program. when u run it just type in "test.txt" (w/o quotes) and u can see what is happening

Share this post


Link to post
Share on other sites
I've barely looked at it and have found three problems:
#include <iomanip.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <fstream.h>
#include <vector>

should be
#include <iomanip>
#include <conio.h>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <vector>

fstream.h and iomanip.h are not a part of the C++ standard. They are an implementation detail for your particular compiler. The proper headers are fstream and iomanip. Similarly stdio.h and stdlib.h were superceeded in C++ by cstdio and cstdlib.

You use std::cout but never include iostream. If appears that in your implementation one of the other headers you are including is itself including iostream. You should not depend on this.

	for(int x=0; x<mesh.NumVert; x++)
cout << mesh.Vert[x].x << ' ' << mesh.Vert[x].y << ' ' << mesh.Vert[x].z << endl;
cout << "indices:\n";
for(x=0; x<mesh.NumFace; x++)
cout << mesh.Face[x].x << ' ' << mesh.Face[x].y << ' ' << mesh.Face[x].z << endl;

This is an error. I'm guessing you're using MSVC++ 6? If you're using version 7 please find and turn on conformant for loop behaviour. A variable defined in a for loop is local to the loop according to the standard. A workaround that will work on conforming and nonconforming compilers is to predeclare the variable:
int x;
for(x=0; x<mesh.NumVert; x++)
cout << mesh.Vert[x].x << ' ' << mesh.Vert[x].y << ' ' << mesh.Vert[x].z << endl;
cout << "indices:\n";
for(x=0; x<mesh.NumFace; x++)
cout << mesh.Face[x].x << ' ' << mesh.Face[x].y << ' ' << mesh.Face[x].z << endl;


While I'm at it, typedef'd structs are redundant in C++. You can use the struct name without having to use the struct keyword.

I'll post back if I find any other errors.

Enigma

Share this post


Link to post
Share on other sites
Another big problem that isn't causing your crash, plus the cause of your crash:
	char filename[256];

printf("input a filename with extension...\n");
scanf("%s", filename);

What do you think is going to happen when I enter this_is_a_very_long_filename_for_a_file_which_probably_doesnt_exist_but_thats_not_the_point_now_really_is_it_I_just_want_your_code_to_fall_over_and_die_If_I_was_feeling_really_horrible_I_could_try_and_insert_some_instructions_here_to_really_test_if_you_have_a_security_leak.txt?
			if(mesh.Face[y].x == x)
{
vert_face.resize(vert_face.capacity());
vert_face[y][vert_face.capacity()] = x;
}
if(mesh.Face[y].y == x)
{
vert_face.resize(vert_face.capacity());
vert_face[y][vert_face.capacity()] = x;
}
if(mesh.Face[y].z == x)
{
vert_face.resize(vert_face.capacity());
vert_face[y][vert_face.capacity()] = x;
}

You're indexing into vert_face[y] even though vert_face[y] has not been resized. You're also calling the capacity() member function, when you should be using size() and you should be indexing with size() - 1 if you want the last element.

I'm going to rewrite your code for you in full C++ rather that the C with a little bit of C++ that you're using just so you can see how much cleaner it is.

Enigma

Share this post


Link to post
Share on other sites
WOW!!! i never realized how f***ed up my code really was?!?! i took 2 compsci class 3 years ago and my teachers NEVER told us the importance behind using the right datatypes. on top of that i have had to teach myself traditional c like using printf instead of cout.

thank you guys SOOO much!

if any of you guys realize what i have going on in my function CalVertexNormals, and could offer any more optimization suggestions, PLEASE TELL ME!

Share this post


Link to post
Share on other sites
Quote:
Original post by Enigma
Another big problem that isn't causing your crash, plus the cause of your crash:
*** Source Snippet Removed ***
You're indexing into vert_face[y] even though vert_face[y] has not been resized. You're also calling the capacity() member function, when you should be using size() and you should be indexing with size() - 1 if you want the last element.

I'm going to rewrite your code for you in full C++ rather that the C with a little bit of C++ that you're using just so you can see how much cleaner it is.

Enigma


im a little lost here. im trying to fix it but i keep getting errors, im guessing with resizing the arrays...


for(x=0; x<mesh.NumVert; x++)
{
for(y=0; y<mesh.NumFace; y++)
{
if(mesh.Face[y].x == x)
{
vert_face.resize(vert_face.size()+1);
vert_face[y][vert_face.size()-1] = x;
}
if(mesh.Face[y].y == x)
{
vert_face.resize(vert_face.size()+1);
vert_face[y][vert_face.size()-1] = x;
}
if(mesh.Face[y].z == x)
{
vert_face.resize(vert_face.size()+1);
vert_face[y][vert_face.size()-1] = x;
}
}
}


Share this post


Link to post
Share on other sites
I'm not entirely sure what you're doing in your CalVertexNormals function. The error is that you access vert_face[y][...] but you never actually resize vert_face[y], you only resize vert_face.

Here's what I came up with based on your code. Note that if I'd have been writing this I wouldn't have done it this way. I would probably have read the vertex, face, normal etc. data into arrays and then assembled polygons from them rather than trying to do the two at one. It's a little cludgy since it was hacked together with little design though. It's a little STL heavy, so have a reference handy (but be glad I couldn't get bind2nd and mem_fun to work in the accumulate call)!

A point class to replace your point3 struct. Note that I templated it since faces are a set of three integers instead of floats. If I'd have been writing this from scratch I would have gone for different names, since a normal and a face are not a point, but I wanted to keep it as close as possible to your original code.
#if !defined(POINT_HEADER)
#define POINT_HEADER

#include <cmath>
#include <ctype>
#include <iostream>

template <typename TYPE>
class Point3
{

public:

Point3()
:
x(),
y(),
z()
{
}

TYPE x;
TYPE y;
TYPE z;

};

typedef Point3<float> Point3f;
typedef Point3<int> Point3i;

template <typename TYPE>
std::istream& operator>>(std::istream& reader, Point3<TYPE>& point)
{
while (std::isspace(reader.peek()))
{
reader.ignore(1);
}
reader.ignore(1);
reader >> point.x;
reader.ignore(1);
reader >> point.y;
reader.ignore(1);
reader >> point.z;
reader.ignore(1);
return reader;
}

template <typename TYPE>
std::ostream& operator<<(std::ostream& writer, const Point3<TYPE>& point)
{
writer << '[' << point.x << ", " << point.y << ", " << point.z << ']';
return writer;
}

template <typename TYPE>
const Point3<TYPE>& operator+=(Point3<TYPE>& firstPoint, const Point3<TYPE>& secondPoint)
{
firstPoint.x += secondPoint.x;
firstPoint.y += secondPoint.y;
firstPoint.z += secondPoint.z;
return firstPoint;
}

template <typename TYPE>
class Normalise
{

public:

void operator()(TYPE& point)
{
float length = std::sqrt((point.x * point.x) + (point.y * point.y) + (point.z * point.z));
if (length < FLT_EPSILON)
{
length = 1;
}
point.x /= length;
point.y /= length;
point.z /= length;
}
};

#endif



Header file for a Polygon class. This is pretty poorly designed since it's just a set of getters/setters. This again is because I was trying to make it as close to your code as possible.
#if !defined(POLYGON_HEADER)
#define POLYGON_HEADER

#include <iosfwd>

#include "Point.h"

class Polygon
{

public:

Polygon();
Point3f getFaceNormal() const;
int getSmoothingGroup() const;
void print(std::ostream& writer) const;
void setMaterial(int materialId);
void setNormal(Point3f normal);
void setSmoothingGroup(int smoothingGroup);
void setVertices(Point3f vertex1, Point3f vertex2, Point3f vertex3);
void setVertexNormals(Point3f vertex1, Point3f vertex2, Point3f vertex3);

private:

Point3f vertices_[3];
Point3f faceNormal_;
Point3f vertexNormals_[3];
int materialId_;
int smoothingGroup_;
};

std::ostream& operator<<(std::ostream& writer, const Polygon& polygon);

#endif



Implementation for the polygon. Note how I don't have a single comment in the source. This is not due to lack of time or lazyness - it doesn't need comments because the variable and function names, in their context, tell you all you need to know.
#if !defined(POLYGON_IMPLEMENTATION)
#define POLYGON_IMPLEMENTATION

#include <iostream>

#include "Polygon.h"

Polygon::Polygon()
:
materialId_(-1),
smoothingGroup_(-1)
{
}

Point3f Polygon::getFaceNormal() const
{
return faceNormal_;
}

int Polygon::getSmoothingGroup() const
{
return smoothingGroup_;
}

void Polygon::print(std::ostream& writer) const
{
writer << "Vertices:\n" << '\t' << vertices_[0] << "\n\t" << vertices_[1] << "\n\t" << vertices_[2] << '\n';
writer << "Normal: " << faceNormal_ << '\n';
writer << "Vertex Normals:\n" << '\t' << vertexNormals_[0] << "\n\t" << vertexNormals_[1] << "\n\t" << vertexNormals_[2] << '\n';
writer << "Material ID: " << materialId_ << '\n';
writer << "Smoothing Group: " << smoothingGroup_ << '\n';
}

void Polygon::setMaterial(int materialId)
{
materialId_ = materialId;
}

void Polygon::setNormal(Point3f normal)
{
faceNormal_ = normal;
}

void Polygon::setSmoothingGroup(int smoothingGroup)
{
smoothingGroup_ = smoothingGroup;
}

void Polygon::setVertices(Point3f vertex1, Point3f vertex2, Point3f vertex3)
{
vertices_[0] = vertex1;
vertices_[1] = vertex2;
vertices_[2] = vertex3;
}

void Polygon::setVertexNormals(Point3f normal1, Point3f normal2, Point3f normal3)
{
vertexNormals_[0] = normal1;
vertexNormals_[1] = normal2;
vertexNormals_[2] = normal3;
}

std::ostream& operator<<(std::ostream& writer, const Polygon& polygon)
{
polygon.print(writer);
return writer;
}

#endif



Header file for the mesh.
#if !defined(MESH_HEADER)
#define MESH_HEADER

#include <iosfwd>
#include <vector>

#include "Point.h"
#include "Polygon.h"

class Mesh
{

public:

void calculateVertexNormals();
void print(std::ostream& writer) const;
void read(std::istream& reader);

private:

void readFaces(std::istream& reader);
void readMaterials(std::istream& reader);
void readNormals(std::istream& reader);
void readSmoothingGroups(std::istream& reader);
void readVertices(std::istream& reader);

std::vector<Point3f> vertices;
std::vector<Point3i> faces;
std::vector<Polygon> polygons;
};

std::istream& operator>>(std::istream& reader, Mesh& mesh);
std::ostream& operator<<(std::ostream& writer, const Mesh& mesh);

#endif



Implementation for the mesh. Have an STL reference handy!
#if !defined(MESH_IMPLEMENTATION)
#define MESH_IMPLEMENTATION

#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>

#include "Mesh.h"

class FindMaximumSmoothingGroup
{

public:

int operator()(int maximumSmoothingGroup, Polygon& polygon)
{
return std::max(maximumSmoothingGroup, polygon.getSmoothingGroup());
}

};

void Mesh::calculateVertexNormals()
{
// find out how many smoothing groups there are
int maximumSmoothingGroup = std::accumulate(polygons.begin(), polygons.end(), 0, FindMaximumSmoothingGroup());

// for each smoothing group
for (int smoothingGroupNumber = 0; smoothingGroupNumber < maximumSmoothingGroup + 1; ++smoothingGroupNumber)
{

// set up a set of vertex normals for this smoothing group
std::vector<Point3f> vertexNormals(vertices.size());

// for each polygon
for (unsigned int polygonNumber = 0; polygonNumber < polygons.size(); ++polygonNumber)
{

// if this polygon is in the current smoothing group
if (polygons[polygonNumber].getSmoothingGroup() == smoothingGroupNumber)
{

// set the polygon vertices
polygons[polygonNumber].setVertices(vertices[faces[polygonNumber].x], vertices[faces[polygonNumber].y], vertices[faces[polygonNumber].z]);

// sum the polgon normal into the vertex normals for this smoothing group
vertexNormals[faces[polygonNumber].x] += polygons[polygonNumber].getFaceNormal();
vertexNormals[faces[polygonNumber].y] += polygons[polygonNumber].getFaceNormal();
vertexNormals[faces[polygonNumber].z] += polygons[polygonNumber].getFaceNormal();
}
}

// normalise the vertex normals for this smoothing group
std::for_each(vertexNormals.begin(), vertexNormals.end(), Normalise<Point3f>());

// for each polygon
for (unsigned int polygonNumber = 0; polygonNumber < polygons.size(); ++polygonNumber)
{

// if this polygon is in the current smoothing group then copy the calculated vertex normals into it
if (polygons[polygonNumber].getSmoothingGroup() == smoothingGroupNumber)
{
polygons[polygonNumber].setVertexNormals(vertexNormals[faces[polygonNumber].x], vertexNormals[faces[polygonNumber].y], vertexNormals[faces[polygonNumber].z]);
}
}
}
}

void Mesh::print(std::ostream& writer) const
{
writer << "vertices:\n";
std::copy(vertices.begin(), vertices.end(), std::ostream_iterator<Point3f>(writer, "\n"));
writer << "\nfaces:\n";
std::copy(faces.begin(), faces.end(), std::ostream_iterator<Point3i>(writer, "\n"));
writer << "\npolygons:\n";
std::copy(polygons.begin(), polygons.end(), std::ostream_iterator<Polygon>(writer, "\n"));
}

void Mesh::read(std::istream& reader)
{
int numberOfVertices;
reader >> numberOfVertices;
vertices.resize(numberOfVertices);
int numberOfFaces;
reader >> numberOfFaces;
faces.resize(numberOfFaces);
polygons.resize(numberOfFaces);
bool verticesRead = false;
bool facesRead = false;
while (!reader.eof())
{
while (std::isspace(reader.peek()))
{
reader.ignore(1);
}
char dataType = reader.get();
if (dataType == 'v')
{
readVertices(reader);
verticesRead = true;
}
else if (dataType == 'f')
{
readFaces(reader);
facesRead = true;
}
else if (dataType == 'n')
{
if (!verticesRead || !facesRead)
{
throw std::string("Need vertex & face information before faces");
}
readNormals(reader);
}
else if (dataType == 'm')
{
if (!verticesRead || !facesRead)
{
throw std::string("Need vertex & face information before materials");
}
readMaterials(reader);
}
else if (dataType == 's')
{
if (!verticesRead || !facesRead)
{
throw std::string("Need vertex & face information before smoothing groups");
}
readSmoothingGroups(reader);
}
}
}

void Mesh::readVertices(std::istream& reader)
{
for (unsigned int vertexNumber = 0; vertexNumber < vertices.size(); ++vertexNumber)
{
Point3f vertex;
reader >> vertex;
vertices[vertexNumber] = vertex;
}
}

void Mesh::readFaces(std::istream& reader)
{
for (unsigned int faceNumber = 0; faceNumber < faces.size(); ++faceNumber)
{
Point3i face;
reader >> face;
face.x -= 1;
face.y -= 1;
face.z -= 1;
faces[faceNumber] = face;
}
}

void Mesh::readNormals(std::istream& reader)
{
for (unsigned int polygonNumber = 0; polygonNumber < faces.size(); ++polygonNumber)
{
Point3f normal;
reader >> normal;
polygons[polygonNumber].setNormal(normal);
}
}

void Mesh::readMaterials(std::istream& reader)
{
for (unsigned int polygonNumber = 0; polygonNumber < faces.size(); ++polygonNumber)
{
int materialId;
while (std::isspace(reader.peek()))
{
reader.ignore(1);
}
reader >> materialId;
polygons[polygonNumber].setMaterial(materialId);
}
}

void Mesh::readSmoothingGroups(std::istream& reader)
{
for (unsigned int polygonNumber = 0; polygonNumber < faces.size(); ++polygonNumber)
{
int smoothingGroup;
while (std::isspace(reader.peek()))
{
reader.ignore(1);
}

// ignore the #( and ) around the value
reader.ignore(2);
reader >> smoothingGroup;
reader.ignore(1);
polygons[polygonNumber].setSmoothingGroup(smoothingGroup);
}
}

std::istream& operator>>(std::istream& reader, Mesh& mesh)
{
mesh.read(reader);
return reader;
}

std::ostream& operator<<(std::ostream& writer, const Mesh& mesh)
{
mesh.print(writer);
return writer;
}

#endif



Main application file. Note that by having classes with appropriate behaviour the high level view of the application is completely trivial.
#include <fstream>
#include <iostream>
#include <string>

#include "Mesh.h"

Mesh importLdm(std::string filename)
{
std::ifstream reader(filename.c_str());
if (!reader)
{
throw std::string("File not found");
}

// natural reusable syntax for reading meshes.
Mesh mesh;
reader >> mesh;
std::cout << mesh;
mesh.calculateVertexNormals();
std::cout << mesh;
return mesh;
}

int main()
{
// no buffer overflow bugs
std::string filename;
std::cout << "input a filename with extension...\n";
std::getline(std::cin, filename);

try
{
Mesh mesh = importLdm(filename);
}
catch (std::string& exception)
{
std::cout << "Error: " << exception << '\n';
}
}


Hope this helps. One final comment I would make: The two most important things in C++ are whitespace and function/variable names. Source code is a communication medium - use it as such.

Enigma

Share this post


Link to post
Share on other sites
DUDE! u didnt have to rewrite all of my code, but thanks anyway! im not gonna just copy and paste it into my program. i wont learn anything that way. i never learned templates or much about STL stuff. u have given me ALOT of ideas and im going to give my code a serious overhaul and revamp it.

also how would you guys recommend me setting up my different classes and structures? i need something for vertex indices, face indices, normals, vertex normals, smoothing groups, material IDs, etc. tell me what you think of the changes i made to my structures...

are they too nested?
too many?
do i need better variable names?


template <typename TYPE> class tVector3
{
public:
tVector3(): x(), y(), z() {}
TYPE x;
TYPE y;
TYPE z;
};

typedef tVector3<float> Vector3f;
typedef tVector3<int> Vector3i;

struct tVertex
{
Vector3f Vertex3f;
vector<int> neighbor;
};

typedef struct _polygon
{
tVertex vertex[3]; //vertex values
Vector3f fNormal3f; //face normal
Vector3f vNormal3f[3]; //vertex normals

int matid;
int smoothgroup;
} polygon;

struct _mesh
{
int NumVert;
int NumFace;
vector<tVertex> Vert; //TEMPORARILY stores all of the vertex information
vector<Vector3i> Face; //TEMPORARILY stores all of the face winding info

vector<polygon> polys;
} mesh;




[Edited by - adam17 on December 6, 2004 2:53:24 PM]

Share this post


Link to post
Share on other sites
If I was going to write a simple loader for that file format from scratch I would probably use something like:
template <typename TYPE>
class Vector3
{
public:
Vector3()
{
}
Vector3(TYPE initialiser)
:
x(initialiser),
y(initialiser),
z(initialiser)
{
}
TYPE x;
TYPE y;
TYPE z;
};

typedef float GeometricType;
typedef Vector3<GeometricType> GeometicVector;

class Material
{
public:
// member functions
private:
// member functions & variables
};

class Polygon
{
public:
// member functions
private:
// member functions & variables
GeometricVector vertices_[3];
GeometricVector normals_[3];
Material& material_;
};

class Mesh
{
public:
// member functions
private:
// member functions & variables
std::deque<Polygon> polygons_;

typedef unsigned short VertexIndexType;

class FaceVertices
{
public:
FaceVertices(VertexIndexType faceVertex1, VertexIndexType faceVertex2, VertexIndexType faceVertex3)
:
vertex1(faceVertex1),
vertex2(faceVertex2),
vertex3(faceVertex3)
{
}
VertexIndexType vertex1;
VertexIndexType vertex2;
VertexIndexType vertex3;
};
};


And then load using something like:
std::deque<GeometicVector> vertices;
std::deque<FaceVertices> faces;
std::deque<GeometicVector> faceNormals;
std::deque<Material&> faceMaterials;
typedef unsigned short SmoothingGroupType;
std::deque<SmoothingGroupType> smoothingGroups;
load(vertices, faces, faceNormals, faceMaterials, smoothingGroups);
std::deque<GeometricVector> vertexNormals = calculateVertexNormals(faces, faceNormals, smoothingGroups);
polygons_ = buildPolygons(vertices, faces, faceMaterials, vertexNormals);



This is just pseudo-code of course and my actual function calls would look nothing like that.

A bit of explanation:
I use std::deque instead of std::vector since contiguous storage is not required. std::deque may have better performance than std::vector.
I use typedefs for types that I might want to change later. For example GeometicType. In the example above this is just a typedef for float. It at a later date I decide I need extra precision and want to use doubles I only have to change one line.
It makes no sense for the set of vertices that make up a face to be named x, y and z. Therefore instead of reusing my templated vector class I create a new class. Faces are an implementation detail of a mesh, so I make it a private class in Mesh.
I hold references to materials. This assumes that I am either able to load materials beforehand or I have a std::deque<Material> and populate it as faces require materials. The actual material properties would then be set to a default and then updated to the correct values when the material was actually read.
Only the persistent key properties are kept as variables in the main classes. Temporary storage is moved to local variables in functions or helper classes.

Enigma

Share this post


Link to post
Share on other sites
enigma

when u start making templates and start putting classes inside of other classes, doesnt that slow down your program when u access some of the deepest elements?

Share this post


Link to post
Share on other sites
Templates and nested classes are purely compile-time constructs. They incur no run-time penalty what-so-ever. Regardless, it is much better to write code clearly and with good encapsulation as it speeds up the writing and testing of the code, giving you more time to concentrate on optimising the bottlenecks in your program rather than spending a month writing the most optimised physics engine possible, only to find you were fillrate limited all along.

Enigma

Share this post


Link to post
Share on other sites
ok here is what i have done to my code. im not entirely done with it though.



#include <iomanip>
#include <conio.h>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <vector>
using namespace std;


bool ImportLDM(char* filename);

FILE* infile;

///////////////////////////////////////////////////////
///////////////////MESH DEFINITIONS////////////////////
///////////////////////////////////////////////////////
template <typename TYPE> class tVector3
{
public:
tVector3(): x(), y(), z() {}
TYPE x;
TYPE y;
TYPE z;
};

typedef tVector3<float> Vector3f;
typedef tVector3<int> Vector3i;

struct tVertex
{
float x, y, z;
vector<int> neighbor;
};

struct tFace
{
float x, y, z;
};

typedef struct _polygon
{
Vector3i vert_face_ind; //which vertices the face uses
tVertex v1, v2, v3; //vertex values
Vector3f fNormal3f; //face normal
Vector3f vNormal3f[3]; //vertex normals

int matid;
int smoothgroup;
} polygon;

struct _mesh
{
int NumVert;
int NumFace;

vector<polygon> polys;
} mesh;
///////////////////////////////////////////////////////
///////////////////MESH DEFINITIONS////////////////////
///////////////////////////////////////////////////////

int main(int argc, char** argv)
{
char filename[256];

printf("input a filename with extension...\n");
scanf("%s", filename);

if(ImportLDM(filename) == false)
printf("file not found!\n");

return 0;
}

void CalVertexNormals()
{
int x=0, y=0, array_len=0, count=0;

printf("\ncalculating vertex normals...\n");

for(x=0; x<mesh.NumVert; x++)
{
for(y=0; y<mesh.NumFace; y++)
{
if(mesh.polys[y].vert_face_ind.x == x)
{
//printf("%i found\n", count++);
array_len = mesh.polys[y].v1.neighbor.size();

mesh.polys[y].v1.neighbor.resize(mesh.polys[y].v1.neighbor.size()+1);
mesh.polys[y].v1.neighbor[array_len] = x;
}
if(mesh.polys[y].vert_face_ind.y == x)
{
//printf("%i found\n", count++);
array_len = mesh.polys[y].v1.neighbor.size();

mesh.polys[y].v2.neighbor.resize(mesh.polys[y].v2.neighbor.size()+1);
mesh.polys[y].v2.neighbor[array_len] = x;
}
if(mesh.polys[y].vert_face_ind.z == x)
{
//printf("%i found\n", count++);
array_len = mesh.polys[y].v1.neighbor.size();

mesh.polys[y].v3.neighbor.resize(mesh.polys[y].v3.neighbor.size()+1);
mesh.polys[y].v3.neighbor[array_len] = x;
}
}
}
printf("finished calculating normals...\n");
}

bool ImportLDM(char* filename)
{
char sdummy[256];
char cdummy;
int mode = 0; //0-vertex 1-face 2-normal 3-material ID 4-smoothgroup
int count = 0;

vector<tVertex> Vert; //TEMPORARILY stores all of the vertex information
//vector<Vector3i> Face; //TEMPORARILY stores all of the face winding info

infile = fopen(filename, "r");
if(infile == false)
return false;
fseek(infile, 0L, SEEK_SET);

fscanf(infile, "%i %i", &mesh.NumVert, &mesh.NumFace);
fscanf(infile, "%s", &sdummy);

Vert.resize(mesh.NumVert);
mesh.polys.resize(mesh.NumFace);

while(!feof(infile))
{
cdummy = fgetc(infile);
switch(cdummy)
{
/***set modes for reading data***/
/*******and reset counter********/
case 'v' : mode=0; count=0; break;
case 'f' : mode=1; count=0; break;
case 'n' : mode=2; count=0; mesh.polys.resize(mesh.NumFace); break;
case 'm' : mode=3; count=0; mesh.polys.resize(mesh.NumFace); break;
case 's' : mode=4; count=0; mesh.polys.resize(mesh.NumFace); break;
/********************************/

case '[' :
switch(mode)
{
case 0: fscanf(infile, "%f,%f,%f]",
&Vert[count].x,
&Vert[count].y,
&Vert[count].z);
count++;
break;
case 1: fscanf(infile, "%i,%i,%i]",
&mesh.polys[count].vert_face_ind.x,
&mesh.polys[count].vert_face_ind.y,
&mesh.polys[count].vert_face_ind.z);
mesh.polys[count].vert_face_ind.x--;
mesh.polys[count].vert_face_ind.y--;
mesh.polys[count].vert_face_ind.z--;
count++;
break;
case 2: fscanf(infile, "%f,%f,%f]",
&mesh.polys[count].fNormal3f.x,
&mesh.polys[count].fNormal3f.y,
&mesh.polys[count].fNormal3f.z);
count++;
break;
}
break;

case '#' :
if(mode == 4)
{
fscanf(infile, "{%i}", &mesh.polys[count].smoothgroup);
mesh.polys[count].smoothgroup--;
count++;
}
break;

default:
switch(mode)
{
case 3: fscanf(infile, "%i", &mesh.polys[count].matid);
mesh.polys[count].matid--;
count++;
break;
}
}
}

int x=0;

for(x=0; x<mesh.NumFace; x++)
{
mesh.polys[x].v1.x = Vert[mesh.polys[x].vert_face_ind.x].x;
mesh.polys[x].v1.y = Vert[mesh.polys[x].vert_face_ind.x].y;
mesh.polys[x].v1.z = Vert[mesh.polys[x].vert_face_ind.x].z;

mesh.polys[x].v2.x = Vert[mesh.polys[x].vert_face_ind.x].x;
mesh.polys[x].v2.y = Vert[mesh.polys[x].vert_face_ind.x].y;
mesh.polys[x].v2.z = Vert[mesh.polys[x].vert_face_ind.x].z;

mesh.polys[x].v3.x = Vert[mesh.polys[x].vert_face_ind.x].x;
mesh.polys[x].v3.y = Vert[mesh.polys[x].vert_face_ind.x].y;
mesh.polys[x].v3.z = Vert[mesh.polys[x].vert_face_ind.x].z;
}

/*printf("vertices:\n");
for(x=0; x<mesh.NumVert; x++)
printf("%f %f %f\n", Vert[x].Vertex3f.x, Vert[x].Vertex3f.y, Vert[x].Vertex3f.z);
printf("indices:\n");
for(x=0; x<mesh.NumFace; x++)
printf("%i %i %i\n", Face[x].x, Face[x].y, Face[x].z);
printf("face normals:\n");
for(x=0; x<mesh.NumFace; x++)
printf("%f %f %f\n", mesh.polys[x].fNormal3f.x, mesh.polys[x].fNormal3f.y, mesh.polys[x].fNormal3f.z);
printf("matid:\n");
for(x=0; x<mesh.NumFace; x++)
printf("%i ", mesh.polys[x].matid);
printf("\nsmoothgroups:\n");
for(x=0; x<mesh.NumFace; x++)
printf("%i ", mesh.polys[x].smoothgroup);
printf("\n");*/


fclose(infile);

CalVertexNormals();

return true;
}



im having a bit of a problem with it too. when i run the program it goes through the entire thing but crashes on exit. any ideas? could it just be my compiler? a corrupt file somewhere?

enigma:
i tried the templates and they work, im just not big on having to type out and entire sentence to get to a fwe bytes of data.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this