# HG changeset patch # User John Tsiombikas # Date 1394339278 -7200 # Node ID f3ddb2bb702496b9e0aaa210f099e5c23f5915ba first 3dfx glide test, initial commit diff -r 000000000000 -r f3ddb2bb7024 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sun Mar 09 06:27:58 2014 +0200 @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include "mesh.h" + +#define XSZ 640 +#define YSZ 480 + +void display(unsigned int msec); +void process_vertex(Vertex *vres, const Vertex &vin); +void draw_mesh(const std::vector &varr); +void draw_triangle(const Vertex *v); + +unsigned int start_time; +Matrix4x4 mv_matrix, proj_matrix, norm_matrix; +Vector4 mat_diffuse; +Vector3 light_dir; +std::vector torus; + +int main(void) +{ + GrHwConfiguration hwcfg; + + if(!grSstQueryBoards(&hwcfg)) { + fprintf(stderr, "No 3dfx graphics boards detected!\n"); + return 1; + } + printf("Found %d 3dfx graphics boards!\n", hwcfg.num_sst); + + grGlideInit(); + if(!grSstQueryHardware(&hwcfg)) { + fprintf(stderr, "No 3dfx graphics hardware detected!\n"); + return 1; + } + grSstSelect(0); + + if(!grSstWinOpen(0, GR_RESOLUTION_640x480, GR_REFRESH_60Hz, GR_COLORFORMAT_RGBA, + GR_ORIGIN_UPPER_LEFT, 2, 1)) { + fprintf(stderr, "Failed to initialize glide device\n"); + return 1; + } + + printf("Voodoo graphics initialized sucessfully!\n"); + + // setup projection matrix + proj_matrix.perspective(45.0f, 1.3333333f, 0.5, 250.0); + + // generate torus mesh + gen_torus(torus, 1.5, 0.5, 24, 12); + + // light + light_dir = normalize(Vector3(-0.6f, 1.0f, 2.0f)); + + // enable W-buffer (depth buffer) + grDepthBufferMode(GR_DEPTHBUFFER_WBUFFER); + grDepthMask(1); + grDepthBufferFunction(GR_CMP_LESS); + + // main loop + start_time = GetTickCount(); + unsigned int msec = 0; + while((msec = GetTickCount() - start_time) < 8000) { + display(msec); + } + + grGlideShutdown(); + return 0; +} + +void display(unsigned int msec) +{ + float t = (float)msec / 1000.0f; + + grBufferClear(0x103060ff, 255, GR_WDEPTHVALUE_FARTHEST); + + mv_matrix.set_identity(); + mv_matrix.translate(0, 0, -8); + mv_matrix.rotate(t * 100.0f, 1, 0, 0); + mv_matrix.rotate(t * 80.0f, 0, 0, 1); + + norm_matrix = mv_matrix; + norm_matrix[0][3] = norm_matrix[1][3] = norm_matrix[2][3] = 0.0f; + norm_matrix[3][0] = norm_matrix[3][1] = norm_matrix[3][2] = 0.0f; + norm_matrix[3][3] = 1.0f; + + mat_diffuse = Vector4(1.0f, 0.6f, 0.2f, 1.0f); + draw_mesh(torus); + + grBufferSwap(1); +} + + +void process_vertex(Vertex *vres, const Vertex &vin) +{ + // transform with the modelview matrix + vres->pos = transform(vin.pos, mv_matrix); + vres->normal = transform(vin.normal, norm_matrix); + + // calculate lighting + float ndotl = dot(vres->normal, light_dir); + if(ndotl < 0.0) ndotl = 0.0; + + Vector3 vdir(0, 0, 1); + Vector3 half_dir = normalize(vdir + light_dir); + float ndoth = dot(vres->normal, half_dir); + if(ndoth < 0.0) ndoth = 0.0; + float spec = pow(ndoth, 32.0); + + float red = mat_diffuse.x * ndotl + spec; + float green = mat_diffuse.y * ndotl + spec; + float blue = mat_diffuse.z * ndotl + spec; + + + vres->color.x = red > 1.0 ? 1.0 : red; + vres->color.y = green > 1.0 ? 1.0 : green; + vres->color.z = blue > 1.0 ? 1.0 : blue; + vres->color.w = mat_diffuse.w; + + + // transform with the projection matrix + vres->pos = transform(vres->pos, proj_matrix); + + // perspective division + vres->pos.x = vres->pos.x / vres->pos.w; + vres->pos.y = vres->pos.y / vres->pos.w; + vres->pos.z = vres->pos.z / vres->pos.w; + + // viewport transformation + vres->pos.x = (vres->pos.x * 0.5 + 0.5) * (float)XSZ; + vres->pos.y = (vres->pos.y * 0.5 + 0.5) * (float)YSZ; +} + + +void draw_mesh(const std::vector &varr) +{ + static Vertex face_vert[3]; + size_t num = varr.size(); + + int face_vert_idx = 0; + + for(int i=0; i= 3) { + draw_triangle(face_vert); + face_vert_idx = 0; + } + } +} + +void draw_triangle(const Vertex *v) +{ + GrVertex face[3]; + + for(int i=0; i<3; i++) { + face[i].x = v[i].pos.x; + face[i].y = v[i].pos.y; + face[i].r = v[i].color.x * 255.0; + face[i].g = v[i].color.y * 255.0; + face[i].b = v[i].color.z * 255.0; + face[i].a = v[i].color.w * 255.0; + face[i].oow = 1.0f / v[i].pos.w; + } + + grDrawTriangle(face, face + 1, face + 2); +} \ No newline at end of file diff -r 000000000000 -r f3ddb2bb7024 matrix.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/matrix.h Sun Mar 09 06:27:58 2014 +0200 @@ -0,0 +1,111 @@ +#ifndef MATRIX_H_ +#define MATRIX_H_ + +#define _USE_MATH_DEFINES +#include + +#ifndef M_PI +#define M_PI 3.14159265359 +#endif + +class Matrix4x4 { +public: + float m[4][4]; + + inline Matrix4x4() + { + *this = Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } + + inline Matrix4x4(float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) + { + m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03; + m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13; + m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23; + m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33; + } + + friend inline Matrix4x4 operator *(const Matrix4x4 &a, const Matrix4x4 &b); + + inline void set_identity() + { + *this = Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); + } + + inline void translate(float x, float y, float z) + { + *this = *this * Matrix4x4(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1); + } + + inline void scale(float x, float y, float z) + { + *this = *this * Matrix4x4(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1); + } + + inline void rotate(float angle, float x, float y, float z) + { + float rad = M_PI * angle / 180.0; + float sina = (float)sin(rad); + float cosa = (float)cos(rad); + float invcosa = 1.0f - cosa; + float nxsq = x * x; + float nysq = y * y; + float nzsq = z * z; + + Matrix4x4 xform; + xform[0][0] = nxsq + (1.0f - nxsq) * cosa; + xform[0][1] = x * y * invcosa - z * sina; + xform[0][2] = x * z * invcosa + y * sina; + xform[1][0] = x * y * invcosa + z * sina; + xform[1][1] = nysq + (1.0f - nysq) * cosa; + xform[1][2] = y * z * invcosa - x * sina; + xform[2][0] = x * z * invcosa - y * sina; + xform[2][1] = y * z * invcosa + x * sina; + xform[2][2] = nzsq + (1.0f - nzsq) * cosa; + *this = *this * xform; + } + + inline void perspective(float vfov_deg, float aspect, float znear, float zfar) + { + float vfov_rad = M_PI * vfov_deg / 180.0; + float f = 1.0f / tan(vfov_rad * 0.5f); + float dz = znear - zfar; + + Matrix4x4 xform; + xform[0][0] = f / aspect; + xform[1][1] = f; + xform[2][2] = (zfar + znear) / dz; + xform[3][2] = -1.0f; + xform[2][3] = 2.0f * zfar * znear / dz; + xform[3][3] = 0.0f; + *this = *this * xform; + } + + inline float *operator [](int idx) + { + return m[idx]; + } + + inline const float *operator[](int idx) const + { + return m[idx]; + } +}; + +inline Matrix4x4 operator *(const Matrix4x4 &a, const Matrix4x4 &b) +{ + Matrix4x4 res; + + for(int i=0; i<4; i++) { + for(int j=0; j<4; j++) { + res.m[i][j] = a.m[i][0] * b.m[0][j] + a.m[i][1] * b.m[1][j] + a.m[i][2] * b.m[2][j] + a.m[i][3] * b.m[3][j]; + } + } + return res; +} + + +#endif // MATRIX_H_ \ No newline at end of file diff -r 000000000000 -r f3ddb2bb7024 mesh.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mesh.cpp Sun Mar 09 06:27:58 2014 +0200 @@ -0,0 +1,66 @@ +#define _USE_MATH_DEFINES +#include +#include "mesh.h" + +#ifndef M_PI +#define M_PI 3.14159265359 +#endif + +void gen_sphere(std::vector &varr, float rad, int usub, int vsub) +{ +} + +static void torus_vertex(Vertex *vert, float u, float v, float rad, float tube_rad) +{ + float theta = 2.0 * M_PI * u; + float phi = 2.0 * M_PI * v; + + float x = 0.0f; + float y = sin(phi) * tube_rad; + float z = cos(phi) * tube_rad + rad; + + vert->pos.x = z * sin(theta); + vert->pos.y = y; + vert->pos.z = -x * sin(theta) + z * cos(theta); + vert->pos.w = 1.0; + + Vector3 cent; + cent.x = sin(theta) * rad; + cent.z = cos(theta) * rad; + + vert->normal = normalize(Vector3(vert->pos) - cent); + vert->color = Vector4(1.0, 1.0, 1.0, 1.0); +} + +void gen_torus(std::vector &varr, float rad, float tube_rad, int usub, int vsub) +{ + int i, j; + + if(usub < 3) usub = 3; + if(vsub < 3) vsub = 3; + + float du = 1.0f / (float)usub; + float dv = 1.0f / (float)vsub; + + + for(i=0; i +#include "vmath.h" + +struct Vertex { + Vector4 pos; + Vector4 color; + Vector3 normal; +}; + + +void gen_sphere(std::vector &varr, float rad, int usub, int vsub); +void gen_torus(std::vector &varr, float rad, float tube_rad, int usub, int vsub); + + +#endif // MESH_H_ \ No newline at end of file diff -r 000000000000 -r f3ddb2bb7024 test1.dsp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test1.dsp Sun Mar 09 06:27:58 2014 +0200 @@ -0,0 +1,118 @@ +# Microsoft Developer Studio Project File - Name="test1" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=test1 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "test1.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "test1.mak" CFG="test1 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "test1 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "test1 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "test1 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G5 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "__MSC__" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glide2x.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "test1 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /G5 /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "__MSC__" /FR /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib glide2x.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "test1 - Win32 Release" +# Name "test1 - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\main.cpp +# End Source File +# Begin Source File + +SOURCE=.\mesh.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\matrix.h +# End Source File +# Begin Source File + +SOURCE=.\mesh.h +# End Source File +# Begin Source File + +SOURCE=.\vmath.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff -r 000000000000 -r f3ddb2bb7024 test1.dsw --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test1.dsw Sun Mar 09 06:27:58 2014 +0200 @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "test1"=.\test1.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff -r 000000000000 -r f3ddb2bb7024 vmath.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vmath.h Sun Mar 09 06:27:58 2014 +0200 @@ -0,0 +1,261 @@ +#ifndef VMATH_H_ +#define VMATH_H_ + +#include +#include "matrix.h" + +class Vector4; + +class Vector3 { +public: + float x, y, z; + + Vector3() : x(0), y(0), z(0) {} + Vector3(float xx, float yy, float zz) : x(xx), y(yy), z(zz) {} + explicit inline Vector3(const Vector4 &v); + + inline float &operator [](int idx) + { + switch(idx) { + case 0: + return x; + case 1: + return y; + case 2: + default: + return z; + } + } + + inline const float &operator [](int idx) const + { + switch(idx) { + case 0: + return x; + case 1: + return y; + case 2: + default: + return z; + } + } + + inline float length() const + { + return sqrt(x * x + y * y + z * z); + } + + inline void normalize() + { + float len = length(); + if(len != 0) { + x /= len; + y /= len; + z /= len; + } + } +}; + +inline Vector3 operator +(const Vector3 &a, const Vector3 &b) +{ + return Vector3(a.x + b.x, a.y + b.y, a.z + b.z); +} + +inline Vector3 operator -(const Vector3 &a, const Vector3 &b) +{ + return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +inline Vector3 operator *(const Vector3 &a, const Vector3 &b) +{ + return Vector3(a.x * b.x, a.y * b.y, a.z * b.z); +} + +inline Vector3 operator *(const Vector3 &v, float s) +{ + return Vector3(v.x * s, v.y * s, v.z * s); +} + +inline Vector3 operator *(float s, const Vector3 &v) +{ + return Vector3(v.x * s, v.y * s, v.z * s); +} + +inline Vector3 operator /(const Vector3 &a, const Vector3 &b) +{ + return Vector3(a.x / b.x, a.y / b.y, a.z / b.z); +} + +inline Vector3 operator /(const Vector3 &v, float s) +{ + return Vector3(v.x / s, v.y / s, v.z / s); +} + +inline float dot(const Vector3 &a, const Vector3 &b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +inline Vector3 cross(const Vector3 &a, const Vector3 &b) +{ + return Vector3(a.y * b.z - a.z * b.y, + a.z * b.x - a.x * b.z, + a.x * b.y - a.y * b.z); +} + + +inline float length(const Vector3 &v) +{ + return sqrt(v.x * v.x + v.y * v.y + v.z * v.z); +} + +inline float length_sq(const Vector3 &v) +{ + return v.x * v.x + v.y * v.y + v.z * v.z; +} + +inline Vector3 normalize(const Vector3 &v) +{ + float len = length(v); + float s = len == 0 ? 1.0 : 1.0 / len; + return v * s; +} + +inline Vector3 transform(const Vector3 &v, const Matrix4x4 &m) +{ + return Vector3( + m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3], + m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3], + m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3]); +} + + +// ---- Vector4 ---- +class Vector4 { +public: + float x, y, z, w; + + Vector4() : x(0), y(0), z(0), w(1) {} + Vector4(float xx, float yy, float zz, float ww = 1.0f) : x(xx), y(yy), z(zz), w(ww) {} + explicit Vector4(const Vector3 &v) : x(v.x), y(v.y), z(v.z), w(1.0f) {} + + inline float &operator [](int idx) + { + switch(idx) { + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + case 3: + return w; + } + } + + inline const float &operator [](int idx) const + { + switch(idx) { + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + default: + return w; + } + } + + inline float length() const + { + return sqrt(x * x + y * y + z * z + w * w); + } + + inline void normalize() + { + float len = length(); + if(len != 0) { + x /= len; + y /= len; + z /= len; + w /= len; + } + } +}; + +inline Vector4 operator +(const Vector4 &a, const Vector4 &b) +{ + return Vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} + +inline Vector4 operator -(const Vector4 &a, const Vector4 &b) +{ + return Vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} + +inline Vector4 operator *(const Vector4 &a, const Vector4 &b) +{ + return Vector4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); +} + +inline Vector4 operator *(const Vector4 &v, float s) +{ + return Vector4(v.x * s, v.y * s, v.z * s, v.w * s); +} + +inline Vector4 operator *(float s, const Vector4 &v) +{ + return Vector4(v.x * s, v.y * s, v.z * s, v.w * s); +} + +inline Vector4 operator /(const Vector4 &a, const Vector4 &b) +{ + return Vector4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} + +inline Vector4 operator /(const Vector4 &v, float s) +{ + return Vector4(v.x / s, v.y / s, v.z / s, v.w / s); +} + +inline float dot(const Vector4 &a, const Vector4 &b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; +} + +inline float length(const Vector4 &v) +{ + return sqrt(v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w); +} + +inline float length_sq(const Vector4 &v) +{ + return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w; +} + +inline Vector4 normalize(const Vector4 &v) +{ + float len = length(v); + float s = len == 0 ? 1.0 : 1.0 / len; + return v * s; +} + +inline Vector4 transform(const Vector4 &v, const Matrix4x4 &m) +{ + return Vector4( + m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w, + m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w, + m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w, + m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] * v.w); +} + +inline Vector3::Vector3(const Vector4 &v) + : x(v.x), y(v.y), z(v.z) +{ +} + + +#endif // VMATH_H_ \ No newline at end of file