# HG changeset patch # User John Tsiombikas # Date 1435469664 -10800 # Node ID b1a195c3ee1689b84e6e425082079c3459a20b47 # Parent 283eb6e9f0a37475f5ba0fea81c896bf6e7245a5 added shaders diff -r 283eb6e9f0a3 -r b1a195c3ee16 Makefile --- a/Makefile Sun Jun 28 07:44:23 2015 +0300 +++ b/Makefile Sun Jun 28 08:34:24 2015 +0300 @@ -1,11 +1,13 @@ PREFIX ?= /usr/local src = $(wildcard src/*.cc) -obj = $(src:.cc=.o) +csrc = $(wildcard src/*.c) +obj = $(src:.cc=.o) $(csrc:.c=.o) dep = $(obj:.o=.d) bin = tavli +CFLAGS = -pedantic -Wall -g CXXFLAGS = -pedantic -Wall -g LDFLAGS = $(libgl) -lvmath -limago -lm -lpthread @@ -20,6 +22,9 @@ -include $(dep) +%.d: %.c + @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ + %.d: %.cc @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@ diff -r 283eb6e9f0a3 -r b1a195c3ee16 sdr/phong-notex.p.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr/phong-notex.p.glsl Sun Jun 28 08:34:24 2015 +0300 @@ -0,0 +1,24 @@ +/* vi: set ft=glsl */ +varying vec3 vdir, ldir, normal; + +#define KD gl_FrontMaterial.diffuse.rgb +#define KS gl_FrontMaterial.specular.rgb +#define SPOW gl_FrontMaterial.shininess + +void main() +{ + vec3 n = normalize(normal); + vec3 v = normalize(vdir); + vec3 l = normalize(ldir); + vec3 h = normalize(l + v); + + float ndotl = max(dot(n, l), 0.0); + float ndoth = max(dot(n, h), 0.0); + + vec3 diffuse = KD * gl_LightSource[0].diffuse.rgb * ndotl; + vec3 specular = KS * gl_LightSource[0].specular.rgb * pow(ndoth, SPOW); + + vec3 ambient = gl_LightModel.ambient.rgb * KD; + gl_FragColor.rgb = ambient + diffuse + specular; + gl_FragColor.a = gl_FrontMaterial.diffuse.a; +} diff -r 283eb6e9f0a3 -r b1a195c3ee16 sdr/phong.p.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr/phong.p.glsl Sun Jun 28 08:34:24 2015 +0300 @@ -0,0 +1,29 @@ +/* vi: set ft=glsl */ +uniform sampler2D tex; + +varying vec3 vdir, ldir, normal; + +#define KD gl_FrontMaterial.diffuse.rgb +#define KS gl_FrontMaterial.specular.rgb +#define SPOW gl_FrontMaterial.shininess + +void main() +{ + vec4 texel = texture2D(tex, gl_TexCoord[0].st); + + vec3 n = normalize(normal); + vec3 v = normalize(vdir); + vec3 l = normalize(ldir); + vec3 h = normalize(l + v); + + float ndotl = max(dot(n, l), 0.0); + float ndoth = max(dot(n, h), 0.0); + + vec3 albedo = KD * texel.rgb; + vec3 diffuse = albedo * gl_LightSource[0].diffuse.rgb * ndotl; + vec3 specular = KS * gl_LightSource[0].specular.rgb * pow(ndoth, SPOW); + + vec3 ambient = gl_LightModel.ambient.rgb * albedo; + gl_FragColor.rgb = ambient + diffuse + specular; + gl_FragColor.a = gl_FrontMaterial.diffuse.a * texel.a; +} diff -r 283eb6e9f0a3 -r b1a195c3ee16 sdr/phong.v.glsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdr/phong.v.glsl Sun Jun 28 08:34:24 2015 +0300 @@ -0,0 +1,12 @@ +varying vec3 vdir, ldir, normal; + +void main() +{ + gl_Position = ftransform(); + + vec3 vpos = (gl_ModelViewMatrix * gl_Vertex).xyz; + normal = gl_NormalMatrix * gl_Normal; + vdir = -vpos; + ldir = gl_LightSource[0].position.xyz - vpos; + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; +} diff -r 283eb6e9f0a3 -r b1a195c3ee16 src/board.cc --- a/src/board.cc Sun Jun 28 07:44:23 2015 +0300 +++ b/src/board.cc Sun Jun 28 08:34:24 2015 +0300 @@ -221,6 +221,7 @@ opiece->mtl.diffuse = Vector3(0.6, 0.6, 0.6); opiece->mtl.specular = Vector3(0.8, 0.8, 0.8); opiece->xform().set_translation(Vector3(0, 0.2, 0)); + opiece->set_shader(sdr_phong_notex); obj.push_back(opiece); // meshgen stats diff -r 283eb6e9f0a3 -r b1a195c3ee16 src/game.cc --- a/src/game.cc Sun Jun 28 07:44:23 2015 +0300 +++ b/src/game.cc Sun Jun 28 08:34:24 2015 +0300 @@ -3,10 +3,12 @@ #include "game.h" #include "board.h" #include "scenery.h" +#include "sdr.h" static void draw_backdrop(); int win_width, win_height; +unsigned int sdr_phong, sdr_phong_notex; bool wireframe; static Board board; @@ -15,6 +17,7 @@ static bool bnstate[8]; static int prev_x, prev_y; +static bool dbg_busyloop; bool game_init() { @@ -28,6 +31,15 @@ glEnable(GL_MULTISAMPLE); } + Mesh::use_custom_sdr_attr = false; + + if(!(sdr_phong = create_program_load("sdr/phong.v.glsl", "sdr/phong.p.glsl"))) { + return false; + } + if(!(sdr_phong_notex = create_program_load("sdr/phong.v.glsl", "sdr/phong-notex.p.glsl"))) { + return false; + } + if(!board.init()) { return false; } @@ -59,12 +71,16 @@ glRotatef(cam_phi, 1, 0, 0); glRotatef(cam_theta, 0, 1, 0); - float ldir[] = {-1, 2, 1, 0}; + float ldir[] = {-10, 20, 10, 1}; glLightfv(GL_LIGHT0, GL_POSITION, ldir); draw_backdrop(); draw_scenery(); board.draw(); + + if(dbg_busyloop) { + redisplay(); + } } static void draw_backdrop() @@ -117,6 +133,11 @@ wireframe = !wireframe; redisplay(); break; + + case 'd': + dbg_busyloop = !dbg_busyloop; + redisplay(); + break; } } } diff -r 283eb6e9f0a3 -r b1a195c3ee16 src/game.h --- a/src/game.h Sun Jun 28 07:44:23 2015 +0300 +++ b/src/game.h Sun Jun 28 08:34:24 2015 +0300 @@ -2,6 +2,7 @@ #define GAME_H_ extern int win_width, win_height; +extern unsigned int sdr_phong, sdr_phong_notex; extern bool wireframe; diff -r 283eb6e9f0a3 -r b1a195c3ee16 src/mesh.cc --- a/src/mesh.cc Sun Jun 28 07:44:23 2015 +0300 +++ b/src/mesh.cc Sun Jun 28 08:34:24 2015 +0300 @@ -8,6 +8,7 @@ #define USE_OLDGL +bool Mesh::use_custom_sdr_attr = true; int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 }; /* (int)SDR_ATTR_VERTEX, @@ -574,7 +575,7 @@ return; } - if(cur_sdr) { + if(cur_sdr && use_custom_sdr_attr) { // rendering with shaders if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) { fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__); @@ -623,7 +624,7 @@ glDrawArrays(GL_TRIANGLES, 0, nverts); } - if(cur_sdr) { + if(cur_sdr && use_custom_sdr_attr) { // rendered with shaders for(int i=0; itex = tex; } +void Object::set_shader(unsigned int sdr) +{ + this->sdr = sdr; +} + void Object::draw() const { if(!mesh) return; @@ -73,6 +79,10 @@ glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT); rop.setup(); + if(sdr) { + glUseProgram(sdr); + } + if(tex) { glBindTexture(GL_TEXTURE_2D, tex); glEnable(GL_TEXTURE_2D); @@ -103,6 +113,10 @@ glPopMatrix(); } + if(sdr) { + glUseProgram(0); + } + glMatrixMode(GL_MODELVIEW); glPopMatrix(); diff -r 283eb6e9f0a3 -r b1a195c3ee16 src/object.h --- a/src/object.h Sun Jun 28 07:44:23 2015 +0300 +++ b/src/object.h Sun Jun 28 08:34:24 2015 +0300 @@ -27,6 +27,7 @@ Matrix4x4 matrix; unsigned int tex; Matrix4x4 tex_matrix; + unsigned int sdr; public: Material mtl; @@ -45,6 +46,7 @@ Mesh *get_mesh() const; void set_texture(unsigned int tex); + void set_shader(unsigned int sdr); void draw() const; void draw_wire(const Vector4 &col = Vector4(1, 1, 1, 1)) const; diff -r 283eb6e9f0a3 -r b1a195c3ee16 src/scenery.cc --- a/src/scenery.cc Sun Jun 28 07:44:23 2015 +0300 +++ b/src/scenery.cc Sun Jun 28 08:34:24 2015 +0300 @@ -7,6 +7,7 @@ #include "object.h" #include "revol.h" #include "image.h" +#include "sdr.h" static bool gen_textures(); @@ -18,9 +19,9 @@ {3, 0}, // mid 0 {5.8, 0}, {5.99, 0}, // mid 1 - {6, -0.15}, - {6.15, -0.15}, // mid 2 - {6.2, -0.4} + {6, -0.1}, + {6.1, -0.1}, // mid 2 + {6.13, -0.3} }; static const BezCurve table_curve = { sizeof table_cp / sizeof *table_cp, @@ -39,7 +40,7 @@ Matrix4x4 xform; Mesh *table = new Mesh; - gen_revol(table, 48, 12, bezier_revol, bezier_revol_normal, (void*)&table_curve); + gen_revol(table, 48, 16, bezier_revol, bezier_revol_normal, (void*)&table_curve); table->texcoord_gen_plane(Vector3(0, 1, 0), Vector3(1, 0, 0)); xform.set_scaling(Vector3(0.5, 0.5, 0.5)); xform.translate(Vector3(1, 1, 0)); @@ -51,10 +52,11 @@ Object *otable = new Object; otable->set_mesh(table); - otable->mtl.diffuse = Vector3(0.6, 0.6, 0.6); - otable->mtl.specular = Vector3(0.8, 0.8, 0.8); + otable->mtl.diffuse = Vector3(1, 1, 1); + otable->mtl.specular = Vector3(0.7, 0.7, 0.7); otable->xform().set_translation(Vector3(0, -0.025, 0)); otable->set_texture(img_marble.texture()); + otable->set_shader(sdr_phong); obj.push_back(otable); @@ -113,7 +115,7 @@ float u = (float)j / (float)img_marble.width; float marble_val = marble(u, v); - Vector3 color = lerp(marble_col2, marble_col1, marble_val); + Vector3 color = lerp(marble_col2, marble_col1, marble_val) * 0.6; int r = (int)(color.x * 255.0); int g = (int)(color.y * 255.0); diff -r 283eb6e9f0a3 -r b1a195c3ee16 src/sdr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sdr.c Sun Jun 28 08:34:24 2015 +0300 @@ -0,0 +1,407 @@ +#include +#include +#include +#include +#include +#include +#include "opengl.h" + +#if defined(unix) || defined(__unix__) +#include +#include +#endif /* unix */ + +#include "sdr.h" + +static const char *sdrtypestr(unsigned int sdrtype); + +unsigned int create_vertex_shader(const char *src) +{ + return create_shader(src, GL_VERTEX_SHADER); +} + +unsigned int create_pixel_shader(const char *src) +{ + return create_shader(src, GL_FRAGMENT_SHADER); +} + +unsigned int create_tessctl_shader(const char *src) +{ +#ifdef GL_TESS_CONTROL_SHADER + return create_shader(src, GL_TESS_CONTROL_SHADER); +#else + return 0; +#endif +} + +unsigned int create_tesseval_shader(const char *src) +{ +#ifdef GL_TESS_EVALUATION_SHADER + return create_shader(src, GL_TESS_EVALUATION_SHADER); +#else + return 0; +#endif +} + +unsigned int create_geometry_shader(const char *src) +{ +#ifdef GL_GEOMETRY_SHADER + return create_shader(src, GL_GEOMETRY_SHADER); +#else + return 0; +#endif +} + +unsigned int create_shader(const char *src, unsigned int sdr_type) +{ + unsigned int sdr; + int success, info_len; + char *info_str = 0; + GLenum err; + + sdr = glCreateShader(sdr_type); + assert(glGetError() == GL_NO_ERROR); + glShaderSource(sdr, 1, &src, 0); + err = glGetError(); + assert(err == GL_NO_ERROR); + glCompileShader(sdr); + assert(glGetError() == GL_NO_ERROR); + + glGetShaderiv(sdr, GL_COMPILE_STATUS, &success); + assert(glGetError() == GL_NO_ERROR); + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); + assert(glGetError() == GL_NO_ERROR); + + if(info_len) { + if((info_str = malloc(info_len + 1))) { + glGetShaderInfoLog(sdr, info_len, 0, info_str); + assert(glGetError() == GL_NO_ERROR); + info_str[info_len] = 0; + } + } + + if(success) { + fprintf(stderr, info_str ? "done: %s\n" : "done\n", info_str); + } else { + fprintf(stderr, info_str ? "failed: %s\n" : "failed\n", info_str); + glDeleteShader(sdr); + sdr = 0; + } + + free(info_str); + return sdr; +} + +void free_shader(unsigned int sdr) +{ + glDeleteShader(sdr); +} + +unsigned int load_vertex_shader(const char *fname) +{ + return load_shader(fname, GL_VERTEX_SHADER); +} + +unsigned int load_pixel_shader(const char *fname) +{ + return load_shader(fname, GL_FRAGMENT_SHADER); +} + +unsigned int load_tessctl_shader(const char *fname) +{ +#ifdef GL_TESS_CONTROL_SHADER + return load_shader(fname, GL_TESS_CONTROL_SHADER); +#else + return 0; +#endif +} + +unsigned int load_tesseval_shader(const char *fname) +{ +#ifdef GL_TESS_EVALUATION_SHADER + return load_shader(fname, GL_TESS_EVALUATION_SHADER); +#else + return 0; +#endif +} + +unsigned int load_geometry_shader(const char *fname) +{ +#ifdef GL_GEOMETRY_SHADER + return load_shader(fname, GL_GEOMETRY_SHADER); +#else + return 0; +#endif +} + +unsigned int load_shader(const char *fname, unsigned int sdr_type) +{ + unsigned int sdr; + size_t filesize; + FILE *fp; + char *src; + + if(!(fp = fopen(fname, "rb"))) { + fprintf(stderr, "failed to open shader %s: %s\n", fname, strerror(errno)); + return 0; + } + + fseek(fp, 0, SEEK_END); + filesize = ftell(fp); + fseek(fp, 0, SEEK_SET); + + if(!(src = malloc(filesize + 1))) { + fclose(fp); + return 0; + } + fread(src, 1, filesize, fp); + src[filesize] = 0; + fclose(fp); + + fprintf(stderr, "compiling %s shader: %s... ", sdrtypestr(sdr_type), fname); + sdr = create_shader(src, sdr_type); + + free(src); + return sdr; +} + + +/* ---- gpu programs ---- */ + +unsigned int create_program(void) +{ + unsigned int prog = glCreateProgram(); + assert(glGetError() == GL_NO_ERROR); + return prog; +} + +unsigned int create_program_link(unsigned int sdr0, ...) +{ + unsigned int prog, sdr; + va_list ap; + + if(!(prog = create_program())) { + return 0; + } + + attach_shader(prog, sdr0); + if(glGetError()) { + return 0; + } + + va_start(ap, sdr0); + while((sdr = va_arg(ap, unsigned int))) { + attach_shader(prog, sdr); + if(glGetError()) { + return 0; + } + } + va_end(ap); + + if(link_program(prog) == -1) { + free_program(prog); + return 0; + } + return prog; +} + +unsigned int create_program_load(const char *vfile, const char *pfile) +{ + unsigned int vs = 0, ps = 0; + + if(vfile && *vfile && !(vs = load_vertex_shader(vfile))) { + return 0; + } + if(pfile && *pfile && !(ps = load_pixel_shader(pfile))) { + return 0; + } + return create_program_link(vs, ps, 0); +} + +void free_program(unsigned int sdr) +{ + glDeleteProgram(sdr); +} + +void attach_shader(unsigned int prog, unsigned int sdr) +{ + int err; + + if(prog && sdr) { + assert(glGetError() == GL_NO_ERROR); + glAttachShader(prog, sdr); + if((err = glGetError()) != GL_NO_ERROR) { + fprintf(stderr, "failed to attach shader %u to program %u (err: 0x%x)\n", sdr, prog, err); + abort(); + } + } +} + +int link_program(unsigned int prog) +{ + int linked, info_len, retval = 0; + char *info_str = 0; + + glLinkProgram(prog); + assert(glGetError() == GL_NO_ERROR); + glGetProgramiv(prog, GL_LINK_STATUS, &linked); + assert(glGetError() == GL_NO_ERROR); + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); + assert(glGetError() == GL_NO_ERROR); + + if(info_len) { + if((info_str = malloc(info_len + 1))) { + glGetProgramInfoLog(prog, info_len, 0, info_str); + assert(glGetError() == GL_NO_ERROR); + info_str[info_len] = 0; + } + } + + if(linked) { + fprintf(stderr, info_str ? "linking done: %s\n" : "linking done\n", info_str); + } else { + fprintf(stderr, info_str ? "linking failed: %s\n" : "linking failed\n", info_str); + retval = -1; + } + + free(info_str); + return retval; +} + +int bind_program(unsigned int prog) +{ + GLenum err; + + glUseProgram(prog); + if(prog && (err = glGetError()) != GL_NO_ERROR) { + /* maybe the program is not linked, try linking first */ + if(err == GL_INVALID_OPERATION) { + if(link_program(prog) == -1) { + return -1; + } + glUseProgram(prog); + return glGetError() == GL_NO_ERROR ? 0 : -1; + } + return -1; + } + return 0; +} + +/* ugly but I'm not going to write the same bloody code over and over */ +#define BEGIN_UNIFORM_CODE \ + int loc, curr_prog; \ + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); \ + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { \ + return -1; \ + } \ + if((loc = glGetUniformLocation(prog, name)) != -1) + +#define END_UNIFORM_CODE \ + if((unsigned int)curr_prog != prog) { \ + bind_program(curr_prog); \ + } \ + return loc == -1 ? -1 : 0 + +int set_uniform_int(unsigned int prog, const char *name, int val) +{ + BEGIN_UNIFORM_CODE { + glUniform1i(loc, val); + } + END_UNIFORM_CODE; +} + +int set_uniform_float(unsigned int prog, const char *name, float val) +{ + BEGIN_UNIFORM_CODE { + glUniform1f(loc, val); + } + END_UNIFORM_CODE; +} + +int set_uniform_float2(unsigned int prog, const char *name, float x, float y) +{ + BEGIN_UNIFORM_CODE { + glUniform2f(loc, x, y); + } + END_UNIFORM_CODE; +} + +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z) +{ + BEGIN_UNIFORM_CODE { + glUniform3f(loc, x, y, z); + } + END_UNIFORM_CODE; +} + +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w) +{ + BEGIN_UNIFORM_CODE { + glUniform4f(loc, x, y, z, w); + } + END_UNIFORM_CODE; +} + +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat) +{ + BEGIN_UNIFORM_CODE { + glUniformMatrix4fv(loc, 1, GL_FALSE, mat); + } + END_UNIFORM_CODE; +} + +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat) +{ + BEGIN_UNIFORM_CODE { + glUniformMatrix4fv(loc, 1, GL_TRUE, mat); + } + END_UNIFORM_CODE; +} + +int get_attrib_loc(unsigned int prog, const char *name) +{ + int loc, curr_prog; + + glGetIntegerv(GL_CURRENT_PROGRAM, &curr_prog); + if((unsigned int)curr_prog != prog && bind_program(prog) == -1) { + return -1; + } + + loc = glGetAttribLocation(prog, (char*)name); + + if((unsigned int)curr_prog != prog) { + bind_program(curr_prog); + } + return loc; +} + +void set_attrib_float3(int attr_loc, float x, float y, float z) +{ + glVertexAttrib3f(attr_loc, x, y, z); +} + +static const char *sdrtypestr(unsigned int sdrtype) +{ + switch(sdrtype) { + case GL_VERTEX_SHADER: + return "vertex"; + case GL_FRAGMENT_SHADER: + return "pixel"; +#ifdef GL_TESS_CONTROL_SHADER + case GL_TESS_CONTROL_SHADER: + return "tessellation control"; +#endif +#ifdef GL_TESS_EVALUATION_SHADER + case GL_TESS_EVALUATION_SHADER: + return "tessellation evaluation"; +#endif +#ifdef GL_GEOMETRY_SHADER + case GL_GEOMETRY_SHADER: + return "geometry"; +#endif + + default: + break; + } + return ""; +} diff -r 283eb6e9f0a3 -r b1a195c3ee16 src/sdr.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sdr.h Sun Jun 28 08:34:24 2015 +0300 @@ -0,0 +1,52 @@ +#ifndef SDR_H_ +#define SDR_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* ---- shaders ---- */ +unsigned int create_vertex_shader(const char *src); +unsigned int create_pixel_shader(const char *src); +unsigned int create_tessctl_shader(const char *src); +unsigned int create_tesseval_shader(const char *src); +unsigned int create_geometry_shader(const char *src); +unsigned int create_shader(const char *src, unsigned int sdr_type); +void free_shader(unsigned int sdr); + +unsigned int load_vertex_shader(const char *fname); +unsigned int load_pixel_shader(const char *fname); +unsigned int load_tessctl_shader(const char *fname); +unsigned int load_tesseval_shader(const char *fname); +unsigned int load_geometry_shader(const char *fname); +unsigned int load_shader(const char *src, unsigned int sdr_type); + +int add_shader(const char *fname, unsigned int sdr); +int remove_shader(const char *fname); + +/* ---- gpu programs ---- */ +unsigned int create_program(void); +unsigned int create_program_link(unsigned int sdr0, ...); +unsigned int create_program_load(const char *vfile, const char *pfile); +void free_program(unsigned int sdr); + +void attach_shader(unsigned int prog, unsigned int sdr); +int link_program(unsigned int prog); +int bind_program(unsigned int prog); + +int set_uniform_int(unsigned int prog, const char *name, int val); +int set_uniform_float(unsigned int prog, const char *name, float val); +int set_uniform_float2(unsigned int prog, const char *name, float x, float y); +int set_uniform_float3(unsigned int prog, const char *name, float x, float y, float z); +int set_uniform_float4(unsigned int prog, const char *name, float x, float y, float z, float w); +int set_uniform_matrix4(unsigned int prog, const char *name, float *mat); +int set_uniform_matrix4_transposed(unsigned int prog, const char *name, float *mat); + +int get_attrib_loc(unsigned int prog, const char *name); +void set_attrib_float3(int attr_loc, float x, float y, float z); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* SDR_H_ */