evolving the basic gfx abstractions
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 2 Apr 2024 07:48:15 +0000 (10:48 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 2 Apr 2024 07:48:15 +0000 (10:48 +0300)
.gitignore
Makefile
src/gfx.h
src/gl/gfx_gl.c
src/gl/gfx_gl.h [new file with mode: 0644]
src/gl/opengl.c
src/gl/opengl.h
src/wsys/wsys_fglut.c
test.c
test.p.glsl [new file with mode: 0644]
test.v.glsl [new file with mode: 0644]

index 0497878..0f5c968 100644 (file)
@@ -5,3 +5,4 @@
 test
 compile_commands.json
 .cache/
+*.spv
index 27ec497..203d578 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,9 @@ src = $(wildcard src/*.c) $(wildcard src/gl/*.c) $(wildcard src/wsys/*.c) \
 obj = $(src:.c=.o)
 dep = $(src:.c=.d)
 
+sdr = test.v.glsl test.p.glsl
+spirv = $(sdr:.glsl=.spv)
+
 name = nexus3d
 liba = lib$(name).a
 
@@ -12,7 +15,10 @@ dbg = -g
 inc = -Isrc
 
 CFLAGS = $(warn) $(dbg) $(opt) $(inc) $(def) -MMD
-LDFLAGS = -lGL -lglut -lm
+LDFLAGS = -lGL -lglut -lGLEW -lm
+
+GLSLANG = glslangValidator
+
 
 test: test.o $(liba)
        $(CC) -o $@ test.o $(obj) $(liba) $(LDFLAGS)
@@ -22,6 +28,12 @@ $(liba): $(obj)
 
 -include $(dep)
 
+%.v.spv: %.v.glsl
+       $(GLSLANG) -G -S vert -o $@ $<
+
+%.p.spv: %.p.glsl
+       $(GLSLANG) -G -S frag -o $@ $<
+
 .PHONY: clean
 clean:
        rm -f $(obj) $(liba) test test.o
index beac8c1..5faf474 100644 (file)
--- a/src/gfx.h
+++ b/src/gfx.h
@@ -1,7 +1,80 @@
 #ifndef NEXUS3D_GFX_H_
 #define NEXUS3D_GFX_H_
 
+#include <stddef.h>
+
+enum nex_state_flags {
+       NEX_DEPTH_TEST          = 0x0001,
+       NEX_STENCIL_TEST        = 0x0002,
+       NEX_BLEND                       = 0x0004,
+};
+
+enum nex_vattr_type {
+       NEX_FLOAT,
+       NEX_VEC2, NEX_VEC3, NEX_VEC4,
+       NEX_COL3, NEX_COL4
+};
+
+enum nex_primitive {
+       NEX_POINTS,
+       NEX_LINES,
+       NEX_LINE_STRIP,
+       NEX_TRIANGLES,
+       NEX_TRIANGLE_STRIP,
+       NEX_TRIANGLE_FAN
+};
+
+enum nex_sdr_type {
+       NEX_SDR_VERTEX,
+       NEX_SDR_PIXEL
+};
+
+typedef struct nex_buffer nex_buffer;
+typedef struct nex_geometry nex_geometry;
+typedef struct nex_shader nex_shader;
+typedef struct nex_sdrprog nex_sdrprog;
+
 void nex_clear(void);
+void nex_clearcolor(float r, float g, float b);
+void nex_cleardepth(float z);
+void nex_clearstencil(unsigned int s);
+
 void nex_viewport(int x, int y, int w, int h);
 
+/* --- buffers and geometry --- */
+nex_buffer *nex_alloc_buffer(size_t sz, const void *data);
+void nex_free_buffer(nex_buffer *buf);
+nex_geometry *nex_alloc_geometry(void);
+void nex_free_geometry(nex_geometry *geom);
+
+void nex_geom_vbuffer(nex_geometry *geom, unsigned int bufid, const nex_buffer *buf,
+               unsigned int stride);
+void nex_geom_ibuffer(nex_geometry *geom, const nex_buffer *buf);
+void nex_geom_vattr(nex_geometry *geom, unsigned int attr,
+               enum nex_vattr_type type, int bufid, unsigned int offs);
+
+void nex_draw_geometry(const nex_geometry *geom, enum nex_primitive prim, unsigned int count);
+
+/* --- shaders --- */
+nex_shader *nex_alloc_shader(enum nex_sdr_type type);
+void nex_free_shader(nex_shader *sdr); /* refcounted */
+
+nex_sdrprog *nex_alloc_sdrprog(void);
+void nex_free_sdrprog(nex_sdrprog *prog);
+
+void nex_sdrname(nex_shader *sdr, const char *name);
+void nex_sdrsrc(nex_shader *sdr, const char *src);
+void nex_sdrbin(nex_shader *sdr, void *bin, size_t sz);
+
+void nex_sdrconst_int(nex_shader *sdr, int id, int val);
+void nex_sdrconst_float(nex_shader *sdr, int id, float val);
+int nex_build_shader(nex_shader *sdr);
+
+void nex_attach_shader(nex_sdrprog *prog, nex_shader *sdr);
+int nex_build_sdrprog(nex_sdrprog *prog);
+void nex_bind_sdrprog(nex_sdrprog *prog);
+
+nex_shader *nex_load_shader(const char *path, enum nex_sdr_type type);
+nex_sdrprog *nex_load_sdrprog(const char *vpath, const char *ppath);
+
 #endif /* NEXUS3D_GFX_H_ */
index 4156368..c0a830d 100644 (file)
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <alloca.h>
 #include "opengl.h"
 #include "nexus3d_impl.h"
+#include "gfx_gl.h"
 
 void nex_clear(void)
 {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 }
 
+void nex_clearcolor(float r, float g, float b)
+{
+       glClearColor(r, g, b, 1.0f);
+}
+
+void nex_cleardepth(float z)
+{
+       glClearDepth(z);
+}
+
+void nex_clearstencil(unsigned int s)
+{
+       glClearStencil(s);
+}
+
 void nex_viewport(int x, int y, int w, int h)
 {
        glViewport(x, y, w, h);
 }
+
+nex_buffer *nex_alloc_buffer(size_t sz, const void *data)
+{
+       nex_buffer *buf;
+
+       if(!(buf = malloc(sizeof *buf))) {
+               return 0;
+       }
+       glCreateBuffers(1, &buf->bo);
+       if(data) {
+               glNamedBufferStorage(buf->bo, sz, data, GL_DYNAMIC_STORAGE_BIT);
+       }
+
+       buf->size = sz;
+       return buf;
+}
+
+void nex_free_buffer(nex_buffer *buf)
+{
+       if(!buf) return;
+       glDeleteBuffers(1, &buf->bo);
+       free(buf);
+}
+
+nex_geometry *nex_alloc_geometry(void)
+{
+       nex_geometry *geom;
+
+       if(!(geom = calloc(1, sizeof *geom))) {
+               return 0;
+       }
+       glCreateVertexArrays(1, &geom->vao);
+       return geom;
+}
+
+void nex_free_geometry(nex_geometry *geom)
+{
+       if(!geom) return;
+       glDeleteVertexArrays(1, &geom->vao);
+       free(geom);
+}
+
+void nex_geom_vbuffer(nex_geometry *geom, unsigned int bufid, const nex_buffer *buf,
+               unsigned int stride)
+{
+       glVertexArrayVertexBuffer(geom->vao, bufid, buf->bo, 0, stride);
+
+       assert(bufid >= 0 && bufid < MAX_VAO_BUF);
+       geom->buf[bufid] = buf;
+}
+
+void nex_geom_ibuffer(nex_geometry *geom, const nex_buffer *buf)
+{
+       glVertexArrayElementBuffer(geom->vao, buf->bo);
+
+       geom->ibuf = buf;
+}
+
+static int attrnelem(enum nex_vattr_type atype)
+{
+       switch(atype) {
+       case NEX_FLOAT:
+               return 1;
+       case NEX_VEC2:
+               return 2;
+       case NEX_VEC3:
+       case NEX_COL3:
+               return 3;
+       case NEX_VEC4:
+       case NEX_COL4:
+               return 4;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int attrnorm(enum nex_vattr_type atype)
+{
+       return atype > NEX_COL3 ? 1 : 0;
+}
+
+static int attrsize(enum nex_vattr_type atype)
+{
+       switch(atype) {
+       case NEX_FLOAT:
+               return sizeof(float);
+       case NEX_VEC2:
+               return 2 * sizeof(float);
+       case NEX_VEC3:
+       case NEX_COL3:
+               return 3 * sizeof(float);
+       case NEX_VEC4:
+       case NEX_COL4:
+               return 4 * sizeof(float);
+       default:
+               break;
+       }
+       return 0;
+}
+
+void nex_geom_vattr(nex_geometry *geom, unsigned int attr, enum nex_vattr_type type,
+               int bufid, unsigned int offs)
+{
+       assert(attr >= 0 && attr < MAX_VAO_ATTR);
+
+       if(bufid >= 0) {
+               glVertexArrayAttribFormat(geom->vao, attr, attrnelem(type), GL_FLOAT,
+                               attrnorm(type), offs);
+               glVertexArrayAttribBinding(geom->vao, attr, bufid);
+               glEnableVertexArrayAttrib(geom->vao, attr);
+
+               assert(geom->buf[bufid]);
+               geom->attr[attr].type = type;
+               geom->attr[attr].bufid = bufid;
+               geom->attr[attr].size = attrsize(type);
+               /* XXX no attempt to validate equal vcount across all bound buffers */
+               geom->vcount = geom->buf[bufid]->size / geom->attr[attr].size;
+       } else {
+               glDisableVertexArrayAttrib(geom->vao, attr);
+               geom->attr[attr].bufid = 0;
+               geom->attr[attr].size = 0;
+       }
+}
+
+static unsigned int glprim(enum nex_primitive prim)
+{
+       switch(prim) {
+       case NEX_POINTS:
+               return GL_POINTS;
+       case NEX_LINES:
+               return GL_LINES;
+       case NEX_LINE_STRIP:
+               return GL_LINE_STRIP;
+       case NEX_TRIANGLES:
+               return GL_TRIANGLES;
+       case NEX_TRIANGLE_STRIP:
+               return GL_TRIANGLE_STRIP;
+       case NEX_TRIANGLE_FAN:
+               return GL_TRIANGLE_FAN;
+       default:
+               break;
+       }
+       return 0;
+}
+
+void nex_draw_geometry(const nex_geometry *geom, enum nex_primitive prim, unsigned int count)
+{
+       glBindVertexArray(geom->vao);
+       if(geom->ibuf) {
+               if(!count) count = geom->ibuf->size >> 2;
+               glDrawElements(glprim(prim), count, GL_UNSIGNED_INT, 0);
+       } else {
+               if(!count) count = geom->vcount;
+               glDrawArrays(glprim(prim), 0, count);
+       }
+}
+
+static unsigned int gl_sdrtype(enum nex_sdr_type type)
+{
+       switch(type) {
+       case NEX_SDR_VERTEX:
+               return GL_VERTEX_SHADER;
+       case NEX_SDR_PIXEL:
+               return GL_FRAGMENT_SHADER;
+       default:
+               break;
+       }
+       return 0;
+}
+
+nex_shader *nex_alloc_shader(enum nex_sdr_type type)
+{
+       nex_shader *sdr;
+
+       if(!(sdr = calloc(1, sizeof *sdr))) {
+               return 0;
+       }
+       sdr->sdr = glCreateShader(gl_sdrtype(type));
+       sdr->type = type;
+       return sdr;
+}
+
+void nex_free_shader(nex_shader *sdr)
+{
+       if(!sdr || --sdr->nref > 0) return;
+
+       free(sdr->name);
+       glDeleteShader(sdr->sdr);
+       free(sdr);
+}
+
+nex_sdrprog *nex_alloc_sdrprog(void)
+{
+       nex_sdrprog *prog;
+
+       if(!(prog = calloc(1, sizeof *prog))) {
+               return 0;
+       }
+       prog->prog = glCreateProgram();
+       return prog;
+}
+
+void nex_free_sdrprog(nex_sdrprog *prog)
+{
+       int i;
+
+       if(!prog) return;
+
+       glDeleteProgram(prog->prog);
+
+       for(i=0; i<prog->num_sdr; i++) {
+               nex_free_shader(prog->sdr[i]);
+       }
+}
+
+void nex_sdrname(nex_shader *sdr, const char *name)
+{
+       free(sdr->name);
+       sdr->name = strdup(name);
+}
+
+void nex_sdrsrc(nex_shader *sdr, const char *src)
+{
+       glShaderSource(sdr->sdr, 1, &src, 0);
+       sdr->src = 1;
+       sdr->compiled = 0;
+}
+
+void nex_sdrbin(nex_shader *sdr, void *bin, size_t sz)
+{
+       glShaderBinary(1, &sdr->sdr, GL_SHADER_BINARY_FORMAT_SPIR_V, bin, sz);
+       sdr->src = 0;
+       sdr->num_const = 0;
+       sdr->compiled = 0;
+}
+
+#define NEX_SDRCONST(sdr, id, val) \
+       int n; \
+       assert((sdr)->num_const < MAX_SDR_CONST); \
+       n = (sdr)->num_const++; \
+       (sdr)->cidx[n] = id; \
+       (sdr)->cval[n] = *(unsigned int*)&(val)
+
+void nex_sdrconst_int(nex_shader *sdr, int id, int val)
+{
+       NEX_SDRCONST(sdr, id, val);
+}
+
+void nex_sdrconst_float(nex_shader *sdr, int id, float val)
+{
+       NEX_SDRCONST(sdr, id, val);
+}
+
+int nex_build_shader(nex_shader *sdr)
+{
+       int status, len;
+       char *buf;
+
+       if(sdr->compiled) return 0;
+
+       if(sdr->src) {
+               glCompileShader(sdr->sdr);
+       } else {
+               glSpecializeShaderARB(sdr->sdr, "main", sdr->num_const, sdr->cidx, sdr->cval);
+       }
+
+       glGetShaderiv(sdr->sdr, GL_COMPILE_STATUS, &status);
+       glGetShaderInfoLog(sdr->sdr, 0, &len, 0);
+       if(len > 0) {
+               buf = alloca(len + 1);
+               glGetShaderInfoLog(sdr->sdr, len, 0, buf);
+               buf[len] = 0;
+               fprintf(status ? stdout : stderr, "nex_build_shader %s:\n%s\n",
+                               sdr->name ? sdr->name : "<unk>", buf);
+       }
+
+       if(status) {
+               sdr->compiled = 1;
+               return 0;
+       }
+       return -1;
+}
+
+void nex_attach_shader(nex_sdrprog *prog, nex_shader *sdr)
+{
+       assert(prog->num_sdr < MAX_SDRPROG_SDR);
+
+       glAttachShader(prog->prog, sdr->sdr);
+       prog->sdr[prog->num_sdr++] = sdr;
+       sdr->nref++;
+}
+
+int nex_build_sdrprog(nex_sdrprog *prog)
+{
+       int i, status, len;
+       char *buf;
+
+       for(i=0; i<prog->num_sdr; i++) {
+               if(!prog->sdr[i]->compiled) {
+                       if(nex_build_shader(prog->sdr[i]) == -1) {
+                               return -1;
+                       }
+               }
+       }
+
+       glLinkProgram(prog->prog);
+
+       glGetProgramiv(prog->prog, GL_LINK_STATUS, &status);
+       glGetProgramInfoLog(prog->prog, 0, &len, 0);
+       if(len) {
+               buf = alloca(len + 1);
+               glGetProgramInfoLog(prog->prog, len, 0, buf);
+               buf[len] = 0;
+               fprintf(status ? stdout : stderr, "nex_build_sdrprog:\n%s\n", buf);
+       }
+
+       return status ? 0 : -1;
+}
+
+#define SPIRV_MAGIC            0x07230203
+#define SPIRV_CIGAM            0x03022307
+struct spirv_header {
+       uint32_t magic;
+       uint32_t ver;
+       uint32_t gen;
+       uint32_t bound;
+       uint32_t rsvd;
+} __attribute__((packed));
+
+nex_shader *nex_load_shader(const char *path, enum nex_sdr_type type)
+{
+       FILE *fp;
+       nex_shader *sdr = 0;
+       size_t len;
+       char *buf;
+       struct spirv_header *hdr;
+
+       if(!(fp = fopen(path, "rb"))) {
+               fprintf(stderr, "failed to open shader file: %s\n", path);
+               return 0;
+       }
+       fseek(fp, 0, SEEK_END);
+       len = ftell(fp);
+       rewind(fp);
+
+       if(!(buf = malloc(len + 1))) {
+               fprintf(stderr, "failed to allocate shader buffer\n");
+               goto end;
+       }
+       if(fread(buf, 1, len, fp) != len) {
+               fprintf(stderr, "failed to read shader\n");
+               goto end;
+       }
+
+       if(!(sdr = nex_alloc_shader(type))) {
+               fprintf(stderr, "failed to allocate shader\n");
+               goto end;
+       }
+       nex_sdrname(sdr, path);
+
+       hdr = (struct spirv_header*)buf;
+       if(hdr->magic == SPIRV_MAGIC || hdr->magic == SPIRV_CIGAM) {
+               /* TODO parse spir-v OpEntryPoint to auto-detect shader type */
+               nex_sdrbin(sdr, buf, len);
+       } else {
+               buf[len] = 0;
+               nex_sdrsrc(sdr, buf);
+       }
+
+end:
+       free(buf);
+       fclose(fp);
+       return sdr;
+}
+
+nex_sdrprog *nex_load_sdrprog(const char *vpath, const char *ppath)
+{
+       nex_sdrprog *prog = 0;
+       nex_shader *vsdr = 0, *psdr = 0;
+
+       if(!(vsdr = nex_load_shader(vpath, NEX_SDR_VERTEX)) || nex_build_shader(vsdr) == -1) {
+               goto err;
+       }
+
+       if(!(psdr = nex_load_shader(ppath, NEX_SDR_PIXEL)) || nex_build_shader(psdr) == -1) {
+               goto err;
+       }
+
+       if(!(prog = nex_alloc_sdrprog())) {
+               fprintf(stderr, "failed to allocate shader program\n");
+               goto err;
+       }
+       nex_attach_shader(prog, vsdr);
+       nex_attach_shader(prog, psdr);
+       if(nex_build_sdrprog(prog) == -1) {
+               goto err;
+       }
+
+       return prog;
+err:
+       if(prog) {
+               nex_free_sdrprog(prog); /* will also delete shaders */
+       } else {
+               nex_free_shader(vsdr);
+               nex_free_shader(psdr);
+       }
+       return 0;
+}
+
+void nex_bind_sdrprog(nex_sdrprog *prog)
+{
+       glUseProgram(prog->prog);
+}
diff --git a/src/gl/gfx_gl.h b/src/gl/gfx_gl.h
new file mode 100644 (file)
index 0000000..01fa5c8
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef NEXUS3D_GFX_GL_H_
+#define NEXUS3D_GFX_GL_H_
+
+#include <stddef.h>
+#include "gfx.h"
+
+struct nex_buffer {
+       unsigned int bo;
+       size_t size;
+};
+
+#define MAX_VAO_BUF            8
+#define MAX_VAO_ATTR   32
+
+struct nex_attr_desc {
+       enum nex_vattr_type type;
+       unsigned int size, bufid;
+};
+
+struct nex_geometry {
+       unsigned int vao;
+       const struct nex_buffer *buf[MAX_VAO_BUF];
+       const struct nex_buffer *ibuf;
+       struct nex_attr_desc attr[MAX_VAO_ATTR];
+       unsigned int vcount;    /* computed by buf size / attr size */
+};
+
+#define MAX_SDR_CONST  64
+
+struct nex_shader {
+       unsigned int sdr;
+       enum nex_sdr_type type;
+       char *name;
+       int src, compiled, nref;
+
+       unsigned int cidx[MAX_SDR_CONST];
+       unsigned int cval[MAX_SDR_CONST];
+       unsigned int num_const;
+};
+
+#define MAX_SDRPROG_SDR        8
+
+struct nex_sdrprog {
+       unsigned int prog;
+
+       nex_shader *sdr[MAX_SDRPROG_SDR];
+       int num_sdr;
+};
+
+#endif /* NEXUS3D_GFX_GL_H_ */
index ca7fb6b..06fedef 100644 (file)
@@ -1,6 +1,114 @@
+#include <stdio.h>
+#include <unistd.h>
 #include "opengl.h"
 
+static void GLAPIENTRY gldebug_logger(GLenum src, GLenum type, GLuint id, GLenum severity,
+               GLsizei len, const char *msg, const void *cls);
+
+static const char *gldebug_srcstr(unsigned int src);
+static const char *gldebug_typestr(unsigned int type);
+static const char *gldebug_sevstr(unsigned int sev);
+
+
 int init_gl(void)
 {
+       glewInit();
+
+       glDebugMessageCallbackARB(gldebug_logger, 0);
        return 0;
 }
+
+static void textcolor(FILE *fp, int col)
+{
+       if(!isatty(fileno(fp))) return;
+
+       if(col) {
+               fprintf(fp, "\033[;%dm", col);
+       } else {
+               fputs("\033[0m", fp);
+       }
+}
+
+
+static void GLAPIENTRY gldebug_logger(GLenum src, GLenum type, GLuint id, GLenum severity,
+               GLsizei len, const char *msg, const void *cls)
+{
+       static const char *fmt = "[GLDEBUG]%s (%s) %s: %s\n";
+       switch(type) {
+       case GL_DEBUG_TYPE_ERROR:
+               textcolor(stderr, 31);
+               fprintf(stderr, fmt, gldebug_sevstr(severity), gldebug_srcstr(src),
+                               gldebug_typestr(type), msg);
+               textcolor(stderr, 0);
+               break;
+
+       case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
+       case GL_DEBUG_TYPE_PORTABILITY:
+       case GL_DEBUG_TYPE_PERFORMANCE:
+               textcolor(stderr, 33);
+               fprintf(stderr, fmt, gldebug_sevstr(severity), gldebug_srcstr(src),
+                               gldebug_typestr(type), msg);
+               textcolor(stderr, 0);
+               break;
+
+       default:
+               fprintf(stderr, fmt, gldebug_sevstr(severity), gldebug_srcstr(src),
+                               gldebug_typestr(type), msg);
+       }
+}
+
+static const char *gldebug_srcstr(unsigned int src)
+{
+       switch(src) {
+       case GL_DEBUG_SOURCE_API:
+               return "api";
+       case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
+               return "wsys";
+       case GL_DEBUG_SOURCE_SHADER_COMPILER:
+               return "sdrc";
+       case GL_DEBUG_SOURCE_THIRD_PARTY:
+               return "3rdparty";
+       case GL_DEBUG_SOURCE_APPLICATION:
+               return "app";
+       case GL_DEBUG_SOURCE_OTHER:
+               return "other";
+       default:
+               break;
+       }
+       return "unknown";
+}
+
+static const char *gldebug_typestr(unsigned int type)
+{
+       switch(type) {
+       case GL_DEBUG_TYPE_ERROR:
+               return "error";
+       case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
+               return "deprecated";
+       case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
+               return "undefined behavior";
+       case GL_DEBUG_TYPE_PORTABILITY:
+               return "portability warning";
+       case GL_DEBUG_TYPE_PERFORMANCE:
+               return "performance warning";
+       case GL_DEBUG_TYPE_OTHER:
+               return "other";
+       default:
+               break;
+       }
+       return "unknown";
+}
+
+static const char *gldebug_sevstr(unsigned int sev)
+{
+       switch(sev) {
+       case GL_DEBUG_SEVERITY_HIGH:
+               return "!!";
+       case GL_DEBUG_SEVERITY_MEDIUM:
+               return "!";
+       case GL_DEBUG_SEVERITY_LOW:
+       default:
+               break;
+       }
+       return "";
+}
index 4723efc..86ccdb3 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef NEXUS3D_OPENGL_H_
 #define NEXUS3D_OPENGL_H_
 
-#include <GL/gl.h>
+#include <GL/glew.h>
 
 int init_gl(void);
 
index 8194813..8ed49de 100644 (file)
@@ -1,6 +1,6 @@
-#include <GL/freeglut.h>
 #include "nexus3d_impl.h"
 #include "gl/opengl.h"
+#include <GL/freeglut.h>
 
 static void winclose(void);
 static void display(void);
diff --git a/test.c b/test.c
index e38d66f..e3aa026 100644 (file)
--- a/test.c
+++ b/test.c
@@ -1,6 +1,8 @@
 #include <stdio.h>
 #include "nexus3d.h"
 
+static int init(void);
+static void cleanup(void);
 
 static void display(void *cls);
 static void reshape(int x, int y, void *cls);
@@ -8,8 +10,32 @@ static void keyb(int key, int pressed, void *cls);
 static void mbutton(int bn, int pressed, int x, int y, void *cls);
 static void mmove(int x, int y, void *cls);
 
+#define ATTR_POS       0
+#define ATTR_COL       1
+
+static const float vdata[] = {
+       -0.25f, -0.25f, 0.25f, 0.25f, -0.25f, 0.25f, 0.25f, -0.25f, -0.25f, -0.25f, -0.25f, -0.25f,
+       -0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, 0.25f, -0.25f, -0.25f, 0.25f, -0.25f
+};
+static const float vcolors[] = {
+       1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0,
+       0, 1, 1, 1, 0, 1, 1, 0.5, 0, 0.5, 0.5, 0.5
+};
+
+static const unsigned int idata[] = {
+       0, 1, 5,        0, 5, 4,
+       1, 2, 6,        1, 6, 5,
+       2, 3, 7,        2, 7, 6,
+       3, 0, 4,        3, 4, 7,
+       4, 5, 6,        4, 6, 7,
+       1, 0, 3,        1, 3, 2
+};
+
 
 static int quit;
+static nex_buffer *vbuf, *ibuf, *cbuf;
+static nex_geometry *geom;
+static nex_sdrprog *sdrprog;
 
 int main(void)
 {
@@ -24,17 +50,54 @@ int main(void)
        nex_cbmousebn(mbutton, 0);
        nex_cbmousemove(mmove, 0);
 
+       if(init() == -1) {
+               goto end;
+       }
+
        while(nex_evloop_wait() && !quit);
 
+end:
+       cleanup();
        nex_closegfx();
        return 0;
 }
 
+static int init(void)
+{
+       nex_clearcolor(0.1, 0.12, 0.2);
+
+       vbuf = nex_alloc_buffer(sizeof vdata, vdata);
+       cbuf = nex_alloc_buffer(sizeof vcolors, vcolors);
+       ibuf = nex_alloc_buffer(sizeof idata, idata);
+       geom = nex_alloc_geometry();
+       nex_geom_vbuffer(geom, 0, vbuf, 3 * sizeof(float));
+       nex_geom_vbuffer(geom, 1, cbuf, 3 * sizeof(float));
+       nex_geom_vattr(geom, ATTR_POS, NEX_VEC3, 0, 0);
+       nex_geom_vattr(geom, ATTR_COL, NEX_COL3, 1, 0);
+       nex_geom_ibuffer(geom, ibuf);
+
+       if(!(sdrprog = nex_load_sdrprog("test.v.spv", "test.p.spv"))) {
+               return -1;
+       }
+       return 0;
+}
+
+static void cleanup(void)
+{
+       nex_free_buffer(vbuf);
+       nex_free_buffer(cbuf);
+       nex_free_buffer(ibuf);
+       nex_free_geometry(geom);
+       nex_free_sdrprog(sdrprog);
+}
 
 static void display(void *cls)
 {
        nex_clear();
 
+       nex_bind_sdrprog(sdrprog);
+       nex_draw_geometry(geom, NEX_TRIANGLES, 0);
+
        nex_swap_buffers();
 }
 
diff --git a/test.p.glsl b/test.p.glsl
new file mode 100644 (file)
index 0000000..aecbf05
--- /dev/null
@@ -0,0 +1,9 @@
+#version 410
+
+layout(location = 0) out vec4 ocol;
+layout(location = 3) in vec4 vcol;
+
+void main()
+{
+       ocol = vcol;
+}
diff --git a/test.v.glsl b/test.v.glsl
new file mode 100644 (file)
index 0000000..0ecd84a
--- /dev/null
@@ -0,0 +1,11 @@
+#version 410
+
+layout(location = 0) in vec4 attr_vertex;
+layout(location = 1) in vec4 attr_color;
+layout(location = 3) out vec4 vcol;
+
+void main()
+{
+       gl_Position = attr_vertex;
+       vcol = attr_color;
+}