6 #include <GL/freeglut.h>
34 unsigned int vbo, ibo, vao;
43 } __attribute__((packed));
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);
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);
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);
63 void GLAPIENTRY gldebug(GLenum src, GLenum type, GLuint id, GLenum severity,
64 GLsizei len, const char *msg, const void *cls);
66 float cam_theta, cam_phi = 25, cam_dist = 4;
67 int prev_x, prev_y, bnstate[8];
73 struct matrix_state matrix_state;
75 unsigned int ubo_matrix;
77 static PFNGLSPECIALIZESHADERPROC gl_specialize_shader;
79 int main(int argc, char **argv)
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");
88 glutDisplayFunc(display);
89 glutReshapeFunc(reshape);
90 glutKeyboardFunc(keypress);
92 glutMotionFunc(motion);
105 glDebugMessageCallback(gldebug, 0);
106 glEnable(GL_DEPTH_TEST);
107 glEnable(GL_CULL_FACE);
109 gl_specialize_shader = (PFNGLSPECIALIZESHADERPROC)glXGetProcAddress((unsigned char*)"glSpecializeShaderARB");
110 if(!gl_specialize_shader) {
111 fprintf(stderr, "failed to load glSpecializeShaderARB entry point\n");
115 if(!(tex = gen_texture(256, 256))) {
119 if(gen_torus(&torus, 1.0, 0.25, 32, 12) == -1) {
124 if(!(sdr = load_program("vertex.glsl", "pixel.glsl"))) {
128 if(!(sdr = load_program("spirv/vertex.spv", "spirv/pixel.spv"))) {
133 if(link_program(sdr) == -1) {
134 fprintf(stderr, "failed to bind attribute locations\n");
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);
152 glDeleteBuffers(1, &torus.vbo);
153 glDeleteBuffers(1, &torus.ibo);
156 glDeleteVertexArrays(1, &torus.vao);
158 glDeleteTextures(1, &tex);
163 matrix_state.lpos[0] = -10;
164 matrix_state.lpos[1] = 10;
165 matrix_state.lpos[2] = 10;
167 glClearColor(0.05, 0.05, 0.05, 1.0);
168 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
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);
175 mat_copy(matrix_state.mvmat, matrix_state.view_mat);
177 mat_copy(matrix_state.mvpmat, matrix_state.proj_mat);
178 mat_mul(matrix_state.mvpmat, matrix_state.mvmat);
180 mat_transform(matrix_state.view_mat, matrix_state.lpos);
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);
188 glBindTexture(GL_TEXTURE_2D, tex);
191 assert(glGetError() == GL_NO_ERROR);
195 void reshape(int x, int y)
197 glViewport(0, 0, x, y);
199 mat_identity(matrix_state.proj_mat);
200 mat_perspective(matrix_state.proj_mat, 50.0, (float)x / (float)y, 0.5, 500.0);
203 void keypress(unsigned char key, int x, int y)
211 void mouse(int bn, int st, int x, int y)
213 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
218 void motion(int x, int y)
225 if(!dx && !dy) return;
228 cam_theta += dx * 0.5;
230 if(cam_phi < -90) cam_phi = -90;
231 if(cam_phi > 90) cam_phi = 90;
235 cam_dist += dy * 0.1;
236 if(cam_dist < 0.0) cam_dist = 0.0;
241 static void torus_vertex(struct vertex *vout, float rad, float rrad, float u, float v)
243 float theta = u * M_PI * 2.0;
244 float phi = v * M_PI * 2.0;
245 float rx, ry, rz, cx, cy, cz;
247 cx = sin(theta) * rad;
249 cz = -cos(theta) * rad;
251 rx = -cos(phi) * rrad + rad;
252 ry = sin(phi) * rrad;
255 vout->x = rx * sin(theta) + rz * cos(theta);
257 vout->z = -rx * cos(theta) + rz * sin(theta);
259 vout->nx = (vout->x - cx) / rrad;
260 vout->ny = (vout->y - cy) / rrad;
261 vout->nz = (vout->z - cz) / rrad;
268 int gen_torus(struct mesh *mesh, float rad, float rrad, int usub, int vsub)
270 int i, j, uverts, vverts, nverts, nquads, ntri;
272 float du = 1.0 / (float)usub;
273 float dv = 1.0 / (float)vsub;
277 if(usub < 3) usub = 3;
278 if(vsub < 3) vsub = 3;
283 nverts = uverts * vverts;
284 nquads = usub * vsub;
287 mesh->vcount = nverts;
288 mesh->icount = ntri * 3;
290 if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
291 fprintf(stderr, "failed to allocate vertex array for %d vertices\n", mesh->vcount);
295 if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
296 fprintf(stderr, "failed to allocate index array for %d indices\n", mesh->icount);
304 for(i=0; i<uverts; i++) {
306 for(j=0; j<vverts; j++) {
307 torus_vertex(vptr++, rad, rrad, u, v);
309 if(i < usub && j < vsub) {
310 int vnum = i * vverts + j;
312 *iptr++ = vnum + vverts + 1;
315 *iptr++ = vnum + vverts;
316 *iptr++ = vnum + vverts + 1;
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);
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);
334 glGenVertexArrays(1, &mesh->vao);
335 glBindVertexArray(mesh->vao);
337 glEnableVertexAttribArray(VATTR_VERTEX);
338 glEnableVertexAttribArray(VATTR_NORMAL);
339 glEnableVertexAttribArray(VATTR_TEXCOORD);
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);
347 glBindVertexArray(0);
351 void draw_mesh(struct mesh *mesh)
353 glBindVertexArray(mesh->vao);
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);
359 glBindVertexArray(0);
362 unsigned int gen_texture(int width, int height)
366 unsigned char *pixels, *ptr;
368 if(!(pixels = malloc(width * height * 3))) {
373 for(i=0; i<height; i++) {
374 for(j=0; j<width; j++) {
377 *ptr++ = (x << 1) & 0xff;
378 *ptr++ = (x << 2) & 0xff;
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);
393 unsigned int load_shader(const char *fname, int type)
401 if(!(fp = fopen(fname, "rb"))) {
402 fprintf(stderr, "failed to open shader: %s\n", fname);
405 fseek(fp, 0, SEEK_END);
409 if(!(buf = malloc(fsz + 1))) {
410 fprintf(stderr, "failed to allocate %d bytes\n", fsz + 1);
414 if(fread(buf, 1, fsz, fp) < fsz) {
415 fprintf(stderr, "failed to read shader: %s\n", fname);
423 sdr = glCreateShader(type);
426 glShaderSource(sdr, 1, (const char**)&buf, 0);
427 glCompileShader(sdr);
429 glShaderBinary(1, &sdr, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, buf, fsz);
430 gl_specialize_shader(sdr, "main", 0, 0, 0);
434 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
436 printf("successfully compiled shader: %s\n", fname);
438 printf("failed to compile shader: %s\n", fname);
441 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
442 if(loglen > 0 && (buf = malloc(loglen + 1))) {
443 glGetShaderInfoLog(sdr, loglen, 0, buf);
456 unsigned int load_program(const char *vfname, const char *pfname)
458 unsigned int vs, ps, prog;
460 if(!(vs = load_shader(vfname, GL_VERTEX_SHADER))) {
463 if(!(ps = load_shader(pfname, GL_FRAGMENT_SHADER))) {
468 prog = glCreateProgram();
469 glAttachShader(prog, vs);
470 glAttachShader(prog, ps);
472 if(link_program(prog) == -1) {
475 glDeleteProgram(prog);
481 int link_program(unsigned int prog)
488 glGetProgramiv(prog, GL_LINK_STATUS, &status);
490 printf("successfully linked shader program\n");
492 printf("failed to link shader program\n");
495 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &loglen);
496 if(loglen > 0 && (buf = malloc(loglen + 1))) {
497 glGetProgramInfoLog(prog, loglen, 0, buf);
503 return status ? 0 : -1;
506 const char *gldebug_srcstr(unsigned int src)
509 case GL_DEBUG_SOURCE_API:
511 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
513 case GL_DEBUG_SOURCE_SHADER_COMPILER:
515 case GL_DEBUG_SOURCE_THIRD_PARTY:
517 case GL_DEBUG_SOURCE_APPLICATION:
519 case GL_DEBUG_SOURCE_OTHER:
527 const char *gldebug_typestr(unsigned int type)
530 case GL_DEBUG_TYPE_ERROR:
532 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
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:
548 void GLAPIENTRY gldebug(GLenum src, GLenum type, GLuint id, GLenum severity,
549 GLsizei len, const char *msg, const void *cls)
551 printf("[GLDEBUG] (%s) %s: %s\n", gldebug_srcstr(src), gldebug_typestr(type), msg);