7 #include "nexus3d_impl.h"
10 static unsigned int cur_state;
14 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
17 void nex_clearcolor(float r, float g, float b)
19 glClearColor(r, g, b, 1.0f);
22 void nex_cleardepth(float z)
27 void nex_clearstencil(unsigned int s)
32 void nex_viewport(int x, int y, int w, int h)
34 glViewport(x, y, w, h);
37 static unsigned int glstateopt(enum nex_state_opt opt)
42 case NEX_STENCIL_TEST:
43 return GL_STENCIL_TEST;
54 void nex_enable(enum nex_state_opt opt)
56 unsigned int glst = glstateopt(opt);
59 cur_state |= (1 << opt);
63 void nex_disable(enum nex_state_opt opt)
65 unsigned int glst = glstateopt(opt);
68 cur_state &= ~(1 << opt);
72 int nex_is_enabled(enum nex_state_opt opt)
74 return cur_state & (1 << opt) ? 1 : 0;
77 nex_buffer *nex_alloc_buffer(size_t sz, const void *data)
81 if(!(buf = malloc(sizeof *buf))) {
84 glCreateBuffers(1, &buf->bo);
86 glNamedBufferStorage(buf->bo, sz, data, GL_DYNAMIC_STORAGE_BIT);
93 void nex_free_buffer(nex_buffer *buf)
96 glDeleteBuffers(1, &buf->bo);
100 nex_geometry *nex_alloc_geometry(void)
104 if(!(geom = calloc(1, sizeof *geom))) {
107 glCreateVertexArrays(1, &geom->vao);
111 void nex_free_geometry(nex_geometry *geom)
114 glDeleteVertexArrays(1, &geom->vao);
118 void nex_geom_vbuffer(nex_geometry *geom, unsigned int bufid, const nex_buffer *buf,
121 glVertexArrayVertexBuffer(geom->vao, bufid, buf->bo, 0, stride);
123 assert(bufid >= 0 && bufid < MAX_VAO_BUF);
124 geom->buf[bufid] = buf;
127 void nex_geom_ibuffer(nex_geometry *geom, const nex_buffer *buf)
129 glVertexArrayElementBuffer(geom->vao, buf->bo);
134 static int attrnelem(enum nex_vattr_type atype)
153 static int attrnorm(enum nex_vattr_type atype)
155 return atype > NEX_COL3 ? 1 : 0;
158 static int attrsize(enum nex_vattr_type atype)
162 return sizeof(float);
164 return 2 * sizeof(float);
167 return 3 * sizeof(float);
170 return 4 * sizeof(float);
177 void nex_geom_vattr(nex_geometry *geom, unsigned int attr, enum nex_vattr_type type,
178 int bufid, unsigned int offs)
180 assert(attr >= 0 && attr < MAX_VAO_ATTR);
183 glVertexArrayAttribFormat(geom->vao, attr, attrnelem(type), GL_FLOAT,
184 attrnorm(type), offs);
185 glVertexArrayAttribBinding(geom->vao, attr, bufid);
186 glEnableVertexArrayAttrib(geom->vao, attr);
188 assert(geom->buf[bufid]);
189 geom->attr[attr].type = type;
190 geom->attr[attr].bufid = bufid;
191 geom->attr[attr].size = attrsize(type);
192 /* XXX no attempt to validate equal vcount across all bound buffers */
193 geom->vcount = geom->buf[bufid]->size / geom->attr[attr].size;
195 glDisableVertexArrayAttrib(geom->vao, attr);
196 geom->attr[attr].bufid = 0;
197 geom->attr[attr].size = 0;
201 static unsigned int glprim(enum nex_primitive prim)
209 return GL_LINE_STRIP;
212 case NEX_TRIANGLE_STRIP:
213 return GL_TRIANGLE_STRIP;
214 case NEX_TRIANGLE_FAN:
215 return GL_TRIANGLE_FAN;
222 void nex_draw_geometry(const nex_geometry *geom, enum nex_primitive prim, unsigned int count)
224 glBindVertexArray(geom->vao);
226 if(!count) count = geom->ibuf->size >> 2;
227 glDrawElements(glprim(prim), count, GL_UNSIGNED_INT, 0);
229 if(!count) count = geom->vcount;
230 glDrawArrays(glprim(prim), 0, count);
234 static unsigned int gl_sdrtype(enum nex_sdr_type type)
238 return GL_VERTEX_SHADER;
240 return GL_FRAGMENT_SHADER;
247 nex_shader *nex_alloc_shader(enum nex_sdr_type type)
251 if(!(sdr = calloc(1, sizeof *sdr))) {
254 sdr->sdr = glCreateShader(gl_sdrtype(type));
259 void nex_free_shader(nex_shader *sdr)
261 if(!sdr || --sdr->nref > 0) return;
264 glDeleteShader(sdr->sdr);
268 nex_sdrprog *nex_alloc_sdrprog(void)
272 if(!(prog = calloc(1, sizeof *prog))) {
275 prog->prog = glCreateProgram();
279 void nex_free_sdrprog(nex_sdrprog *prog)
285 glDeleteProgram(prog->prog);
287 for(i=0; i<prog->num_sdr; i++) {
288 nex_free_shader(prog->sdr[i]);
292 void nex_sdrname(nex_shader *sdr, const char *name)
295 sdr->name = strdup(name);
298 void nex_sdrsrc(nex_shader *sdr, const char *src)
300 glShaderSource(sdr->sdr, 1, &src, 0);
305 void nex_sdrbin(nex_shader *sdr, void *bin, size_t sz)
307 glShaderBinary(1, &sdr->sdr, GL_SHADER_BINARY_FORMAT_SPIR_V, bin, sz);
313 #define NEX_SDRCONST(sdr, id, val) \
315 assert((sdr)->num_const < MAX_SDR_CONST); \
316 n = (sdr)->num_const++; \
317 (sdr)->cidx[n] = id; \
318 (sdr)->cval[n] = *(unsigned int*)&(val)
320 void nex_sdrconst_int(nex_shader *sdr, int id, int val)
322 NEX_SDRCONST(sdr, id, val);
325 void nex_sdrconst_float(nex_shader *sdr, int id, float val)
327 NEX_SDRCONST(sdr, id, val);
330 int nex_build_shader(nex_shader *sdr)
335 if(sdr->compiled) return 0;
338 glCompileShader(sdr->sdr);
340 glSpecializeShaderARB(sdr->sdr, "main", sdr->num_const, sdr->cidx, sdr->cval);
343 glGetShaderiv(sdr->sdr, GL_COMPILE_STATUS, &status);
344 glGetShaderInfoLog(sdr->sdr, 0, &len, 0);
346 buf = alloca(len + 1);
347 glGetShaderInfoLog(sdr->sdr, len, 0, buf);
349 fprintf(status ? stdout : stderr, "nex_build_shader %s:\n%s\n",
350 sdr->name ? sdr->name : "<unk>", buf);
360 void nex_attach_shader(nex_sdrprog *prog, nex_shader *sdr)
362 assert(prog->num_sdr < MAX_SDRPROG_SDR);
364 glAttachShader(prog->prog, sdr->sdr);
365 prog->sdr[prog->num_sdr++] = sdr;
369 int nex_build_sdrprog(nex_sdrprog *prog)
374 for(i=0; i<prog->num_sdr; i++) {
375 if(!prog->sdr[i]->compiled) {
376 if(nex_build_shader(prog->sdr[i]) == -1) {
382 glLinkProgram(prog->prog);
384 glGetProgramiv(prog->prog, GL_LINK_STATUS, &status);
385 glGetProgramInfoLog(prog->prog, 0, &len, 0);
387 buf = alloca(len + 1);
388 glGetProgramInfoLog(prog->prog, len, 0, buf);
390 fprintf(status ? stdout : stderr, "nex_build_sdrprog:\n%s\n", buf);
393 return status ? 0 : -1;
396 void nex_bind_sdrprog(nex_sdrprog *prog)
398 glUseProgram(prog->prog);
401 int nex_find_uniform(nex_sdrprog *prog, const char *name)
403 return glGetUniformLocation(prog->prog, name);
406 void nex_uniform_mat4(nex_sdrprog *prog, int loc, const float *mat)
409 glProgramUniformMatrix4fv(prog->prog, loc, 1, 0, mat);
412 void nex_uniform_mat4_name(nex_sdrprog *prog, const char *name, const float *mat)
414 int loc = glGetUniformLocation(prog->prog, name);
416 glProgramUniformMatrix4fv(prog->prog, loc, 1, 0, mat);
420 #define SPIRV_MAGIC 0x07230203
421 #define SPIRV_CIGAM 0x03022307
422 struct spirv_header {
428 } __attribute__((packed));
430 nex_shader *nex_load_shader(const char *path, enum nex_sdr_type type)
436 struct spirv_header *hdr;
438 if(!(fp = fopen(path, "rb"))) {
439 fprintf(stderr, "failed to open shader file: %s\n", path);
442 fseek(fp, 0, SEEK_END);
446 if(!(buf = malloc(len + 1))) {
447 fprintf(stderr, "failed to allocate shader buffer\n");
450 if(fread(buf, 1, len, fp) != len) {
451 fprintf(stderr, "failed to read shader\n");
455 if(!(sdr = nex_alloc_shader(type))) {
456 fprintf(stderr, "failed to allocate shader\n");
459 nex_sdrname(sdr, path);
461 hdr = (struct spirv_header*)buf;
462 if(hdr->magic == SPIRV_MAGIC || hdr->magic == SPIRV_CIGAM) {
463 /* TODO parse spir-v OpEntryPoint to auto-detect shader type */
464 nex_sdrbin(sdr, buf, len);
467 nex_sdrsrc(sdr, buf);
476 nex_sdrprog *nex_load_sdrprog(const char *vpath, const char *ppath)
478 nex_sdrprog *prog = 0;
479 nex_shader *vsdr = 0, *psdr = 0;
481 if(!(vsdr = nex_load_shader(vpath, NEX_SDR_VERTEX)) || nex_build_shader(vsdr) == -1) {
485 if(!(psdr = nex_load_shader(ppath, NEX_SDR_PIXEL)) || nex_build_shader(psdr) == -1) {
489 if(!(prog = nex_alloc_sdrprog())) {
490 fprintf(stderr, "failed to allocate shader program\n");
493 nex_attach_shader(prog, vsdr);
494 nex_attach_shader(prog, psdr);
495 if(nex_build_sdrprog(prog) == -1) {
502 nex_free_sdrprog(prog); /* will also delete shaders */
504 nex_free_shader(vsdr);
505 nex_free_shader(psdr);