require "mspcore";
require "mspdatafile";
+ require "mspmath";
require "mspgui";
require "opengl";
}
// We must redo the base point correction since interpolation throws if off
+ // XXX This should probably be done on local matrices
Matrix result = iter->pose_matrices[link].get(time_since_keyframe/iter->delta_t);
const Vector3 &base = animation.armature->get_link(link).get_base();
Vector3 new_base = result*base;
- result = Matrix::translation(base.x-new_base.x, base.y-new_base.y, base.z-new_base.z)*result;
+ result = Matrix::translation(base-new_base)*result;
return result;
}
float l1 = 1, l2 = 1;
if(generate_tbn || tex_fit!=STRETCH)
{
- l1 = sqrt(s1.x*s1.x+s1.y*s1.y+s1.z*s1.z);
- l2 = sqrt(s2.x*s2.x+s2.y*s2.y+s2.z*s2.z);
+ l1 = s1.norm();
+ l2 = s2.norm();
}
if(generate_tbn)
{
- builder.tangent(s1.x/l1, s1.y/l1, s1.z/l1);
- builder.binormal(s2.x/l2, s2.y/l2, s2.z/l2);
+ builder.tangent(s1/l1);
+ builder.binormal(s2/l2);
}
float u_size = 1;
builder.begin(TRIANGLE_STRIP);
builder.texcoord(0, v_size);
- builder.vertex(o.x+s2.x, o.y+s2.y, o.z+s2.z);
+ builder.vertex(o+s2);
builder.texcoord(0, 0);
- builder.vertex(o.x, o.y, o.z);
+ builder.vertex(o);
builder.texcoord(u_size, v_size);
- builder.vertex(o.x+s1.x+s2.x, o.y+s1.y+s2.y, o.z+s1.z+s2.z);
+ builder.vertex(o+s1+s2);
builder.texcoord(u_size, 0);
- builder.vertex(o.x+s1.x, o.y+s1.y, o.z+s1.z);
+ builder.vertex(o+s1);
builder.end();
}
void Camera::set_up_direction(const Vector3 &u)
{
- float len = sqrt(u.x*u.x+u.y*u.y+u.z*u.z);
-
- up_dir.x = u.x/len;
- up_dir.y = u.y/len;
- up_dir.z = u.z/len;
+ up_dir = normalize(u);
compute_matrix();
}
void Camera::set_look_direction(const Vector3 &l)
{
- float len = sqrt(l.x*l.x+l.y*l.y+l.z*l.z);
-
- look_dir.x = l.x/len;
- look_dir.y = l.y/len;
- look_dir.z = l.z/len;
+ look_dir = normalize(l);
compute_matrix();
}
void Camera::look_at(const Vector3 &p)
{
- set_look_direction(Vector3(p.x-position.x, p.y-position.y, p.z-position.z));
+ set_look_direction(p-position);
}
Vector3 Camera::project(const Vector4 &p) const
float frustum_w = frustum_h*aspect;
float z_range = clip_far-clip_near;
- float eye_x = matrix[0]*p.x+matrix[4]*p.y+matrix[8]*p.z+matrix[12]*p.w;
- float eye_y = matrix[1]*p.x+matrix[5]*p.y+matrix[9]*p.z+matrix[13]*p.w;
- float eye_z = matrix[2]*p.x+matrix[6]*p.y+matrix[10]*p.z+matrix[14]*p.w;
+ Vector4 eye = matrix*p;
- return Vector3(eye_x/frustum_w/-eye_z, eye_y/frustum_h/-eye_z,
- (clip_far+clip_near)/z_range+2*clip_far*clip_near/(eye_z*z_range));
+ return Vector3(eye.x/frustum_w/-eye.z, eye.y/frustum_h/-eye.z,
+ (clip_far+clip_near)/z_range+2*clip_far*clip_near/(eye.z*z_range));
+}
+
+Vector3 Camera::project(const Vector3 &p) const
+{
+ return project(Vector4(p.x, p.y, p.z, 1.0));
}
Vector4 Camera::unproject(const Vector4 &p) const
void Camera::compute_matrix()
{
- float x = look_dir.y*up_dir.z-look_dir.z*up_dir.y;
- float y = look_dir.z*up_dir.x-look_dir.x*up_dir.z;
- float z = look_dir.x*up_dir.y-look_dir.y*up_dir.x;
- float len = sqrt(x*x+y*y+z*z);
+ Vector3 right_dir = normalize(cross(look_dir, up_dir));
double mdata[16];
- mdata[0] = x/len;
- mdata[4] = y/len;
- mdata[8] = z/len;
+ mdata[0] = right_dir.x;
+ mdata[4] = right_dir.y;
+ mdata[8] = right_dir.z;
- mdata[1] = mdata[4]*look_dir.z-mdata[8]*look_dir.y;
- mdata[5] = mdata[8]*look_dir.x-mdata[0]*look_dir.z;
- mdata[9] = mdata[0]*look_dir.y-mdata[4]*look_dir.x;
+ mdata[1] = right_dir.y*look_dir.z-right_dir.z*look_dir.y;
+ mdata[5] = right_dir.z*look_dir.x-right_dir.x*look_dir.z;
+ mdata[9] = right_dir.x*look_dir.y-right_dir.y*look_dir.x;
mdata[2] = -look_dir.x;
mdata[6] = -look_dir.y;
const Matrix &get_matrix() const { return matrix; }
Vector3 project(const Vector4 &) const;
+ Vector3 project(const Vector3 &) const;
Vector4 unproject(const Vector4 &) const;
void apply() const;
if(compute_normals)
{
- norm.x = side1.y*side2.z-side1.z*side2.y;
- norm.y = side1.z*side2.x-side1.x*side2.z;
- norm.z = side1.x*side2.y-side1.y*side2.x;
- float l = sqrt(norm.x*norm.x+norm.y*norm.y+norm.z*norm.z);
- norm.x /= l;
- norm.y /= l;
- norm.z /= l;
-
- binorm.x = norm.y*side1.z-norm.z*side1.y;
- binorm.y = norm.z*side1.x-norm.x*side1.z;
- binorm.z = norm.x*side1.y-norm.y*side1.x;
- l = sqrt(binorm.x*binorm.x+binorm.y*binorm.y+binorm.z*binorm.z);
- binorm.x /= l;
- binorm.y /= l;
- binorm.z /= l;
+ norm = normalize(cross(side1, side2));
+ binorm = normalize(cross(norm, side1));
}
}
void GridBuilder::build(PrimitiveBuilder &builder) const
{
- float l1_sq = side1.x*side1.x+side1.y*side1.y+side1.z*side1.z;
- float l2 = side2.x*binorm.x+side2.y*binorm.y+side2.z*binorm.z;
+ float l1_sq = dot(side1, side1);
+ float l2 = dot(side2, binorm);
float u_scale = 1/l1_sq;
float v_scale = 1/l2;
adjust_texture_scale(u_scale, v_scale, sqrt(l1_sq), l2);
builder.normal(norm.x, norm.y, norm.z);
if(generate_tbn)
{
- builder.tangent(side1.x, side1.y, side1.z);
- builder.binormal(binorm.x, binorm.y, binorm.z);
+ builder.tangent(side1);
+ builder.binormal(binorm);
}
for(unsigned j=0; j<=v_div; ++j)
{
- float v = j*1.0/v_div;
- Vector3 row(origin.x+side2.x*v, origin.y+side2.y*v, origin.z+side2.z*v);
- v = (row.x*binorm.x+row.y*binorm.y+row.z*binorm.z)*v_scale;
+ Vector3 row = origin+side2*(j*1.0f/v_div);
+ float v = dot(row, binorm)*v_scale;
for(unsigned i=0; i<=u_div; ++i)
{
- float u = i*1.0/u_div;
- Vector3 p(row.x+side1.x*u, row.y+side1.y*u, row.z+side1.z*u);
- u = (p.x*side1.x+p.y*side1.y+p.z*side1.z)*u_scale;
+ Vector3 p = row+side1*(i*1.0f/u_div);
+ float u = dot(p, side1)*u_scale;
builder.texcoord(u, v);
builder.vertex(p);
}
#include <algorithm>
#include <cmath>
+#include <msp/geometry/affinetransformation.h>
#include "error.h"
#include "matrix.h"
namespace GL {
Matrix::Matrix():
- flags(IDENTITY)
-{
- for(unsigned i=0; i<16; ++i)
- matrix[i] = (i%5 ? 0 : 1);
-}
+ Base(Base::identity())
+{ }
Matrix::Matrix(const float *m):
- flags(IDENTITY)
-{
- copy(m, m+16, matrix);
- check_flags();
-}
+ Base(LinAl::SquareMatrix<float, 4>(m))
+{ }
Matrix::Matrix(const double *m):
- flags(IDENTITY)
-{
- copy(m, m+16, matrix);
- check_flags();
-}
+ Base(m)
+{ }
-void Matrix::check_flags()
-{
- const double *m = matrix;
- if(m[12]!=0 || m[13]!=0 || m[14]!=0)
- flags |= TRANSLATE;
- if(m[0]!=1)
- {
- flags |= SCALE;
- if(m[5]!=m[0] || m[10]!=m[0])
- flags |= ARBITARY;
- }
- if(m[1]!=0 || m[2]!=0 || m[4]!=0 || m[6]!=0 || m[8]!=0 || m[9]!=0)
- {
- flags |= ROTATE;
- double x_dot_y = m[0]*m[1]+m[4]*m[5]+m[8]*m[9];
- double x_dot_z = m[0]*m[2]+m[4]*m[6]+m[8]*m[10];
- double y_dot_z = m[1]*m[2]+m[5]*m[6]+m[9]*m[10];
- if(x_dot_y!=0 || x_dot_z!=0 || y_dot_z!=0)
- flags |= ARBITARY;
- }
- if(m[3]!=0 || m[7]!=0 || m[11]!=0 || m[15]!=1)
- flags |= ARBITARY;
-}
+Matrix::Matrix(const LinAl::Matrix<double, 4, 4> &other):
+ Base(other)
+{ }
void Matrix::multiply(const Matrix &other)
{
*this = *this*other;
}
-void Matrix::translate(double x, double y, double z)
-{
- multiply(translation(x, y, z));
-}
-
-void Matrix::rotate(double a, double x, double y, double z)
+void Matrix::translate(const Vector3 &t)
{
- multiply(rotation(a, x, y, z));
+ multiply(translation(t));
}
-void Matrix::rotate_deg(double a, double x, double y, double z)
+void Matrix::rotate(const Angle &a, const Vector3 &x)
{
- multiply(rotation_deg(a, x, y, z));
+ multiply(rotation(a, x));
}
-void Matrix::scale(double s)
+void Matrix::scale(const Vector3 &s)
{
multiply(scaling(s));
}
-void Matrix::scale(double x, double y, double z)
-{
- multiply(scaling(x, y, z));
-}
-
Matrix Matrix::operator*(const Matrix &other) const
{
- if(flags==IDENTITY)
- return other;
- else if(other.flags==IDENTITY)
- return *this;
- else if(flags==TRANSLATE && !(other.flags&ARBITARY))
- {
- Matrix result = other;
- result.matrix[12] += matrix[12];
- result.matrix[13] += matrix[13];
- result.matrix[14] += matrix[14];
- result.flags |= flags;
- return result;
- }
- else if(!(flags&ARBITARY) && other.flags==TRANSLATE)
- {
- Matrix result = *this;
- const double *m = other.matrix;
- result.matrix[12] += matrix[0]*m[12]+matrix[4]*m[13]+matrix[8]*m[14];
- result.matrix[13] += matrix[1]*m[12]+matrix[5]*m[13]+matrix[9]*m[14];
- result.matrix[14] += matrix[2]*m[12]+matrix[6]*m[13]+matrix[10]*m[14];
- result.flags |= other.flags;
- return result;
- }
- else
- {
- Matrix result;
- fill(result.matrix, result.matrix+16, 0.0);
- for(unsigned i=0; i<4; ++i)
- for(unsigned j=0; j<4; ++j)
- for(unsigned k=0; k<4; ++k)
- result.matrix[i+j*4] += matrix[i+k*4]*other.matrix[k+j*4];
- result.flags = flags|other.flags;
- return result;
- }
+ return static_cast<const Base &>(*this)*static_cast<const Base &>(other);
}
Matrix &Matrix::operator*=(const Matrix &other)
Vector4 Matrix::operator*(const Vector4 &vec) const
{
- if(flags==IDENTITY)
- return vec;
- else if(flags==TRANSLATE)
- return Vector4(vec.x+vec.w*matrix[12], vec.y+vec.w*matrix[13], vec.z+vec.w*matrix[14], vec.w);
- else if(flags==SCALE)
- return Vector4(vec.x*matrix[0], vec.y*matrix[5], vec.z*matrix[10], vec.w);
- else
- {
- Vector4 result;
- result.x = vec.x*matrix[0]+vec.y*matrix[4]+vec.z*matrix[8]+vec.w*matrix[12];
- result.y = vec.x*matrix[1]+vec.y*matrix[5]+vec.z*matrix[9]+vec.w*matrix[13];
- result.z = vec.x*matrix[2]+vec.y*matrix[6]+vec.z*matrix[10]+vec.w*matrix[14];
- result.w = vec.x*matrix[3]+vec.y*matrix[7]+vec.z*matrix[11]+vec.w*matrix[15];
- return result;
- }
+ return static_cast<const Base &>(*this)*LinAl::Vector<double, 4>(vec);
}
-double Matrix::operator[](unsigned i) const
+Vector3 Matrix::operator*(const Vector3 &vec) const
{
- if(i>=16)
- throw out_of_range("Matrix::operator[]");
- return matrix[i];
+ return Geometry::reduce_vector((*this)*Geometry::augment_vector(vec, 1.0f));
}
-Matrix Matrix::translation(double x, double y, double z)
-{
- Matrix result;
- result.matrix[12] = x;
- result.matrix[13] = y;
- result.matrix[14] = z;
- result.flags |= TRANSLATE;
- return result;
-}
-
-Matrix Matrix::rotation(double a, double x, double y, double z)
+double Matrix::operator[](unsigned i) const
{
- double l = sqrt(x*x+y*y+z*z);
- x /= l;
- y /= l;
- z /= l;
- double c = cos(a);
- double s = sin(a);
-
- // http://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_given_an_axis_and_an_angle
- Matrix result;
- result.matrix[0] = c+x*x*(1-c);
- result.matrix[1] = y*x*(1-c)+z*s;
- result.matrix[2] = z*x*(1-c)-y*s;
- result.matrix[4] = x*y*(1-c)-z*s;
- result.matrix[5] = c+y*y*(1-c);
- result.matrix[6] = z*y*(1-c)+x*s;
- result.matrix[8] = x*z*(1-c)+y*s;
- result.matrix[9] = y*z*(1-c)-x*s;
- result.matrix[10] = c+z*z*(1-c);
- result.flags |= ROTATE;
- return result;
+ if(i>=16)
+ throw out_of_range("Matrix::operator[]");
+ return operator()(i%4, i/4);
}
-Matrix Matrix::rotation_deg(double a, double x, double y, double z)
+Matrix Matrix::translation(const Vector3 &t)
{
- return rotation(a*M_PI/180, x, y, z);
+ return Geometry::AffineTransformation<double, 3>::translation(t).get_matrix();
}
-Matrix Matrix::scaling(double s)
+Matrix Matrix::rotation(const Angle &a, const Vector3 &x)
{
- Matrix result;
- result.matrix[0] = s;
- result.matrix[5] = s;
- result.matrix[10] = s;
- result.flags |= SCALE;
- return result;
+ return Geometry::AffineTransformation<double, 3>::rotation(a, x).get_matrix();
}
-Matrix Matrix::scaling(double x, double y, double z)
+Matrix Matrix::scaling(const Vector3 &s)
{
- Matrix result;
- result.matrix[0] = x;
- result.matrix[5] = y;
- result.matrix[10] = z;
- result.flags |= SCALE|ARBITARY;
- return result;
+ return Geometry::AffineTransformation<double, 3>::scaling(s).get_matrix();
}
Matrix Matrix::ortho(double l, double r, double b, double t, double n, double f)
throw invalid_argument("Matrix::ortho");
Matrix result;
- result.matrix[0] = 2/(r-l);
- result.matrix[5] = 2/(t-b);
- result.matrix[10] = -2/(f-n);
- result.matrix[12] = -(r+l)/(r-l);
- result.matrix[13] = -(t+b)/(t-b);
- result.matrix[14] = -(f+n)/(f-n);
- result.flags = TRANSLATE|SCALE|ARBITARY;
+ result(0, 0) = 2/(r-l);
+ result(1, 1) = 2/(t-b);
+ result(2, 2) = -2/(f-n);
+ result(0, 3) = -(r+l)/(r-l);
+ result(1, 3) = -(t+b)/(t-b);
+ result(2, 3) = -(f+n)/(f-n);
return result;
}
throw invalid_argument("Matrix::frustum");
Matrix result;
- result.matrix[0] = 2*n/(r-l);
- result.matrix[5] = 2*n/(t-b);
- result.matrix[8] = (r+l)/(r-l);
- result.matrix[9] = (t+b)/(t-b);
- result.matrix[10] = -(f+n)/(f-n);
- result.matrix[11] = -1;
- result.matrix[14] = -2*f*n/(f-n);
- result.matrix[15] = 0;
- result.flags = ARBITARY;
+ result(0, 0) = 2*n/(r-l);
+ result(1, 1) = 2*n/(t-b);
+ result(0, 2) = (r+l)/(r-l);
+ result(1, 2) = (t+b)/(t-b);
+ result(2, 2) = -(f+n)/(f-n);
+ result(3, 2) = -1;
+ result(2, 3) = -2*f*n/(f-n);
+ result(3 ,3) = 0;
return result;
}
#define MSP_GL_MATRIX_H_
#include <vector>
+#include <msp/geometry/angle.h>
+#include <msp/linal/squarematrix.h>
#include "gl.h"
#include "vector.h"
namespace Msp {
namespace GL {
-class Matrix
+class Matrix: public LinAl::SquareMatrix<double, 4>
{
private:
- enum Flags
- {
- IDENTITY = 0,
- TRANSLATE = 1,
- ROTATE = 2,
- SCALE = 4,
- ARBITARY = 8
- };
-
- double matrix[16];
- unsigned flags;
+ typedef LinAl::SquareMatrix<double, 4> Base;
+ typedef Geometry::Angle<double> Angle;
public:
Matrix();
Matrix(const float *);
Matrix(const double *);
-private:
- void check_flags();
+ Matrix(const LinAl::Matrix<double, 4, 4> &);
-public:
- const double *data() const { return matrix; }
+ const double *data() const { return &Base::operator()(0, 0); }
void multiply(const Matrix &);
- void translate(double, double, double);
- void translate(const Vector3 &t) { translate(t.x, t.y, t.z); }
- void rotate(double, double, double, double);
- void rotate(double a, const Vector3 &x) { rotate(a, x.x, x.y, x.z); }
- void rotate_deg(double, double, double, double);
- void rotate_deg(double a, const Vector3 & x) { rotate_deg(a, x.x, x.y, x.z); }
- void scale(double);
- void scale(double, double, double);
+ void translate(double x, double y, double z) { translate(Vector3(x, y, z)); }
+ void translate(const Vector3 &);
+ void rotate(const Angle &, const Vector3 &);
+ void rotate(double a, double x, double y, double z) { rotate(Angle::from_radians(a), Vector3(x, y, z)); }
+ void rotate(double a, const Vector3 &x) { rotate(Angle::from_radians(a), x); }
+ void rotate_deg(double a, double x, double y, double z) { rotate(Angle::from_degrees(a), Vector3(x, y, z)); }
+ void rotate_deg(double a, const Vector3 & x) { rotate(Angle::from_degrees(a), x); }
+ void scale(double s) { scale(Vector3(s, s, s)); }
+ void scale(double x, double y, double z) { scale(Vector3(x, y, z)); }
+ void scale(const Vector3 &);
Matrix operator*(const Matrix &) const;
Matrix &operator*=(const Matrix &);
Vector4 operator*(const Vector4 &) const;
+ Vector3 operator*(const Vector3 &) const;
double operator[](unsigned) const;
- static Matrix translation(double, double, double);
- static Matrix translation(const Vector3 &t) { return translation(t.x, t.y, t.z); }
- static Matrix rotation(double, double, double, double);
- static Matrix rotation(double a, const Vector3 &x) { return rotation(a, x.x, x.y, x.z); }
- static Matrix rotation_deg(double, double, double, double);
- static Matrix rotation_deg(double a, const Vector3 &x) { return rotation_deg(a, x.x, x.y, x.z); }
- static Matrix scaling(double);
- static Matrix scaling(double, double, double);
+ static Matrix translation(double x, double y, double z) { return translation(Vector3(x, y, z)); }
+ static Matrix translation(const Vector3 &);
+ static Matrix rotation(const Angle &a, const Vector3 &);
+ static Matrix rotation(double a, double x, double y, double z) { return rotation(Angle::from_radians(a), Vector3(x, y, z)); }
+ static Matrix rotation(double a, const Vector3 &x) { return rotation(Angle::from_radians(a), x); }
+ static Matrix rotation_deg(double a, double x, double y, double z) { return rotation(Angle::from_degrees(a), Vector3(x, y, z)); }
+ static Matrix rotation_deg(double a, const Vector3 &x) { return rotation(Angle::from_degrees(a), x); }
+ static Matrix scaling(double s) { return scaling(Vector3(s, s, s)); }
+ static Matrix scaling(double x, double y, double z) { return scaling(Vector3(x, y, z)); }
+ static Matrix scaling(const Vector3 &);
static Matrix ortho(double, double, double, double, double, double);
static Matrix ortho_centered(double, double);
// Keep the base point stationary
Vector3 base = arm_link.get_base();
Vector3 new_base = links[i].local_matrix*base;
- links[i].local_matrix = GL::Matrix::translation(base.x-new_base.x, base.y-new_base.y, base.z-new_base.z)*links[i].local_matrix;
+ links[i].local_matrix = GL::Matrix::translation(base-new_base)*links[i].local_matrix;
if(const Armature::Link *parent = arm_link.get_parent())
links[i].matrix = links[parent->get_index()].matrix*links[i].local_matrix;
#include <map>
#include <msp/datafile/objectloader.h>
#include "program.h"
+#include "vector.h"
namespace Msp {
namespace GL {
class Matrix;
class Uniform;
class UniformBlock;
-class Vector3;
-class Vector4;
/**
Stores uniform variables for shader programs. The uniforms are stored in a
{
/* XXX Not really proper way to support positional lights, but good
enough when the light source is far away */
- lpos.x -= target.x;
- lpos.y -= target.y;
- lpos.z -= target.z;
+ lpos -= Vector4(target.x, target.y, target.z, 1.0f);
}
- float l = sqrt(lpos.x*lpos.x+lpos.y*lpos.y+lpos.z*lpos.z);
- lpos.x /= l;
- lpos.y /= l;
- lpos.z /= l;
+ lpos.normalize();
float matrix[16];
if(abs(lpos.z)>=abs(lpos.x) && abs(lpos.z)>=abs(lpos.y))
const Vector3 &fv = get_face_direction(face);
const Vector3 &sv = get_s_direction(face);
const Vector3 &tv = get_t_direction(face);
- return Vector3(fv.x+s*sv.x, fv.y+t*tv.y, fv.z+s*sv.z+t*tv.z);
+ return fv+s*sv+t*tv;
}
} // namespace GL
#include <vector>
#include "bufferable.h"
#include "program.h"
+#include "vector.h"
namespace Msp {
namespace GL {
class Color;
class Matrix;
class Uniform;
-class Vector3;
-class Vector4;
/**
Stores uniforms with a specific layout. Both named and default uniform blocks
#ifndef MSP_GL_VECTOR_H_
#define MSP_GL_VECTOR_H_
+#include <msp/linal/vector.h>
+
namespace Msp {
namespace GL {
-struct Vector4;
-
-struct Vector3
-{
- float x, y, z;
-
- Vector3(): x(0), y(0), z(0) { }
- Vector3(float x_, float y_, float z_): x(x_), y(y_), z(z_) { }
- Vector3(const Vector4 &);
-};
-
-struct Vector4
-{
- float x, y, z, w;
-
- Vector4(): x(0), y(0), z(0), w(1) { }
- Vector4(float x_, float y_, float z_): x(x_), y(y_), z(z_), w(1) { }
- Vector4(float x_, float y_, float z_, float w_): x(x_), y(y_), z(z_), w(w_) { }
- Vector4(const Vector3 &v): x(v.x), y(v.y), z(v.z), w(1) { }
-};
-
-inline Vector3::Vector3(const Vector4 &v):
- x(v.x/v.w), y(v.y/v.w), z(v.z/v.w)
-{ }
+typedef LinAl::Vector<float, 3> Vector3;
+typedef LinAl::Vector<float, 4> Vector4;
} // namespace GL
} // namespace Msp
void vertex(float x, float y, float z, float w)
{ vertex(Vector4(x, y, z, w)); }
+ void vertex(const Vector3 &v)
+ { vertex(Vector4(v.x, v.y, v.z, 1)); }
+
void vertex(const Vector4 &v)
{ vertex_(mtx.top()*v); }