I am using a bit different approach. I created GLSL_math.h template for CPU side C++ code with the same syntax and functionality as GLSL (swizzling included) so I can run the same math code on GLSL and CPU for debugging purposes. The template also contains local and global rotations which are not present in native GLSL (as I intended to use this also as replacement for my old reper and vector math classes and needed the functionality)
The template was done in Embarcadero (Borland) BDS2006 Turbo C++ so it might need some tweeking in different C++ IDE / compiler. Most of the code was autogenerated with function _vec_generate
which is included but commented out as it uses AnsiString which is not present outside VCL as coding this manually would be insane (~244KByte).
The texture access and stuff differences between CPU/GLSL I handle by macro statements like in here:
where only the macro differs for GLSL and CPU ...
This way I can use my C++ IDE debugging features like breakpoints, tracing, watches ... without which I would never accomplish more complex shaders like the raytracers through mesh or voxel maps ...
For cases when behavior differs (different FPU implementations or GLSL quirks and bugs related to drivers) I use this:
to directly print out sub-results from fragment shader
Here a sample test code in order to test the template operator syntax fuctionality (different compiler might need to change the operator header syntax slightly until it compiles):
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
template <class mat,class vec,class T> void test_operators_syntax()
{
mat m0,m1,m2;
vec v0,v1,v2;
T c1=1;
m0=+m1;
m0=-m1;
m0=m1*m2;
m0=c1*m1;
m0=m1*c1;
m0=m1/c1;
m0*=m1;
m0*=c1;
m0/=c1;
v0=m1*v1;
v0=m1*v1;
v0=m1*v1;
v0=+v1;
v0=-v1;
v0=v1++;
v0=++v1;
v0=v1--;
v0=--v1;
v0=v1+v2;
v0=v1-v2;
v0=v1*v2;
v0=v1/v2;
v0+=v1;
v0-=v1;
v0*=v1;
v0/=v1;
v0++=v1;
v0--=v1;
v0=c1+v1;
v0=c1-v1;
v0=c1*v1;
v0=v1+c1;
v0=v1-c1;
v0=v1*c1;
v0=v1/c1;
v0+=c1;
v0-=c1;
v0*=c1;
v0/=c1;
};
//---------------------------------------------------------------------------
void test_operators()
{
test_operators_syntax< mat2, vec2,float >(); vec2 v2= vec2(0.0,0.0); mat2 m2= mat2(0.0,0.0,0.0,0.0);
test_operators_syntax< mat3, vec3,float >(); vec3 v3= vec3(0.0,0.0,0.0); mat3 m3= mat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax< mat4, vec4,float >(); vec4 v4= vec4(0.0,0.0,0.0,0.0); mat4 m4= mat4(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax<dmat2,dvec2,double>(); dvec2 dv2=dvec2(0.0,0.0); dmat2 dm2=dmat2(0.0,0.0,0.0,0.0);
test_operators_syntax<dmat3,dvec3,double>(); dvec3 dv3=dvec3(0.0,0.0,0.0); dmat3 dm3=dmat3(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
test_operators_syntax<dmat4,dvec4,double>(); dvec4 dv4=dvec4(0.0,0.0,0.0,0.0); dmat4 dm4=dmat4(0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0);
m3=rotate(m3,15.0*deg,v2);
m4=rotate(m4,15.0*deg,v3,v3);
m3=grotz(m3,15.0*deg); m3=lrotz(m3,15.0*deg);
m4=grotx(m4,15.0*deg); m4=lrotx(m4,15.0*deg);
m4=groty(m4,15.0*deg); m4=lroty(m4,15.0*deg);
m4=grotz(m4,15.0*deg); m4=lrotz(m4,15.0*deg);
m2=inverse(m2); m2=inverse2(m2); m2=transpose(m2);
m3=inverse(m3); m3=inverse2(m3); m3=transpose(m3);
m4=inverse(m4); m4=inverse2(m4); m4=transpose(m4);
float f=1.0; f=max(0.0f,f); f=min(0.0f,f); f=abs(f);
double d=2.0; d=max(0.0 ,d); d=min(0.0 ,d); d=abs(d);
f=length(v2)+length2(v2)+dot(normalize(v2),cross(v2));
f=length(v3)+length2(v3)+dot(normalize(v3),cross(v3,v3));
f=length(v4)+length2(v4)+dot(normalize(v4),cross(v4,v4,v4));
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------