6 #include <GL/freeglut.h>
34 unsigned int vbo, ibo, vao;
43 } __attribute__((packed));
51 void reshape(int x, int y);
52 void keypress(unsigned char key, int x, int y);
53 void mouse(int bn, int st, int x, int y);
54 void motion(int x, int y);
56 int gen_torus(struct mesh *mesh, float rad, float rrad, int usub, int vsub);
57 void draw_mesh(struct mesh *mesh);
58 unsigned int gen_texture(int width, int height);
60 unsigned int load_shader(const char *fname, int type);
61 unsigned int load_program(const char *vfname, const char *pfname);
62 int link_program(unsigned int prog);
64 void GLAPIENTRY gldebug(GLenum src, GLenum type, GLuint id, GLenum severity,
65 GLsizei len, const char *msg, const void *cls);
67 float cam_theta, cam_phi = 25, cam_dist = 4;
68 int prev_x, prev_y, bnstate[8];
74 struct matrix_state matrix_state;
76 unsigned int ubo_matrix;
78 static PFNGLSPECIALIZESHADERPROC gl_specialize_shader;
80 int main(int argc, char **argv)
82 glutInit(&argc, argv);
83 glutInitWindowSize(800, 600);
84 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
85 glutInitContextProfile(GLUT_CORE_PROFILE);
86 glutInitContextVersion(4, 4);
87 glutCreateWindow("GL4 test");
89 glutDisplayFunc(display);
90 glutReshapeFunc(reshape);
91 glutKeyboardFunc(keypress);
93 glutMotionFunc(motion);
106 unsigned int uloc_matrix;
108 glDebugMessageCallback(gldebug, 0);
109 glEnable(GL_DEPTH_TEST);
110 glEnable(GL_CULL_FACE);
112 gl_specialize_shader = (PFNGLSPECIALIZESHADERPROC)glXGetProcAddress((unsigned char*)"glSpecializeShaderARB");
113 if(!gl_specialize_shader) {
114 fprintf(stderr, "failed to load glSpecializeShaderARB entry point\n");
118 if(!(tex = gen_texture(256, 256))) {
122 glGenSamplers(1, &sampler);
123 glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
124 glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
126 if(gen_torus(&torus, 1.0, 0.25, 32, 12) == -1) {
131 if(!(sdr = load_program("vertex.glsl", "pixel.glsl"))) {
135 if(!(sdr = load_program("spirv/vertex.spv", "spirv/pixel.spv"))) {
140 if(link_program(sdr) == -1) {
141 fprintf(stderr, "failed to bind attribute locations\n");
147 glGenBuffers(1, &ubo_matrix);
148 glBindBuffer(GL_UNIFORM_BUFFER, ubo_matrix);
149 glBufferData(GL_UNIFORM_BUFFER, sizeof matrix_state, &matrix_state, GL_STREAM_DRAW);
150 uloc_matrix = glGetUniformBlockIndex(sdr, "matrix_state");
151 glUniformBlockBinding(sdr, uloc_matrix, UBLOCK_MATRIX);
161 glDeleteBuffers(1, &torus.vbo);
162 glDeleteBuffers(1, &torus.ibo);
165 glDeleteVertexArrays(1, &torus.vao);
167 glDeleteTextures(1, &tex);
168 glDeleteSamplers(1, &sampler);
173 matrix_state.lpos[0] = -10;
174 matrix_state.lpos[1] = 10;
175 matrix_state.lpos[2] = 10;
177 glClearColor(0.05, 0.05, 0.05, 1.0);
178 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
180 mat_identity(matrix_state.view_mat);
181 mat_translate(matrix_state.view_mat, 0, 0, -cam_dist);
182 mat_rotate(matrix_state.view_mat, cam_phi, 1, 0, 0);
183 mat_rotate(matrix_state.view_mat, cam_theta, 0, 1, 0);
185 mat_copy(matrix_state.mvmat, matrix_state.view_mat);
187 mat_copy(matrix_state.mvpmat, matrix_state.proj_mat);
188 mat_mul(matrix_state.mvpmat, matrix_state.mvmat);
190 mat_transform(matrix_state.view_mat, matrix_state.lpos);
194 glBindBuffer(GL_UNIFORM_BUFFER, ubo_matrix);
195 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof matrix_state, &matrix_state);
196 glBindBufferBase(GL_UNIFORM_BUFFER, UBLOCK_MATRIX, ubo_matrix);
198 glBindTexture(GL_TEXTURE_2D, tex);
199 glBindSampler(0, sampler);
203 //assert(glGetError() == GL_NO_ERROR);
207 void reshape(int x, int y)
209 glViewport(0, 0, x, y);
211 mat_identity(matrix_state.proj_mat);
212 mat_perspective(matrix_state.proj_mat, 50.0, (float)x / (float)y, 0.5, 500.0);
215 void keypress(unsigned char key, int x, int y)
223 void mouse(int bn, int st, int x, int y)
225 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
230 void motion(int x, int y)
237 if(!dx && !dy) return;
240 cam_theta += dx * 0.5;
242 if(cam_phi < -90) cam_phi = -90;
243 if(cam_phi > 90) cam_phi = 90;
247 cam_dist += dy * 0.1;
248 if(cam_dist < 0.0) cam_dist = 0.0;
253 static void torus_vertex(struct vertex *vout, float rad, float rrad, float u, float v)
255 float theta = u * M_PI * 2.0;
256 float phi = v * M_PI * 2.0;
257 float rx, ry, rz, cx, cy, cz;
259 cx = sin(theta) * rad;
261 cz = -cos(theta) * rad;
263 rx = -cos(phi) * rrad + rad;
264 ry = sin(phi) * rrad;
267 vout->x = rx * sin(theta) + rz * cos(theta);
269 vout->z = -rx * cos(theta) + rz * sin(theta);
271 vout->nx = (vout->x - cx) / rrad;
272 vout->ny = (vout->y - cy) / rrad;
273 vout->nz = (vout->z - cz) / rrad;
280 int gen_torus(struct mesh *mesh, float rad, float rrad, int usub, int vsub)
282 int i, j, uverts, vverts, nverts, nquads, ntri;
284 float du = 1.0 / (float)usub;
285 float dv = 1.0 / (float)vsub;
289 if(usub < 3) usub = 3;
290 if(vsub < 3) vsub = 3;
295 nverts = uverts * vverts;
296 nquads = usub * vsub;
299 mesh->vcount = nverts;
300 mesh->icount = ntri * 3;
302 if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
303 fprintf(stderr, "failed to allocate vertex array for %d vertices\n", mesh->vcount);
307 if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
308 fprintf(stderr, "failed to allocate index array for %d indices\n", mesh->icount);
316 for(i=0; i<uverts; i++) {
318 for(j=0; j<vverts; j++) {
319 torus_vertex(vptr++, rad, rrad, u, v);
321 if(i < usub && j < vsub) {
322 int vnum = i * vverts + j;
324 *iptr++ = vnum + vverts + 1;
327 *iptr++ = vnum + vverts;
328 *iptr++ = vnum + vverts + 1;
336 glGenBuffers(1, &mesh->vbo);
337 glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
338 glBufferData(GL_ARRAY_BUFFER, mesh->vcount * sizeof *mesh->varr, mesh->varr, GL_STATIC_DRAW);
339 glBindBuffer(GL_ARRAY_BUFFER, 0);
341 glGenBuffers(1, &mesh->ibo);
342 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
343 glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->icount * sizeof *mesh->iarr, mesh->iarr, GL_STATIC_DRAW);
344 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
346 glGenVertexArrays(1, &mesh->vao);
347 glBindVertexArray(mesh->vao);
349 glEnableVertexAttribArray(VATTR_VERTEX);
350 glEnableVertexAttribArray(VATTR_NORMAL);
351 glEnableVertexAttribArray(VATTR_TEXCOORD);
353 glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
354 glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), 0);
355 glVertexAttribPointer(VATTR_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, nx));
356 glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, tu));
357 glBindBuffer(GL_ARRAY_BUFFER, 0);
359 glBindVertexArray(0);
363 void draw_mesh(struct mesh *mesh)
365 glBindVertexArray(mesh->vao);
367 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
368 glDrawElements(GL_TRIANGLES, mesh->icount, GL_UNSIGNED_INT, 0);
369 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
371 glBindVertexArray(0);
374 unsigned int gen_texture(int width, int height)
378 unsigned char *pixels, *ptr;
380 if(!(pixels = malloc(width * height * 3))) {
385 for(i=0; i<height; i++) {
386 for(j=0; j<width; j++) {
389 *ptr++ = (x << 1) & 0xff;
390 *ptr++ = (x << 2) & 0xff;
394 glGenTextures(1, &tex);
395 glBindTexture(GL_TEXTURE_2D, tex);
396 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
397 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
398 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
399 glGenerateMipmap(GL_TEXTURE_2D);
405 unsigned int load_shader(const char *fname, int type)
413 if(!(fp = fopen(fname, "rb"))) {
414 fprintf(stderr, "failed to open shader: %s\n", fname);
417 fseek(fp, 0, SEEK_END);
421 if(!(buf = malloc(fsz + 1))) {
422 fprintf(stderr, "failed to allocate %d bytes\n", fsz + 1);
426 if(fread(buf, 1, fsz, fp) < fsz) {
427 fprintf(stderr, "failed to read shader: %s\n", fname);
435 sdr = glCreateShader(type);
438 glShaderSource(sdr, 1, (const char**)&buf, 0);
439 glCompileShader(sdr);
441 glShaderBinary(1, &sdr, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, buf, fsz);
442 gl_specialize_shader(sdr, "main", 0, 0, 0);
446 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
448 printf("successfully compiled shader: %s\n", fname);
450 printf("failed to compile shader: %s\n", fname);
453 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
454 if(loglen > 0 && (buf = malloc(loglen + 1))) {
455 glGetShaderInfoLog(sdr, loglen, 0, buf);
468 unsigned int load_program(const char *vfname, const char *pfname)
470 unsigned int vs, ps, prog;
472 if(!(vs = load_shader(vfname, GL_VERTEX_SHADER))) {
475 if(!(ps = load_shader(pfname, GL_FRAGMENT_SHADER))) {
480 prog = glCreateProgram();
481 glAttachShader(prog, vs);
482 glAttachShader(prog, ps);
484 if(link_program(prog) == -1) {
487 glDeleteProgram(prog);
493 int link_program(unsigned int prog)
500 glGetProgramiv(prog, GL_LINK_STATUS, &status);
502 printf("successfully linked shader program\n");
504 printf("failed to link shader program\n");
507 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &loglen);
508 if(loglen > 0 && (buf = malloc(loglen + 1))) {
509 glGetProgramInfoLog(prog, loglen, 0, buf);
515 return status ? 0 : -1;
518 const char *gldebug_srcstr(unsigned int src)
521 case GL_DEBUG_SOURCE_API:
523 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
525 case GL_DEBUG_SOURCE_SHADER_COMPILER:
527 case GL_DEBUG_SOURCE_THIRD_PARTY:
529 case GL_DEBUG_SOURCE_APPLICATION:
531 case GL_DEBUG_SOURCE_OTHER:
539 const char *gldebug_typestr(unsigned int type)
542 case GL_DEBUG_TYPE_ERROR:
544 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
546 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
547 return "undefined behavior";
548 case GL_DEBUG_TYPE_PORTABILITY:
549 return "portability";
550 case GL_DEBUG_TYPE_PERFORMANCE:
551 return "performance";
552 case GL_DEBUG_TYPE_OTHER:
560 void GLAPIENTRY gldebug(GLenum src, GLenum type, GLuint id, GLenum severity,
561 GLsizei len, const char *msg, const void *cls)
563 printf("[GLDEBUG] (%s) %s: %s\n", gldebug_srcstr(src), gldebug_typestr(type), msg);