Samplers are not needed anymore
[gl4] / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <stddef.h>
5 #include <assert.h>
6 #include <GL/freeglut.h>
7 #include <GL/glext.h>
8 #include <GL/glx.h>
9 #include "matrix.h"
10
11 #define SPIRV
12
13 enum {
14         UBLOCK_MATRIX,
15 };
16
17 enum {
18         VATTR_VERTEX,
19         VATTR_NORMAL,
20         VATTR_TEXCOORD
21 };
22
23 struct vertex {
24         float x, y, z;
25         float nx, ny, nz;
26         float tu, tv;
27 };
28
29 struct mesh {
30         struct vertex *varr;
31         unsigned int *iarr;
32         int vcount, icount;
33
34         unsigned int vbo, ibo, vao;
35 };
36
37 struct matrix_state {
38         float view_mat[16];
39         float proj_mat[16];
40         float mvmat[16];
41         float mvpmat[16];
42         float lpos[3];
43 } __attribute__((packed));
44
45 unsigned int tex;
46
47 int init(void);
48 void cleanup(void);
49 void display(void);
50 void reshape(int x, int y);
51 void keypress(unsigned char key, int x, int y);
52 void mouse(int bn, int st, int x, int y);
53 void motion(int x, int y);
54
55 int gen_torus(struct mesh *mesh, float rad, float rrad, int usub, int vsub);
56 void draw_mesh(struct mesh *mesh);
57 unsigned int gen_texture(int width, int height);
58
59 unsigned int load_shader(const char *fname, int type);
60 unsigned int load_program(const char *vfname, const char *pfname);
61 int link_program(unsigned int prog);
62
63 void GLAPIENTRY gldebug(GLenum src, GLenum type, GLuint id, GLenum severity,
64                 GLsizei len, const char *msg, const void *cls);
65
66 float cam_theta, cam_phi = 25, cam_dist = 4;
67 int prev_x, prev_y, bnstate[8];
68
69 struct mesh torus;
70
71 unsigned int sdr;
72
73 struct matrix_state matrix_state;
74
75 unsigned int ubo_matrix;
76
77 static PFNGLSPECIALIZESHADERPROC gl_specialize_shader;
78
79 int main(int argc, char **argv)
80 {
81         glutInit(&argc, argv);
82         glutInitWindowSize(800, 600);
83         glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
84         glutInitContextProfile(GLUT_CORE_PROFILE);
85         glutInitContextVersion(4, 4);
86         glutCreateWindow("GL4 test");
87
88         glutDisplayFunc(display);
89         glutReshapeFunc(reshape);
90         glutKeyboardFunc(keypress);
91         glutMouseFunc(mouse);
92         glutMotionFunc(motion);
93
94         if(init() == -1) {
95                 return 1;
96         }
97         atexit(cleanup);
98
99         glutMainLoop();
100         return 0;
101 }
102
103 int init(void)
104 {
105         glDebugMessageCallback(gldebug, 0);
106         glEnable(GL_DEPTH_TEST);
107         glEnable(GL_CULL_FACE);
108
109         gl_specialize_shader = (PFNGLSPECIALIZESHADERPROC)glXGetProcAddress((unsigned char*)"glSpecializeShaderARB");
110         if(!gl_specialize_shader) {
111                 fprintf(stderr, "failed to load glSpecializeShaderARB entry point\n");
112                 return -1;
113         }
114
115         if(!(tex = gen_texture(256, 256))) {
116                 return -1;
117         }
118
119         if(gen_torus(&torus, 1.0, 0.25, 32, 12) == -1) {
120                 return -1;
121         }
122
123 #ifndef SPIRV
124         if(!(sdr = load_program("vertex.glsl", "pixel.glsl"))) {
125                 return -1;
126         }
127 #else
128         if(!(sdr = load_program("spirv/vertex.spv", "spirv/pixel.spv"))) {
129                 return -1;
130         }
131 #endif
132
133         if(link_program(sdr) == -1) {
134                 fprintf(stderr, "failed to bind attribute locations\n");
135                 return -1;
136         }
137
138         glUseProgram(sdr);
139
140         glGenBuffers(1, &ubo_matrix);
141         glBindBuffer(GL_UNIFORM_BUFFER, ubo_matrix);
142         glBufferData(GL_UNIFORM_BUFFER, sizeof matrix_state, &matrix_state, GL_STREAM_DRAW);
143
144         return 0;
145 }
146
147 void cleanup(void)
148 {
149         free(torus.varr);
150         free(torus.iarr);
151         if(torus.vbo) {
152                 glDeleteBuffers(1, &torus.vbo);
153                 glDeleteBuffers(1, &torus.ibo);
154         }
155         if(torus.vao) {
156                 glDeleteVertexArrays(1, &torus.vao);
157         }
158         glDeleteTextures(1, &tex);
159 }
160
161 void display(void)
162 {
163         matrix_state.lpos[0] = -10;
164         matrix_state.lpos[1] = 10;
165         matrix_state.lpos[2] = 10;
166
167         glClearColor(0.05, 0.05, 0.05, 1.0);
168         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
169
170         mat_identity(matrix_state.view_mat);
171         mat_translate(matrix_state.view_mat, 0, 0, -cam_dist);
172         mat_rotate(matrix_state.view_mat, cam_phi, 1, 0, 0);
173         mat_rotate(matrix_state.view_mat, cam_theta, 0, 1, 0);
174
175         mat_copy(matrix_state.mvmat, matrix_state.view_mat);
176
177         mat_copy(matrix_state.mvpmat, matrix_state.proj_mat);
178         mat_mul(matrix_state.mvpmat, matrix_state.mvmat);
179
180         mat_transform(matrix_state.view_mat, matrix_state.lpos);
181
182         glUseProgram(sdr);
183
184         glBindBuffer(GL_UNIFORM_BUFFER, ubo_matrix);
185         glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof matrix_state, &matrix_state);
186         glBindBufferBase(GL_UNIFORM_BUFFER, UBLOCK_MATRIX, ubo_matrix);
187
188         glBindTexture(GL_TEXTURE_2D, tex);
189         draw_mesh(&torus);
190
191         assert(glGetError() == GL_NO_ERROR);
192         glutSwapBuffers();
193 }
194
195 void reshape(int x, int y)
196 {
197         glViewport(0, 0, x, y);
198
199         mat_identity(matrix_state.proj_mat);
200         mat_perspective(matrix_state.proj_mat, 50.0, (float)x / (float)y, 0.5, 500.0);
201 }
202
203 void keypress(unsigned char key, int x, int y)
204 {
205         switch(key) {
206         case 27:
207                 exit(0);
208         }
209 }
210
211 void mouse(int bn, int st, int x, int y)
212 {
213         bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
214         prev_x = x;
215         prev_y = y;
216 }
217
218 void motion(int x, int y)
219 {
220         int dx = x - prev_x;
221         int dy = y - prev_y;
222         prev_x = x;
223         prev_y = y;
224
225         if(!dx && !dy) return;
226
227         if(bnstate[0]) {
228                 cam_theta += dx * 0.5;
229                 cam_phi += dy * 0.5;
230                 if(cam_phi < -90) cam_phi = -90;
231                 if(cam_phi > 90) cam_phi = 90;
232                 glutPostRedisplay();
233         }
234         if(bnstate[2]) {
235                 cam_dist += dy * 0.1;
236                 if(cam_dist < 0.0) cam_dist = 0.0;
237                 glutPostRedisplay();
238         }
239 }
240
241 static void torus_vertex(struct vertex *vout, float rad, float rrad, float u, float v)
242 {
243         float theta = u * M_PI * 2.0;
244         float phi = v * M_PI * 2.0;
245         float rx, ry, rz, cx, cy, cz;
246
247         cx = sin(theta) * rad;
248         cy = 0.0;
249         cz = -cos(theta) * rad;
250
251         rx = -cos(phi) * rrad + rad;
252         ry = sin(phi) * rrad;
253         rz = 0.0;
254
255         vout->x = rx * sin(theta) + rz * cos(theta);
256         vout->y = ry;
257         vout->z = -rx * cos(theta) + rz * sin(theta);
258
259         vout->nx = (vout->x - cx) / rrad;
260         vout->ny = (vout->y - cy) / rrad;
261         vout->nz = (vout->z - cz) / rrad;
262
263         vout->tu = u;
264         vout->tv = v;
265 }
266
267
268 int gen_torus(struct mesh *mesh, float rad, float rrad, int usub, int vsub)
269 {
270         int i, j, uverts, vverts, nverts, nquads, ntri;
271         float u, v;
272         float du = 1.0 / (float)usub;
273         float dv = 1.0 / (float)vsub;
274         struct vertex *vptr;
275         unsigned int *iptr;
276
277         if(usub < 3) usub = 3;
278         if(vsub < 3) vsub = 3;
279
280         uverts = usub + 1;
281         vverts = vsub + 1;
282
283         nverts = uverts * vverts;
284         nquads = usub * vsub;
285         ntri = nquads * 2;
286
287         mesh->vcount = nverts;
288         mesh->icount = ntri * 3;
289
290         if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
291                 fprintf(stderr, "failed to allocate vertex array for %d vertices\n", mesh->vcount);
292                 return -1;
293         }
294         vptr = mesh->varr;
295         if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
296                 fprintf(stderr, "failed to allocate index array for %d indices\n", mesh->icount);
297                 free(mesh->varr);
298                 mesh->varr = 0;
299                 return -1;
300         }
301         iptr = mesh->iarr;
302
303         u = 0.0;
304         for(i=0; i<uverts; i++) {
305                 v = 0.0;
306                 for(j=0; j<vverts; j++) {
307                         torus_vertex(vptr++, rad, rrad, u, v);
308
309                         if(i < usub && j < vsub) {
310                                 int vnum = i * vverts + j;
311                                 *iptr++ = vnum;
312                                 *iptr++ = vnum + vverts + 1;
313                                 *iptr++ = vnum + 1;
314                                 *iptr++ = vnum;
315                                 *iptr++ = vnum + vverts;
316                                 *iptr++ = vnum + vverts + 1;
317                         }
318
319                         v += dv;
320                 }
321                 u += du;
322         }
323
324         glGenBuffers(1, &mesh->vbo);
325         glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
326         glBufferData(GL_ARRAY_BUFFER, mesh->vcount * sizeof *mesh->varr, mesh->varr, GL_STATIC_DRAW);
327         glBindBuffer(GL_ARRAY_BUFFER, 0);
328
329         glGenBuffers(1, &mesh->ibo);
330         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
331         glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->icount * sizeof *mesh->iarr, mesh->iarr, GL_STATIC_DRAW);
332         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
333
334         glGenVertexArrays(1, &mesh->vao);
335         glBindVertexArray(mesh->vao);
336
337         glEnableVertexAttribArray(VATTR_VERTEX);
338         glEnableVertexAttribArray(VATTR_NORMAL);
339         glEnableVertexAttribArray(VATTR_TEXCOORD);
340
341         glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
342         glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), 0);
343         glVertexAttribPointer(VATTR_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, nx));
344         glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, tu));
345         glBindBuffer(GL_ARRAY_BUFFER, 0);
346
347         glBindVertexArray(0);
348         return 0;
349 }
350
351 void draw_mesh(struct mesh *mesh)
352 {
353         glBindVertexArray(mesh->vao);
354
355         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
356         glDrawElements(GL_TRIANGLES, mesh->icount, GL_UNSIGNED_INT, 0);
357         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
358
359         glBindVertexArray(0);
360 }
361
362 unsigned int gen_texture(int width, int height)
363 {
364         int i, j;
365         unsigned int tex;
366         unsigned char *pixels, *ptr;
367
368         if(!(pixels = malloc(width * height * 3))) {
369                 return 0;
370         }
371         ptr = pixels;
372
373         for(i=0; i<height; i++) {
374                 for(j=0; j<width; j++) {
375                         int x = i ^ j;
376                         *ptr++ = x;
377                         *ptr++ = (x << 1) & 0xff;
378                         *ptr++ = (x << 2) & 0xff;
379                 }
380         }
381
382         glGenTextures(1, &tex);
383         glBindTexture(GL_TEXTURE_2D, tex);
384         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
385         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
386         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
387         glGenerateMipmap(GL_TEXTURE_2D);
388
389         free(pixels);
390         return tex;
391 }
392
393 unsigned int load_shader(const char *fname, int type)
394 {
395         unsigned int sdr;
396         int fsz;
397         char *buf;
398         FILE *fp;
399         int status, loglen;
400
401         if(!(fp = fopen(fname, "rb"))) {
402                 fprintf(stderr, "failed to open shader: %s\n", fname);
403                 return 0;
404         }
405         fseek(fp, 0, SEEK_END);
406         fsz = ftell(fp);
407         rewind(fp);
408
409         if(!(buf = malloc(fsz + 1))) {
410                 fprintf(stderr, "failed to allocate %d bytes\n", fsz + 1);
411                 fclose(fp);
412                 return 0;
413         }
414         if(fread(buf, 1, fsz, fp) < fsz) {
415                 fprintf(stderr, "failed to read shader: %s\n", fname);
416                 free(buf);
417                 fclose(fp);
418                 return 0;
419         }
420         buf[fsz] = 0;
421         fclose(fp);
422
423         sdr = glCreateShader(type);
424
425 #ifndef SPIRV
426         glShaderSource(sdr, 1, (const char**)&buf, 0);
427         glCompileShader(sdr);
428 #else
429         glShaderBinary(1, &sdr, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, buf, fsz);
430         gl_specialize_shader(sdr, "main", 0, 0, 0);
431 #endif
432         free(buf);
433
434         glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
435         if(status) {
436                 printf("successfully compiled shader: %s\n", fname);
437         } else {
438                 printf("failed to compile shader: %s\n", fname);
439         }
440
441         glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
442         if(loglen > 0 && (buf = malloc(loglen + 1))) {
443                 glGetShaderInfoLog(sdr, loglen, 0, buf);
444                 buf[loglen] = 0;
445                 printf("%s\n", buf);
446                 free(buf);
447         }
448
449         if(!status) {
450                 glDeleteShader(sdr);
451                 return 0;
452         }
453         return sdr;
454 }
455
456 unsigned int load_program(const char *vfname, const char *pfname)
457 {
458         unsigned int vs, ps, prog;
459
460         if(!(vs = load_shader(vfname, GL_VERTEX_SHADER))) {
461                 return 0;
462         }
463         if(!(ps = load_shader(pfname, GL_FRAGMENT_SHADER))) {
464                 glDeleteShader(vs);
465                 return 0;
466         }
467
468         prog = glCreateProgram();
469         glAttachShader(prog, vs);
470         glAttachShader(prog, ps);
471
472         if(link_program(prog) == -1) {
473                 glDeleteShader(vs);
474                 glDeleteShader(ps);
475                 glDeleteProgram(prog);
476                 return 0;
477         }
478         return prog;
479 }
480
481 int link_program(unsigned int prog)
482 {
483         int status, loglen;
484         char *buf;
485
486         glLinkProgram(prog);
487
488         glGetProgramiv(prog, GL_LINK_STATUS, &status);
489         if(status) {
490                 printf("successfully linked shader program\n");
491         } else {
492                 printf("failed to link shader program\n");
493         }
494
495         glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &loglen);
496         if(loglen > 0 && (buf = malloc(loglen + 1))) {
497                 glGetProgramInfoLog(prog, loglen, 0, buf);
498                 buf[loglen] = 0;
499                 printf("%s\n", buf);
500                 free(buf);
501         }
502
503         return status ? 0 : -1;
504 }
505
506 const char *gldebug_srcstr(unsigned int src)
507 {
508         switch(src) {
509         case GL_DEBUG_SOURCE_API:
510                 return "api";
511         case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
512                 return "wsys";
513         case GL_DEBUG_SOURCE_SHADER_COMPILER:
514                 return "sdrc";
515         case GL_DEBUG_SOURCE_THIRD_PARTY:
516                 return "3rdparty";
517         case GL_DEBUG_SOURCE_APPLICATION:
518                 return "app";
519         case GL_DEBUG_SOURCE_OTHER:
520                 return "other";
521         default:
522                 break;
523         }
524         return "unknown";
525 }
526
527 const char *gldebug_typestr(unsigned int type)
528 {
529         switch(type) {
530         case GL_DEBUG_TYPE_ERROR:
531                 return "error";
532         case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
533                 return "deprecated";
534         case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
535                 return "undefined behavior";
536         case GL_DEBUG_TYPE_PORTABILITY:
537                 return "portability";
538         case GL_DEBUG_TYPE_PERFORMANCE:
539                 return "performance";
540         case GL_DEBUG_TYPE_OTHER:
541                 return "other";
542         default:
543                 break;
544         }
545         return "unknown";
546 }
547
548 void GLAPIENTRY gldebug(GLenum src, GLenum type, GLuint id, GLenum severity,
549                 GLsizei len, const char *msg, const void *cls)
550 {
551         printf("[GLDEBUG] (%s) %s: %s\n", gldebug_srcstr(src), gldebug_typestr(type), msg);
552 }
553