// Header
class CVector
{
private:
void sub();
public:
GLfloat x;
GLfloat y;
GLfloat z;
VERTEX3fv data;
// ructors
CVector(GLfloat x=0, GLfloat y=0, GLfloat z=0) : x(x), y(y), z(z) { sub(); }
CVector(CVector &V) : x(V.x), y(V.y), z(V.z) { sub();}
CVector& operator = (CVector& V);
GLfloat *GetData();
// Boolean stuff
bool operator == (CVector& Vector);
bool operator != (CVector& Vector);
// Add & Substract, Positive & Negative
CVector operator + (CVector& Vector);
CVector operator + ();
CVector& operator += (CVector& Vector);
// minus vector
CVector operator - (CVector& Vector);
CVector operator - ();
CVector &operator -= (CVector& Vector);
// Multiply & Divide
CVector operator * (CVector& Vector);
CVector& operator *= (CVector& Vector);
CVector operator * (GLfloat d);
CVector& operator *= (GLfloat d);
CVector operator / (CVector& Vector);
CVector &operator /= (CVector& Vector);
CVector operator / (GLfloat d);
CVector& operator /= (GLfloat d);
bool operator > (CVector& Vector);
bool operator < (CVector& Vector);
// Dot Product
GLfloat operator % (CVector& Vector);
// Cross Product
CVector operator ^ (CVector& Vector);
CVector& operator ^= (CVector& Vector);
// Set length (Normalize if 1) or Magnitude of vector
GLfloat operator ! ();
CVector operator | (GLfloat dLength);
CVector& operator |= (GLfloat dLength);
void Normalize();
void SetNormal(CVector vTriangle0, CVector vTriangle1, CVector vTriangle2 );
// The angle between two vectors in radians
GLfloat Angle(CVector& Normal);
// Reflect in Normal Vector
CVector Reflection(CVector& PlaneNormal);
// Rotate dAngle Degrees (radians) Around Normal
CVector Rotate(GLfloat dAngle, CVector& Normal);
// More Advanced Functions
GLfloat PlaneDistance(CVector Normal, CVector Point);
// Is Plane intersected?
bool IntersectedPlane(CVector vTriangle[], CVector vLine[]);
};
// Source
/* --------------------------------- VECTOR IMPLEMENTATION -------------------------------//
//----------------------------------------------------------------------------------------*/
CVector& CVector::operator = (CVector& V)
{ x = V.x;
y = V.y;
z = V.z;
sub();
return *this;
}
// Boolean stuff
bool CVector::operator == (CVector& Vector)
{ return (x == Vector.x && y == Vector.y && z == Vector.z);
}
bool CVector::operator != (CVector& Vector)
{ return !(*this == Vector);
}
// Add & Substract, Positive & Negative
CVector CVector::operator + (CVector& Vector)
{ return CVector(x + Vector.x, y + Vector.y, z + Vector.z);
}
CVector CVector::operator + ()
{ return CVector(*this);
}
CVector& CVector::operator += (CVector& Vector)
{ x += Vector.x;
y += Vector.y;
z += Vector.z;
sub();
return *this;
}
// minus vector
CVector CVector::operator - (CVector& Vector)
{ return CVector(x - Vector.x, y - Vector.y, z - Vector.z);
}
CVector CVector::operator - ()
{ return CVector(-x, -y, -z);
}
CVector &CVector::operator -= (CVector& Vector)
{ x -= Vector.x;
y -= Vector.y;
z -= Vector.z;
sub();
return *this;
}
// Multiply & Divide
CVector CVector::operator * (CVector& Vector)
{ return CVector(x * Vector.x, y * Vector.y, z * Vector.z);
}
CVector &CVector::operator *= (CVector& Vector)
{ x *= Vector.x;
y *= Vector.y;
z *= Vector.z;
sub();
return *this;
}
CVector CVector::operator * (GLfloat d)
{ return CVector(x * d, y * d, z * d);
}
CVector &CVector::operator *= (GLfloat d)
{ x *= d;
y *= d;
z *= d;
sub();
return *this;
}
CVector CVector::operator / (CVector& Vector)
{ return CVector(x / Vector.x, y / Vector.y, z / Vector.z);
}
CVector &CVector::operator /= (CVector& Vector)
{ x /= Vector.x;
y /= Vector.y;
z /= Vector.z;
sub();
return *this;
}
CVector CVector::operator / (GLfloat d)
{ GLfloat _d = 1.0f / d;
return CVector(x * _d, y * _d, z * _d);
}
CVector &CVector::operator /= (GLfloat d)
{ GLfloat _d = 1.0f / d;
x *= _d;
y *= _d;
z *= _d;
sub();
return *this;
}
// Dot Product
GLfloat CVector::operator % (CVector& Vector)
{ return x*Vector.x + y*Vector.y + z*Vector.z;
}
// Cross Product
CVector CVector::operator ^ (CVector& Vector)
{ return CVector(
y * Vector.z - Vector.y * z,
z * Vector.x - Vector.z * x,
x * Vector.y - Vector.x * y);
}
CVector &CVector::operator ^= (CVector& Vector)
{ return *this = *this ^ Vector;
}
bool CVector::operator > (CVector& v)
{
return (x>v.x || y>v.y || z>v.z);
}
bool CVector::operator < (CVector& v)
{
return (x<v.x || y<v.y || z<v.z);
}
// Set length (Normalize if 1) or Magnitude of vector
GLfloat CVector::operator ! ()
{ return sqrtf(x*x + y*y + z*z);
}
CVector CVector::operator | (GLfloat dLength)
{ return *this * (dLength / !*this);
}
CVector &CVector::operator |= (GLfloat dLength)
{ return *this = *this | dLength;
}
void CVector::Normalize()
{
GLfloat magnitude=!*this;
*this/=magnitude;
}
void CVector::SetNormal(CVector vTriangle0, CVector vTriangle1, CVector vTriangle2 )
{
*this = (vTriangle2-vTriangle0)^(vTriangle1-vTriangle0); // Cross Product
this->Normalize(); // Use our function we created to normalize the normal (Makes it a length of one)
}
// The angle between two vectors in radians
GLfloat CVector::Angle(CVector& Normal)
{ return acosf(*this % Normal);
}
// Reflect in Normal Vector
CVector CVector::Reflection(CVector& PlaneNormal)
{ return (*this - PlaneNormal * 2.0 * (*this % PlaneNormal)) * !*this;
}
// Rotate dAngle Degrees (radians) Around Normal
CVector CVector::Rotate(GLfloat dAngle, CVector& Normal)
{ GLfloat dCos = cosf(dAngle);
GLfloat dSin = sinf(dAngle);
return CVector(
*this * dCos +
((Normal * *this) * (1.0f - dCos)) * Normal +
(*this ^ Normal) * dSin);
}
GLfloat *CVector::GetData()
{ return data; }
void CVector::sub()
{
data[0] = x;
data[1] = y;
data[2] = z;
}
/* -------------------------------END VECTOR IMPLEMENTATION ------------------------------//
//----------------------------------------------------------------------------------------*/
Lets make a game...
What came to my mind, is maybe we can start making a game here?
For example, we can post some useful code and how it''s going to be used in the engine, and then after all we can combine that code for ,say, next tutorial on game-making?
Here''s my first addition to this topic - CVector class:
" Do we need us? "
OK, a forum is not the best place to start a project such as this one, we need a proper server and CVS. It could be a theme site, but it has to be properly commented and stepped through. Im up for it, i reckon i have stuff to offer, so feel free to sort out the proper details before we get started.
Hey man,
I was talking about giving your code to public so they can use it in their projects.
I don''t know about CVS (repository), but SourceForge offers it (although I don''t know how to use it)
Would you like to start that kind of thing with me?
I got HEAPS of useful code that I don''t really use for game creation, so I thought maybe someone else can make the game using this code? )
Thanks.
" Do we need us? "
I was talking about giving your code to public so they can use it in their projects.
I don''t know about CVS (repository), but SourceForge offers it (although I don''t know how to use it)
Would you like to start that kind of thing with me?
I got HEAPS of useful code that I don''t really use for game creation, so I thought maybe someone else can make the game using this code? )
Thanks.
" Do we need us? "
About your code:
On my computer, 10000000 calls to sqrt() takes 1.98 seconds, where 10000000 calls to sqrtf() takes 3.08 seconds, a fairly large difference. conclusion: sqrt() is better.
Also, in your functions where you calculate the reciprocal, you''re not using the initial value again so you can avoid creating a new variable _d by just doing d = 1 / d; then multiplying by d.
And you''d get another speed boost by getting rid of that sub() thing, I don''t see why you need the vars in array form =)
On my computer, 10000000 calls to sqrt() takes 1.98 seconds, where 10000000 calls to sqrtf() takes 3.08 seconds, a fairly large difference. conclusion: sqrt() is better.
Also, in your functions where you calculate the reciprocal, you''re not using the initial value again so you can avoid creating a new variable _d by just doing d = 1 / d; then multiplying by d.
And you''d get another speed boost by getting rid of that sub() thing, I don''t see why you need the vars in array form =)
Thanks Hairybudda, I''ll consider changing that. As for sub(), its just that I didn''t knew about unions. E.g
" Do we need us? "
union{struct{float x;float y;float z;};float data[3];}Thanks.
" Do we need us? "
I'd like to make a couple of comments about the CVector class you've written (I'm not 'having a go', just passing on years of experience).
Firstly, it's generally regarded as good practice not to redefine the meaning of operators. By this I mean not changing the 'XOR' operator into something else. The reason for this is that anyone not familiar with your implementation would expect 'a ^= b' to actually be 'a = a xor b' rather than a cross product. Worse still, you can't change the precedence of the operator - does a cross product have higher or lower precedence than the '+', or other, operator (mathematically speaking, it should be higher). So, for example, you might be tempted to do the following:
CVector a,b,c;
// assign values to a,b,c
if (a > b ^ c)
{
// do stuff
}
This will generate a compiler error, complaining that there is no definition of the '^' operator that takes the given arguments (in this case: bool, CVector).
All because you can do something in C++, doesn't mean it's a good idea.
Secondly, member variables should be private. There's no reason here to expose them.
Thirdly, I'm assuming the 'source' bit would be in a '.cpp', otherwise you'd get multiple definitions of functions (in MSVC V6 at least). This will lead to inefficient code since none of it would be inlined, even with every inline option switched on it would never be inlined apart from the '.cpp' file containing the CVector source. This is because the translation unit processing a source file that includes the CVector class does not have the code in the implementation to hand to do the inlining (because it would be in another translation unit). And the linker wouldn't inline it since that would screw up all the relative jumps in the code. For a class this simple, put the code in the class declaration.
Fourth, I would personally have called the class CVector3D, so you can then have CVector2D and CVector4D. It would also eliminate any potential user confusion that the class may be implementing a custom 'std::vector' type. Also, using a single 'C' prefix could clash with the MFC classes (game objects defined as CObject?). Use a namespace or use a different prefix to avoid any potential problems (a problem prevented won't become a problem).
Lastly, I wrote a 3D vector class but declared it as a template so I could have vectors of floats, doubles, ints, bytes, etc.(bytes is useful to save disk space - quantize model data to 256 samples in x, y and z - saves 9 bytes per vertex!).
Skizz
[edited by - Skizz on February 3, 2003 6:17:52 AM]
Firstly, it's generally regarded as good practice not to redefine the meaning of operators. By this I mean not changing the 'XOR' operator into something else. The reason for this is that anyone not familiar with your implementation would expect 'a ^= b' to actually be 'a = a xor b' rather than a cross product. Worse still, you can't change the precedence of the operator - does a cross product have higher or lower precedence than the '+', or other, operator (mathematically speaking, it should be higher). So, for example, you might be tempted to do the following:
CVector a,b,c;
// assign values to a,b,c
if (a > b ^ c)
{
// do stuff
}
This will generate a compiler error, complaining that there is no definition of the '^' operator that takes the given arguments (in this case: bool, CVector).
All because you can do something in C++, doesn't mean it's a good idea.
Secondly, member variables should be private. There's no reason here to expose them.
Thirdly, I'm assuming the 'source' bit would be in a '.cpp', otherwise you'd get multiple definitions of functions (in MSVC V6 at least). This will lead to inefficient code since none of it would be inlined, even with every inline option switched on it would never be inlined apart from the '.cpp' file containing the CVector source. This is because the translation unit processing a source file that includes the CVector class does not have the code in the implementation to hand to do the inlining (because it would be in another translation unit). And the linker wouldn't inline it since that would screw up all the relative jumps in the code. For a class this simple, put the code in the class declaration.
Fourth, I would personally have called the class CVector3D, so you can then have CVector2D and CVector4D. It would also eliminate any potential user confusion that the class may be implementing a custom 'std::vector' type. Also, using a single 'C' prefix could clash with the MFC classes (game objects defined as CObject?). Use a namespace or use a different prefix to avoid any potential problems (a problem prevented won't become a problem).
Lastly, I wrote a 3D vector class but declared it as a template so I could have vectors of floats, doubles, ints, bytes, etc.(bytes is useful to save disk space - quantize model data to 256 samples in x, y and z - saves 9 bytes per vertex!).
Skizz
[edited by - Skizz on February 3, 2003 6:17:52 AM]
Hello,
It''s not a nice thing to involve openGL specific types in a semi-generic vector class. I suggest you change them to floats instead.
Regards,
Deficte
It''s not a nice thing to involve openGL specific types in a semi-generic vector class. I suggest you change them to floats instead.
Regards,
Deficte
Another criticism of your vector class is that the == and != operators won''t be very reliable since they''re comparing floating point values. Because of the way floating point values work (if you don''t know how they work I suggest you read up on them - check Google) comparing them directly is pretty foolish. A better approach for comparing two vectors would be to check the angle between them.
Also what''s the point of your operator + that takes no argument? It just seems to make a copy of a vector.
Also what''s the point of your operator + that takes no argument? It just seems to make a copy of a vector.
rm3: sqrtf is EXACTLY the same as a sqrt, except it casts to a float for you. If you set a float = sqrt that many times, and a float = sqrtf that many times.. they should be the same speed, just one gives a warning, and the other doesn''t. If you are using doubles... stick with the sqrt obviously .
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement