/* * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * author: Jerome Glisse */ #define MAXFRAME 5 #define PFINISH 1 #define MAX_PARTICLES 256 #include #include #include #include #include #define GL_GLEXT_PROTOTYPES #include #include struct particle { float pos[4]; float vel[4]; }; static struct particle *particles; static GLuint particle_buffer[2]; static GLuint tfb_shader_prog; static GLuint tfb_vs_shader; static GLuint random_tex; static GLint ptime = 0; static GLfloat pdt = 0.0f; static GLuint curr_vb = 0; static GLuint frames = 0; static GLuint win_width = 1024; static GLuint win_height = 1024; static GLint attrib_velocity; static GLint uni_delta_time_ms; static GLint uni_tex; static const char tfb_shader_src[] = "#version 120 \n" " \n" "attribute vec4 velocity; \n" "attribute float age; \n" " \n" "varying vec4 ovelocity; \n" " \n" "uniform float dt; \n" "uniform sampler1D tex; \n" " \n" "void main() \n" "{ \n" " if (velocity.w > 5.0) { \n" " ovelocity = texture1D(tex, ovelocity.w); \n" " ovelocity -= vec4(0.5, 0.5, 0.5, 0.5); \n" " gl_Position = ovelocity * dt; \n" " } else { \n" " ovelocity = velocity; \n" " ovelocity.w = velocity.w + dt; \n" " gl_Position.xyz = gl_Vertex.xyz + velocity.xyz * dt; \n" " } \n" "} \n"; static void particles_update(void) { glUseProgram(tfb_shader_prog); glUniform1f(uni_delta_time_ms, pdt); glUniform1i(uni_tex, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_1D, random_tex); glBindBuffer(GL_ARRAY_BUFFER, particle_buffer[curr_vb]); glEnableVertexAttribArray(attrib_velocity); glVertexAttribPointer(attrib_velocity, 4, GL_FLOAT, GL_FALSE, sizeof(struct particle), (const GLvoid*)16); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(4, GL_FLOAT, sizeof(struct particle), 0); glEnable(GL_RASTERIZER_DISCARD); glBindBufferBaseEXT(GL_TRANSFORM_FEEDBACK_BUFFER, 0, particle_buffer[(curr_vb + 1) & 1]); glBeginTransformFeedback(GL_POINTS); glDrawArrays(GL_POINTS, 0, MAX_PARTICLES); glEndTransformFeedback(); glDisableClientState(GL_VERTEX_ARRAY); glDisableVertexAttribArray(attrib_velocity); glDisable(GL_RASTERIZER_DISCARD); glUseProgram(0); /* swap */ curr_vb = (curr_vb + 1) & 1; ptime += pdt; } void particle_draw() { float ar; ar = (float)win_width / win_height; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-ar, ar, -1.0, 1.0, 5.0, 60.0); glMatrixMode(GL_MODELVIEW); glPointSize(8.0); glColor3f(0,1,0); glBindBuffer(GL_ARRAY_BUFFER, particle_buffer[curr_vb]); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(struct particle), 0); glDrawArrays(GL_POINTS, 0, MAX_PARTICLES); glDisableClientState(GL_VERTEX_ARRAY); } static void draw(void) { #if PFINISH fprintf(stderr, "EE TFB -------------------------------------------------------\n"); #endif particles_update(); #if PFINISH glFinish(); fprintf(stderr, "EE TFB _______________________________________________________\n"); #endif #if PFINISH fprintf(stderr, "EE CLEAR -----------------------------------------------------\n"); #endif glClear(GL_COLOR_BUFFER_BIT); #if PFINISH glFinish(); fprintf(stderr, "EE CLEAR _____________________________________________________\n"); #endif #if PFINISH fprintf(stderr, "EE DRAW ------------------------------------------------------\n"); #endif particle_draw(); #if PFINISH glFinish(); fprintf(stderr, "EE DRAW ______________________________________________________\n"); #endif glutSwapBuffers(); frames++; if (frames >= MAXFRAME) { glFinish(); exit(0); } } static void idle(void) { static double t0 = -1.; double dt, t; t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; if (t0 < 0.0) t0 = t; dt = t - t0; t0 = t; pdt = dt; glutPostRedisplay(); } /* new window size or exposure */ static void reshape(int width, int height) { GLfloat h = (GLfloat) height / (GLfloat) width; glViewport(0, 0, (GLint) width, (GLint) height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -40.0); win_width = width; win_height = height; } float random_0to1(void) { return (float)rand() / RAND_MAX; } static void init(void) { size_t particles_size; const GLchar *p[1]; GLint len[1]; GLint status; const GLchar* varyings[4]; unsigned texsize = 512; float *randomtex; glDisable(GL_DEPTH_TEST); /* random texture */ srand(glutGet(GLUT_ELAPSED_TIME)); randomtex = malloc(texsize * 4 * 4); if (randomtex == NULL) { exit(1); } for (unsigned i = 0 ; i < (texsize * 4); i++) { randomtex[i] = random_0to1(); } glGenTextures(1, &random_tex); glBindTexture(GL_TEXTURE_1D, random_tex); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, texsize, 0.0f, GL_RGBA, GL_FLOAT, randomtex); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); free(randomtex); glBindTexture(GL_TEXTURE_1D, 0); particles_size = sizeof(*particles) * MAX_PARTICLES; particles = malloc(particles_size); if (particles == NULL) { exit(-ENOMEM); } glGenBuffers(2, particle_buffer); for (unsigned i = 0; i < MAX_PARTICLES; i++) { particles[i].pos[0] = random_0to1(); particles[i].pos[1] = random_0to1(); particles[i].pos[2] = random_0to1(); particles[i].pos[3] = 0.0f; particles[i].vel[0] = random_0to1() - 0.5f; particles[i].vel[1] = random_0to1() - 0.5f; particles[i].vel[2] = random_0to1() - 0.5f; particles[i].vel[3] = random_0to1() - 0.5f; } for (unsigned i = 0; i < 2 ; i++) { glBindBuffer(GL_ARRAY_BUFFER, particle_buffer[i]); glBufferData(GL_ARRAY_BUFFER, particles_size, particles, GL_DYNAMIC_DRAW); } free(particles); #if 1 /* tfb shader */ tfb_shader_prog = glCreateProgram(); tfb_vs_shader = glCreateShader(GL_VERTEX_SHADER); p[0] = tfb_shader_src; len[0] = strlen(tfb_shader_src); glShaderSource(tfb_vs_shader, 1, p, len); glCompileShader(tfb_vs_shader); glGetShaderiv(tfb_vs_shader, GL_COMPILE_STATUS, &status); if (!status) { GLchar log[1024]; glGetShaderInfoLog(tfb_vs_shader, 1024, NULL, log); fprintf(stderr, "Error compiling tfb vs shader %s: \n", log); exit(1); } glAttachShader(tfb_shader_prog, tfb_vs_shader); /* tfb linking */ varyings[0] = "gl_Position"; varyings[1] = "ovelocity"; glTransformFeedbackVaryings(tfb_shader_prog, 2, varyings, GL_INTERLEAVED_ATTRIBS); glLinkProgram(tfb_shader_prog); glGetProgramiv(tfb_shader_prog, GL_LINK_STATUS, &status); if (!status) { GLchar log[1024]; glGetProgramInfoLog(tfb_shader_prog, 1024, NULL, log); fprintf(stderr, "Error linking tfb shader %s: \n", log); exit(1); } glValidateProgram(tfb_shader_prog); glGetProgramiv(tfb_shader_prog, GL_VALIDATE_STATUS, &status); if (!status) { GLchar log[1024]; glGetProgramInfoLog(tfb_shader_prog, 1024, NULL, log); fprintf(stderr, "Invalid tfb shader program %s: \n", log); exit(1); } uni_delta_time_ms = glGetUniformLocation(tfb_shader_prog, "dt"); uni_tex = glGetUniformLocation(tfb_shader_prog, "tex"); attrib_velocity = glGetAttribLocation(tfb_shader_prog, "velocity"); if (attrib_velocity == -1) { fprintf(stderr, "invalid attribute location %d\n", attrib_velocity); exit(-1); } #endif } static void key(unsigned char k, int x, int y) { switch (k) { case 27: /* Escape */ exit(0); break; default: return; } glutPostRedisplay(); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | GLUT_STENCIL); glutInitWindowSize(win_width, win_height); glutCreateWindow("glgears"); GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); return -1; } if (!GLEW_EXT_transform_feedback) { fprintf(stderr, "EXT_transform_feedback not supported\n"); return -1; } glutKeyboardFunc(key); glutIdleFunc(idle); glutReshapeFunc(reshape); glutDisplayFunc(draw); init(); reshape(win_width, win_height); glutMainLoop(); return 0; }