Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extracting type and offset from struct field in template

Tags:

d

Notice: even that my example are from OpenGL, this is not an OpenGL question, but general D question.

Background: In my gaming project, I have shader class to help interfacing to GLSL code. Setting uniforms work nicely:

uniform(string name, float value) --> glUniform1f(...)
uniform(string name, mat4 m) --> glUniformMatrix4fv( ...)
etc. etc.

That is, it chooses right function depending on the type of the parameter, and so when I modify my code, it automatically changes to use correct function (assuming that I don't have type conflicts between D and GLSL).

My troubles are implementing somewhat similar mechanism to bind attributes. I have VERTEX structure:

struct VERTEX { ...; vec3 pos; ... }

For binding attribute, in addition to know the type of the field, I need the offset, but I don't need the values. I managed to write clumpsy implementation, where call looks like:

vbo.attrib!(typeof(mesh.VERTEX.pos))("vert_pos", mesh.VERTEX.pos.offsetof);

And VBO.attrib is implemented like this:

void attrib(T: vec2)(string name, ulong offset) { /* 2 floats from offset */ }
void attrib(T: vec3)(string name, ulong offset) { /* 3 floats from offset */ }

Question: Is there a way to make this simpler and more elegant? Generally, I don't like duplicating the field when calling, that is, first extract the type to choose correct attrib binding function, and then separately send offset. I would like the function call look something like this:

vbo.attrib("vert_pos", mesh.VERTEX.pos);

...And the template to extract both type and offset from the argument. I have read D template guides and tutorials, but I have't yet figured out how to implement templates like that. Is it possible and how?

Clarification: I have a feeling that I'm already close, I just don't have enough imagination (and knowledge from D templates and mixins) to implement the first phase:

XXX(name, field)
--> some unknown magic
--> vbo.attrib!(typeof(field))(name,field.offsetof)
--> void attrib(T: vec2)(string name, ulong offset) { /* arguments for GL call */ }

EDIT: With mixins, I managed to make it look like this:

    template attrib(string name, string field)
    {
        const char[] attrib =
            "vbo.attrib!" ~
            "(typeof(" ~ field ~ "))" ~
            "(\"" ~ name ~ "\", " ~ field ~ ".offsetof);";
    }

    mixin(attrib!("vert_pos", "mesh.VERTEX.pos"));
    mixin(attrib!("vert_uv", "mesh.VERTEX.uv"));

To be honest, it (calling) looks even more complex to use than my current one, so I keep my current and look for nicer-looking solution.

like image 228
MaKo Avatar asked Dec 24 '14 19:12

MaKo


1 Answers

you are really very close to the solution. this works with DMD git head:

import std.stdio;

struct vec2 {
  float a, b;
}

struct vec3 {
  float a, b, c;
}

struct VERTEX {
  vec3 pos;
  vec2 uv;
}

void attrib(T: vec2) (string name, ulong offset) {
  writefln("vec2: name=%s; ofs=%s", name, offset);
}

void attrib(T: vec3) (string name, ulong offset) {
  writefln("vec3: name=%s; ofs=%s", name, offset);
}


static void attrib(string name, alias field) () {
  attrib!(typeof(field))(name, field.offsetof);
}


void main () {
  attrib!("vert_pos", VERTEX.pos); // outputs "vec3: name=vert_pos; ofs=0"
  attrib!("vert_uv", VERTEX.uv); // outputs: "vec2: name=vert_uv; ofs=12"
}

unfortunately i don't have official 2.066 release to check if it works with it. this will not work with 2.065 for sure, so you are out of luck with GDC (as it still using 2.065).

the trick is in static, which means "this template doesn't need any context".

p.s. just checked it, and yes, this works with 2.066 release.

like image 80
user4159958 Avatar answered Oct 22 '22 10:10

user4159958