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 glDebugMessageCallback(gldebug, 0);
107 glEnable(GL_DEPTH_TEST);
108 glEnable(GL_CULL_FACE);
110 gl_specialize_shader = (PFNGLSPECIALIZESHADERPROC)glXGetProcAddress((unsigned char*)"glSpecializeShaderARB");
111 if(!gl_specialize_shader) {
112 fprintf(stderr, "failed to load glSpecializeShaderARB entry point\n");
116 if(!(tex = gen_texture(256, 256))) {
120 glGenSamplers(1, &sampler);
121 glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
122 glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
124 if(gen_torus(&torus, 1.0, 0.25, 32, 12) == -1) {
129 if(!(sdr = load_program("vertex.glsl", "pixel.glsl"))) {
133 if(!(sdr = load_program("spirv/vertex.spv", "spirv/pixel.spv"))) {
138 if(link_program(sdr) == -1) {
139 fprintf(stderr, "failed to bind attribute locations\n");
145 glGenBuffers(1, &ubo_matrix);
146 glBindBuffer(GL_UNIFORM_BUFFER, ubo_matrix);
147 glBufferData(GL_UNIFORM_BUFFER, sizeof matrix_state, &matrix_state, GL_STREAM_DRAW);
157 glDeleteBuffers(1, &torus.vbo);
158 glDeleteBuffers(1, &torus.ibo);
161 glDeleteVertexArrays(1, &torus.vao);
163 glDeleteTextures(1, &tex);
164 glDeleteSamplers(1, &sampler);
169 matrix_state.lpos[0] = -10;
170 matrix_state.lpos[1] = 10;
171 matrix_state.lpos[2] = 10;
173 glClearColor(0.05, 0.05, 0.05, 1.0);
174 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
176 mat_identity(matrix_state.view_mat);
177 mat_translate(matrix_state.view_mat, 0, 0, -cam_dist);
178 mat_rotate(matrix_state.view_mat, cam_phi, 1, 0, 0);
179 mat_rotate(matrix_state.view_mat, cam_theta, 0, 1, 0);
181 mat_copy(matrix_state.mvmat, matrix_state.view_mat);
183 mat_copy(matrix_state.mvpmat, matrix_state.proj_mat);
184 mat_mul(matrix_state.mvpmat, matrix_state.mvmat);
186 mat_transform(matrix_state.view_mat, matrix_state.lpos);
190 glBindBuffer(GL_UNIFORM_BUFFER, ubo_matrix);
191 glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof matrix_state, &matrix_state);
192 glBindBufferBase(GL_UNIFORM_BUFFER, UBLOCK_MATRIX, ubo_matrix);
194 glBindTexture(GL_TEXTURE_2D, tex);
195 glBindSampler(0, sampler);
199 assert(glGetError() == GL_NO_ERROR);
203 void reshape(int x, int y)
205 glViewport(0, 0, x, y);
207 mat_identity(matrix_state.proj_mat);
208 mat_perspective(matrix_state.proj_mat, 50.0, (float)x / (float)y, 0.5, 500.0);
211 void keypress(unsigned char key, int x, int y)
219 void mouse(int bn, int st, int x, int y)
221 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN ? 1 : 0;
226 void motion(int x, int y)
233 if(!dx && !dy) return;
236 cam_theta += dx * 0.5;
238 if(cam_phi < -90) cam_phi = -90;
239 if(cam_phi > 90) cam_phi = 90;
243 cam_dist += dy * 0.1;
244 if(cam_dist < 0.0) cam_dist = 0.0;
249 static void torus_vertex(struct vertex *vout, float rad, float rrad, float u, float v)
251 float theta = u * M_PI * 2.0;
252 float phi = v * M_PI * 2.0;
253 float rx, ry, rz, cx, cy, cz;
255 cx = sin(theta) * rad;
257 cz = -cos(theta) * rad;
259 rx = -cos(phi) * rrad + rad;
260 ry = sin(phi) * rrad;
263 vout->x = rx * sin(theta) + rz * cos(theta);
265 vout->z = -rx * cos(theta) + rz * sin(theta);
267 vout->nx = (vout->x - cx) / rrad;
268 vout->ny = (vout->y - cy) / rrad;
269 vout->nz = (vout->z - cz) / rrad;
276 int gen_torus(struct mesh *mesh, float rad, float rrad, int usub, int vsub)
278 int i, j, uverts, vverts, nverts, nquads, ntri;
280 float du = 1.0 / (float)usub;
281 float dv = 1.0 / (float)vsub;
285 if(usub < 3) usub = 3;
286 if(vsub < 3) vsub = 3;
291 nverts = uverts * vverts;
292 nquads = usub * vsub;
295 mesh->vcount = nverts;
296 mesh->icount = ntri * 3;
298 if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
299 fprintf(stderr, "failed to allocate vertex array for %d vertices\n", mesh->vcount);
303 if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
304 fprintf(stderr, "failed to allocate index array for %d indices\n", mesh->icount);
312 for(i=0; i<uverts; i++) {
314 for(j=0; j<vverts; j++) {
315 torus_vertex(vptr++, rad, rrad, u, v);
317 if(i < usub && j < vsub) {
318 int vnum = i * vverts + j;
320 *iptr++ = vnum + vverts + 1;
323 *iptr++ = vnum + vverts;
324 *iptr++ = vnum + vverts + 1;
332 glGenBuffers(1, &mesh->vbo);
333 glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
334 glBufferData(GL_ARRAY_BUFFER, mesh->vcount * sizeof *mesh->varr, mesh->varr, GL_STATIC_DRAW);
335 glBindBuffer(GL_ARRAY_BUFFER, 0);
337 glGenBuffers(1, &mesh->ibo);
338 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
339 glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh->icount * sizeof *mesh->iarr, mesh->iarr, GL_STATIC_DRAW);
340 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
342 glGenVertexArrays(1, &mesh->vao);
343 glBindVertexArray(mesh->vao);
345 glEnableVertexAttribArray(VATTR_VERTEX);
346 glEnableVertexAttribArray(VATTR_NORMAL);
347 glEnableVertexAttribArray(VATTR_TEXCOORD);
349 glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
350 glVertexAttribPointer(VATTR_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), 0);
351 glVertexAttribPointer(VATTR_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, nx));
352 glVertexAttribPointer(VATTR_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (void*)offsetof(struct vertex, tu));
353 glBindBuffer(GL_ARRAY_BUFFER, 0);
355 glBindVertexArray(0);
359 void draw_mesh(struct mesh *mesh)
361 glBindVertexArray(mesh->vao);
363 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ibo);
364 glDrawElements(GL_TRIANGLES, mesh->icount, GL_UNSIGNED_INT, 0);
365 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
367 glBindVertexArray(0);
370 unsigned int gen_texture(int width, int height)
374 unsigned char *pixels, *ptr;
376 if(!(pixels = malloc(width * height * 3))) {
381 for(i=0; i<height; i++) {
382 for(j=0; j<width; j++) {
385 *ptr++ = (x << 1) & 0xff;
386 *ptr++ = (x << 2) & 0xff;
390 glGenTextures(1, &tex);
391 glBindTexture(GL_TEXTURE_2D, tex);
392 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
393 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
394 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels);
395 glGenerateMipmap(GL_TEXTURE_2D);
401 unsigned int load_shader(const char *fname, int type)
409 if(!(fp = fopen(fname, "rb"))) {
410 fprintf(stderr, "failed to open shader: %s\n", fname);
413 fseek(fp, 0, SEEK_END);
417 if(!(buf = malloc(fsz + 1))) {
418 fprintf(stderr, "failed to allocate %d bytes\n", fsz + 1);
422 if(fread(buf, 1, fsz, fp) < fsz) {
423 fprintf(stderr, "failed to read shader: %s\n", fname);
431 sdr = glCreateShader(type);
434 glShaderSource(sdr, 1, (const char**)&buf, 0);
435 glCompileShader(sdr);
437 glShaderBinary(1, &sdr, GL_SHADER_BINARY_FORMAT_SPIR_V_ARB, buf, fsz);
438 gl_specialize_shader(sdr, "main", 0, 0, 0);
442 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
444 printf("successfully compiled shader: %s\n", fname);
446 printf("failed to compile shader: %s\n", fname);
449 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
450 if(loglen > 0 && (buf = malloc(loglen + 1))) {
451 glGetShaderInfoLog(sdr, loglen, 0, buf);
464 unsigned int load_program(const char *vfname, const char *pfname)
466 unsigned int vs, ps, prog;
468 if(!(vs = load_shader(vfname, GL_VERTEX_SHADER))) {
471 if(!(ps = load_shader(pfname, GL_FRAGMENT_SHADER))) {
476 prog = glCreateProgram();
477 glAttachShader(prog, vs);
478 glAttachShader(prog, ps);
480 if(link_program(prog) == -1) {
483 glDeleteProgram(prog);
489 int link_program(unsigned int prog)
496 glGetProgramiv(prog, GL_LINK_STATUS, &status);
498 printf("successfully linked shader program\n");
500 printf("failed to link shader program\n");
503 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &loglen);
504 if(loglen > 0 && (buf = malloc(loglen + 1))) {
505 glGetProgramInfoLog(prog, loglen, 0, buf);
511 return status ? 0 : -1;
514 const char *gldebug_srcstr(unsigned int src)
517 case GL_DEBUG_SOURCE_API:
519 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
521 case GL_DEBUG_SOURCE_SHADER_COMPILER:
523 case GL_DEBUG_SOURCE_THIRD_PARTY:
525 case GL_DEBUG_SOURCE_APPLICATION:
527 case GL_DEBUG_SOURCE_OTHER:
535 const char *gldebug_typestr(unsigned int type)
538 case GL_DEBUG_TYPE_ERROR:
540 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
542 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
543 return "undefined behavior";
544 case GL_DEBUG_TYPE_PORTABILITY:
545 return "portability";
546 case GL_DEBUG_TYPE_PERFORMANCE:
547 return "performance";
548 case GL_DEBUG_TYPE_OTHER:
556 void GLAPIENTRY gldebug(GLenum src, GLenum type, GLuint id, GLenum severity,
557 GLsizei len, const char *msg, const void *cls)
559 printf("[GLDEBUG] (%s) %s: %s\n", gldebug_srcstr(src), gldebug_typestr(type), msg);