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"))) {
135 glGenBuffers(1, &ubo_matrix);
136 glBindBuffer(GL_UNIFORM_BUFFER, ubo_matrix);
137 glBufferData(GL_UNIFORM_BUFFER, sizeof matrix_state, &matrix_state, GL_STREAM_DRAW);
147 glDeleteBuffers(1, &torus.vbo);
148 glDeleteBuffers(1, &torus.ibo);
151 glDeleteVertexArrays(1, &torus.vao);
153 glDeleteTextures(1, &tex);
154 glDeleteBuffers(1, &ubo_matrix);
159 matrix_state.lpos[0] = -10;
160 matrix_state.lpos[1] = 10;
161 matrix_state.lpos[2] = 10;
163 glClearColor(0.05, 0.05, 0.05, 1.0);
164 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
166 mat_identity(matrix_state.view_mat);
167 mat_translate(matrix_state.view_mat, 0, 0, -cam_dist);
168 mat_rotate(matrix_state.view_mat, cam_phi, 1, 0, 0);
169 mat_rotate(matrix_state.view_mat, cam_theta, 0, 1, 0);
171 mat_copy(matrix_state.mvmat, matrix_state.view_mat);
173 mat_copy(matrix_state.mvpmat, matrix_state.proj_mat);
174 mat_mul(matrix_state.mvpmat, matrix_state.mvmat);
176 mat_transform(matrix_state.view_mat, matrix_state.lpos);
180 glBindBuffer(GL_UNIFORM_BUFFER, ubo_matrix);
181 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof matrix_state, &matrix_state);
182 glBindBufferBase(GL_UNIFORM_BUFFER, UBLOCK_MATRIX, ubo_matrix);
184 glBindTexture(GL_TEXTURE_2D, tex);
187 assert(glGetError() == GL_NO_ERROR);
191 void reshape(int x, int y)
193 glViewport(0, 0, x, y);
195 mat_identity(matrix_state.proj_mat);
196 mat_perspective(matrix_state.proj_mat, 50.0, (float)x / (float)y, 0.5, 500.0);
199 void keypress(unsigned char key, int x, int y)
207 void mouse(int bn, int st, int x, int y)
209 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
214 void motion(int x, int y)
221 if(!dx && !dy) return;
224 cam_theta += dx * 0.5;
226 if(cam_phi < -90) cam_phi = -90;
227 if(cam_phi > 90) cam_phi = 90;
231 cam_dist += dy * 0.1;
232 if(cam_dist < 0.0) cam_dist = 0.0;
237 static void torus_vertex(struct vertex *vout, float rad, float rrad, float u, float v)
239 float theta = u * M_PI * 2.0;
240 float phi = v * M_PI * 2.0;
241 float rx, ry, rz, cx, cy, cz;
243 cx = sin(theta) * rad;
245 cz = -cos(theta) * rad;
247 rx = -cos(phi) * rrad + rad;
248 ry = sin(phi) * rrad;
251 vout->x = rx * sin(theta) + rz * cos(theta);
253 vout->z = -rx * cos(theta) + rz * sin(theta);
255 vout->nx = (vout->x - cx) / rrad;
256 vout->ny = (vout->y - cy) / rrad;
257 vout->nz = (vout->z - cz) / rrad;
264 int gen_torus(struct mesh *mesh, float rad, float rrad, int usub, int vsub)
266 int i, j, uverts, vverts, nverts, nquads, ntri;
268 float du = 1.0 / (float)usub;
269 float dv = 1.0 / (float)vsub;
273 if(usub < 3) usub = 3;
274 if(vsub < 3) vsub = 3;
279 nverts = uverts * vverts;
280 nquads = usub * vsub;
283 mesh->vcount = nverts;
284 mesh->icount = ntri * 3;
286 if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
287 fprintf(stderr, "failed to allocate vertex array for %d vertices\n", mesh->vcount);
291 if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
292 fprintf(stderr, "failed to allocate index array for %d indices\n", mesh->icount);
300 for(i=0; i<uverts; i++) {
302 for(j=0; j<vverts; j++) {
303 torus_vertex(vptr++, rad, rrad, u, v);
305 if(i < usub && j < vsub) {
306 int vnum = i * vverts + j;
308 *iptr++ = vnum + vverts + 1;
311 *iptr++ = vnum + vverts;
312 *iptr++ = vnum + vverts + 1;
320 glGenBuffers(1, &mesh->vbo);
321 glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
322 glBufferData(GL_ARRAY_BUFFER, mesh->vcount * sizeof *mesh->varr, mesh->varr, GL_STATIC_DRAW);
323 glBindBuffer(GL_ARRAY_BUFFER, 0);
325 glGenBuffers(1, &mesh->ibo);
326 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
327 glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->icount * sizeof *mesh->iarr, mesh->iarr, GL_STATIC_DRAW);
328 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
330 glGenVertexArrays(1, &mesh->vao);
331 glBindVertexArray(mesh->vao);
333 glEnableVertexAttribArray(VATTR_VERTEX);
334 glEnableVertexAttribArray(VATTR_NORMAL);
335 glEnableVertexAttribArray(VATTR_TEXCOORD);
337 glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
338 glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), 0);
339 glVertexAttribPointer(VATTR_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, nx));
340 glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, tu));
341 glBindBuffer(GL_ARRAY_BUFFER, 0);
343 glBindVertexArray(0);
347 void draw_mesh(struct mesh *mesh)
349 glBindVertexArray(mesh->vao);
351 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
352 glDrawElements(GL_TRIANGLES, mesh->icount, GL_UNSIGNED_INT, 0);
353 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
355 glBindVertexArray(0);
358 unsigned int gen_texture(int width, int height)
362 unsigned char *pixels, *ptr;
364 if(!(pixels = malloc(width * height * 3))) {
369 for(i=0; i<height; i++) {
370 for(j=0; j<width; j++) {
373 *ptr++ = (x << 1) & 0xff;
374 *ptr++ = (x << 2) & 0xff;
378 glGenTextures(1, &tex);
379 glBindTexture(GL_TEXTURE_2D, tex);
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
381 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
382 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
383 glGenerateMipmap(GL_TEXTURE_2D);
389 unsigned int load_shader(const char *fname, int type)
397 if(!(fp = fopen(fname, "rb"))) {
398 fprintf(stderr, "failed to open shader: %s\n", fname);
401 fseek(fp, 0, SEEK_END);
405 if(!(buf = malloc(fsz + 1))) {
406 fprintf(stderr, "failed to allocate %d bytes\n", fsz + 1);
410 if(fread(buf, 1, fsz, fp) < fsz) {
411 fprintf(stderr, "failed to read shader: %s\n", fname);
419 sdr = glCreateShader(type);
422 glShaderSource(sdr, 1, (const char**)&buf, 0);
423 glCompileShader(sdr);
425 glShaderBinary(1, &sdr, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, buf, fsz);
426 gl_specialize_shader(sdr, "main", 0, 0, 0);
430 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
432 printf("successfully compiled shader: %s\n", fname);
434 printf("failed to compile shader: %s\n", fname);
437 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
438 if(loglen > 0 && (buf = malloc(loglen + 1))) {
439 glGetShaderInfoLog(sdr, loglen, 0, buf);
452 unsigned int load_program(const char *vfname, const char *pfname)
454 unsigned int vs, ps, prog;
456 if(!(vs = load_shader(vfname, GL_VERTEX_SHADER))) {
459 if(!(ps = load_shader(pfname, GL_FRAGMENT_SHADER))) {
464 prog = glCreateProgram();
465 glAttachShader(prog, vs);
466 glAttachShader(prog, ps);
468 if(link_program(prog) == -1) {
471 glDeleteProgram(prog);
475 glDetachShader(prog, vs);
476 glDetachShader(prog, ps);
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);