Keeping synced glsl code and c++ code that ought to represent the same function

Viewed 101

I have the following challenge. I am doing a series of experiments in graphics where I need to author sdf functions. These functions must exist in glsl and c++ simultaneously for different purposes. Said otherwise, in both glsl and c++ there must be a function SdfFunction that computes the exact same SDF.

Current possible approaches:

  • Author the function twice by hand. This super slow and very prone to error.
  • Make a parser script that must be run to convert glsl code into C++ or vice versa. This suffers from only working at build time and needing an additional programming language (to make it portable).
  • Have the C++ code itself parse the files. Then compile a dynamic loaded library and link at runtime to the generated files. I have no idea how to actually do this one and it sounds very messy.

Do I have an alternative?

1 Answers

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));
    }
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
Related