I have a template and two Vector classes below, one crazy, one sane. The template implements a simple fixed at compile time array of values. It is designed for subclassing and uses a protected array variable to avoid you having to jump through hoops to access the array. (Some folks might not like such a design. I say, if your subclasses are calling your overloaded operators, coupling might be a good idea.)
The crazy class allows you to have member variables called x, y, z and it acts like an array for calls to glGetFloatV. The sane one just has accessor functions x(), y(), z() and still works with glGetFloatV. You can use either class as a basis for other vector objects you might pass to the OpenGL library. Although the classes below are specific to points, you can obviously just do a search/replace to turn them into a rgb color classes.
The crazy class is crazy because the cost of the syntactic sugar vec.x instead of vec.x() is 3 reference variables. That could take up a lot of space in a large application. Use the simpler sane version.
template <typename T, int N>
class FixedVector {
protected:
T arr[N];
public:
FixedVector();
FixedVector(const T* a) {
for (int i = 0; i < N; ++i) {
arr[i] = a[i];
}
}
FixedVector(const T& other) {
for (int i = 0; i < N; ++i) {
arr[i] = other.arr[i];
}
}
FixedVector& operator=(const T& other) {
for (int i = 0; i < N; ++i) {
arr[i] = other.arr[i];
}
return *this;
}
T* operator&() { return arr; }
const T* operator&() const { return arr; }
T& operator[](int ofs) {
assert(ofs >= 0 && ofs < N);
return arr[ofs];
}
const T& operator[](int ofs) const {
assert(ofs >= 0 && ofs < N);
return arr[ofs];
}
};
class CrazyPoint : public FixedVector<float, 3> {
public:
float &x, &y, &z;
CrazyPoint()
: x(arr[0]), y(arr[1]), z(arr[2])
{ arr[0] = arr[1] = arr[2] = 0.0; }
CrazyPoint(const float* a)
: x(arr[0]), y(arr[1]), z(arr[2])
{
arr[0] = a[0];
arr[1] = a[1];
arr[2] = a[2];
}
CrazyPoint(float a, float b, float c)
: x(a), y(b), z(c)
{
arr[0] = a;
arr[1] = b;
arr[2] = c;
}
};
class SanePoint : public FixedVector<float, 3> {
public:
float& x() { return arr[0]; }
float& y() { return arr[1]; }
float& z() { return arr[2]; }
SanePoint() { arr[0] = arr[1] = arr[2] = 0.0; }
SanePoint(float a, float b, float c)
{
arr[0] = a;
arr[1] = b;
arr[2] = c;
}
};
// usage
SanePoint normal;
glGetFloatV(GL_CURRENT_NORMAL, &normal);