/* gears.c Copyright 2003-2009, NVIDIA Corporation. All rights Reserved. THE INFORMATION CONTAINED HEREIN IS PROPRIETARY AND CONFIDENTIAL TO NVIDIA, CORPORATION. USE, REPRODUCTION OR DISCLOSURE TO ANY THIRD PARTY IS SUBJECT TO WRITTEN PRE-APPROVAL BY NVIDIA, CORPORATION. */ // // OpenGLES 2.0 port of gears demo. // #include #include #include #include #include #include #include #include "nvgl2demo_common.h" GLuint NvGl2DemoLoadShaderHex( const char* vertSource, const char* fragSource ); static void cleanup( ); // The default number of seconds after which the test will end. #define TIME_LIMIT 5.0 // Camera orientation #define VIEW_ROTX 20.0f #define VIEW_ROTY 30.0f #define VIEW_ROTZ 0.0f static const char gearVertShaderHex[] = { # include "gears_vert.glslv.hex" , 0x00}; static const char gearFragShaderHex[] = { # include "gears_frag.glslf.hex" , 0x00}; // Vertex data describing the gears typedef struct { int teeth; GLfloat *vertices; GLfloat *normals; GLushort *frontbody; GLushort *frontteeth; GLushort *backbody; GLushort *backteeth; GLushort *outer; GLushort *inner; } Gear; // Gear structures and matrices static Gear* gear1 = KD_NULL; static Gear* gear2 = KD_NULL; static Gear* gear3 = KD_NULL; static GLfloat gear1_mat[16]; static GLfloat gear2_mat[16]; static GLfloat gear3_mat[16]; //static GLfloat normal_mat[16]; // Shader program to use for gears and indices of attributes static GLuint gearShaderProgram = 0; static GLuint mview_mat_index; static GLuint material_index; static GLuint pos_index; static GLuint nrm_index; static GLboolean shutdown = GL_FALSE; static GLuint s_FBO; static GLuint s_RBO; static GLuint s_Tex; //============================================================================= // // Start of sample plugin code for UIComposer // //============================================================================= #include "UICPluginDLL.h" // forward declaration for gears render static void render(void); static int init(void); long GetPluginType( ) { return EDLLTYPE_RENDERABLE_PLUGIN; } long Initialize( const char* inArg ) { #ifndef _LINUXPLATFORM InitializeGLES2(); #endif // App initialization if ( init( ) ) { glUseProgram( 0 ); return EDLLSTATUS_OK; } return EDLLSTATUS_FAIL; } long Uninitialize( ) { cleanup( ); return 1; } void GetDesiredTextureSize( long* outWidth, long* outHeight, ETEXTUREFORMAT *outTextureFormat ) { // Desired offscreen texture dimensions *outWidth = 320; *outHeight = 240; *outTextureFormat = ETEXTUREFORMAT_ANY; } void SetEGLInfo( void* inEGLDisplay, void* inEGLCurrentContext, void* inEGLSurface, void* inEGLConfig ) { } void SetAllocatedRenderInfo( long inFBO, long inRBO, long inTex, ETEXTUREFORMAT inTextureFormat ) { s_FBO = inFBO; s_RBO = inRBO; s_Tex = inTex; } void Render( long inHostWidth, long inHostHeight, long inDrawTime ) { // Activate offscreen rendering glBindFramebuffer( GL_FRAMEBUFFER, s_FBO ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s_Tex, 0 ); glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, s_RBO ); // Disable vertex/index buffers glBindBuffer( GL_ARRAY_BUFFER, 0 ); glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); // App render glUseProgram( gearShaderProgram ); glViewport(0, 0, inHostWidth, inHostHeight); glDisable( GL_CULL_FACE ); render( ); glEnable( GL_CULL_FACE ); glBindFramebuffer( GL_FRAMEBUFFER, 0 ); } //============================================================================= // // End of sample plugin code for UIComposer // //============================================================================= // Make a gear wheel. You'll probably want to call this function when // building a display list since we do a lot of trig here. // // Input: inner_radius - radius of hole at center // outer_radius - radius at center of teeth // width - width of gear // teeth - number of teeth // tooth_depth - depth of tooth static Gear *makegear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, int teeth, GLfloat tooth_depth) { Gear *gear; GLfloat r0, r1, r2, da, hw; GLfloat *vert, *norm; GLushort *index, *indexF, *indexB; int i; // Create gear structure and arrays of vertex/index data gear = (Gear *)kdMalloc(sizeof(Gear)); gear->teeth = teeth; gear->vertices = (GLfloat*) kdMalloc(20*teeth*3*sizeof(GLfloat)); gear->normals = (GLfloat*) kdMalloc(20*teeth*3*sizeof(GLfloat)); gear->frontbody = (GLushort*)kdMalloc((4*teeth+2)*sizeof(GLushort)); gear->frontteeth = (GLushort*)kdMalloc(4*teeth*sizeof(GLushort)); gear->backbody = (GLushort*)kdMalloc((4*teeth+2)*sizeof(GLushort)); gear->backteeth = (GLushort*)kdMalloc(4*teeth*sizeof(GLushort)); gear->outer = (GLushort*)kdMalloc((16*teeth+2)*sizeof(GLushort)); gear->inner = (GLushort*)kdMalloc((4*teeth+2)*sizeof(GLushort)); // Set up vertices r0 = inner_radius; r1 = outer_radius - 0.5f * tooth_depth; r2 = outer_radius + 0.5f * tooth_depth; hw = 0.5f * width; da = (GLfloat)(0.5f * KD_PI_F / teeth); vert = gear->vertices; norm = gear->normals; for (i=0; ifrontbody; indexB = gear->backbody; for (i=0; ifrontteeth; indexB = gear->backteeth; for (i=0; iinner; for (i=0; iouter; for (i=0; ivertices); glVertexAttribPointer(nrm_index, 3, GL_FLOAT, 0, 0, gear->normals); glEnableVertexAttribArray(pos_index); glDisableVertexAttribArray(nrm_index); // Set the constant normal for front side glVertexAttrib3fv(nrm_index, norm_front); // Draw circular part of front side glDrawElements(GL_TRIANGLE_STRIP, 4*gear->teeth + 2, GL_UNSIGNED_SHORT, gear->frontbody); // Draw front side teeth for (i=0; iteeth; i++) { glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, &gear->frontteeth[4*i]); } // Set the constant normal for back side glVertexAttrib3fv(nrm_index, norm_back); // Draw circular part of front side glDrawElements(GL_TRIANGLE_STRIP, 4*gear->teeth + 2, GL_UNSIGNED_SHORT, gear->backbody); // Draw back side teeth for (i = 0; i < gear->teeth; i++) { glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, &gear->backteeth[4*i]); } // Enable normal pointers for the inner and outer faces glEnableVertexAttribArray(nrm_index); // Draw outer faces of teeth glDrawElements(GL_TRIANGLE_STRIP, 16*gear->teeth + 2, GL_UNSIGNED_SHORT, gear->outer); // Draw inside radius cylinder glDrawElements(GL_TRIANGLE_STRIP, 4*gear->teeth + 2, GL_UNSIGNED_SHORT, gear->inner); } // Free a gear structure static void freegear(Gear *gear) { kdFree(gear->inner); kdFree(gear->outer); kdFree(gear->backteeth); kdFree(gear->backbody); kdFree(gear->frontteeth); kdFree(gear->frontbody); kdFree(gear->normals); kdFree(gear->vertices); kdFree(gear); } // Initialize rendering static int init(void) { // Scene constants const GLfloat light_pos[4] = {1.0f, 3.0f, 5.0f, 0.0f}; const GLfloat nearz = 5.0f; const GLfloat farz = 60.0f; GLuint index; GLfloat aspect; GLfloat proj_mat[16]; GLfloat scene_mat[16]; GLfloat light_norm, light_dir[4]; long error = 0; // Otherwise, load and compile the shader source gearShaderProgram = NvGl2DemoLoadShaderHex( gearVertShaderHex, gearFragShaderHex); // Use the program we just loaded if (!gearShaderProgram) return 0; glUseProgram(gearShaderProgram); // Compute and load the projection matrix aspect = 1.0f; //(GLfloat)gfxState.height / (GLfloat)gfxState.width; NvGl2DemoMatrixIdentity(proj_mat); NvGl2DemoMatrixFrustum(proj_mat, -1.0f, 1.0f, -aspect, aspect, nearz, farz); index = glGetUniformLocation(gearShaderProgram, "proj_mat"); glUniformMatrix4fv(index, 1, 0, proj_mat); // Using a directional light, so find the normalized vector and load light_norm = (GLfloat)( kdInvsqrtf(light_pos[0]*light_pos[0] +light_pos[1]*light_pos[1] +light_pos[2]*light_pos[2] +light_pos[3]*light_pos[3])); light_dir[0] = light_pos[0] * light_norm; light_dir[1] = light_pos[1] * light_norm; light_dir[2] = light_pos[2] * light_norm; light_dir[3] = light_pos[3] * light_norm; index = glGetUniformLocation(gearShaderProgram, "light_dir"); glUniform3fv(index, 1, light_dir); // Get indices for uniforms and attributes updated each frame mview_mat_index = glGetUniformLocation(gearShaderProgram, "mview_mat"); material_index = glGetUniformLocation(gearShaderProgram, "material"); pos_index = glGetAttribLocation(gearShaderProgram, "pos_attr"); nrm_index = glGetAttribLocation(gearShaderProgram, "nrm_attr"); // Create gear data gear1 = makegear(1.0f, 4.0f, 1.0f, 20, 0.7f); gear2 = makegear(0.5f, 2.0f, 2.0f, 10, 0.7f); gear3 = makegear(1.3f, 2.0f, 0.5f, 10, 0.7f); // Set up the global scene matrix NvGl2DemoMatrixIdentity(scene_mat); NvGl2DemoMatrixTranslate(scene_mat, 0.0f, 0.0f, -40.0f); NvGl2DemoMatrixRotate(scene_mat, VIEW_ROTX, 1.0f, 0.0f, 0.0f); NvGl2DemoMatrixRotate(scene_mat, VIEW_ROTY, 0.0f, 1.0f, 0.0f); NvGl2DemoMatrixRotate(scene_mat, VIEW_ROTZ, 0.0f, 0.0f, 1.0f); // Set up the individual gear matrices kdMemcpy(gear1_mat, scene_mat, 16*sizeof(GLfloat)); NvGl2DemoMatrixTranslate(gear1_mat, -3.0f, -2.0f, 0.0f); kdMemcpy(gear2_mat, scene_mat, 16*sizeof(GLfloat)); NvGl2DemoMatrixTranslate(gear2_mat, 3.1f, -2.0f, 0.0f); kdMemcpy(gear3_mat, scene_mat, 16*sizeof(GLfloat)); NvGl2DemoMatrixTranslate(gear3_mat, -3.1f, 4.2f, 0.0f); // Enable depth testing glEnable(GL_DEPTH_TEST); return 1; } // Draw a frame static void render(void) { static GLfloat red [3] = {0.8f, 0.1f, 0.0f}; static GLfloat green[3] = {0.0f, 0.8f, 0.2f}; static GLfloat blue [3] = {0.2f, 0.2f, 1.0f}; GLfloat mview_mat[16]; // Rotate the gears static int angle = 0; // We can wrap around the angle without breaking continuity of the // animation as long as we multiply it only by integers for different // rotating elements that it controls. angle = (angle + 2) % 360; // Clear the buffers glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Transform, color, and draw gear 1 kdMemcpy(mview_mat, gear1_mat, 16*sizeof(float)); NvGl2DemoMatrixRotate(mview_mat, (float)angle, 0.0f, 0.0f, 1.0f); glUniformMatrix4fv(mview_mat_index, 1, 0, mview_mat); glUniform3fv(material_index, 1, red); drawgear(gear1); // Transform, color, and draw gear 2 kdMemcpy(mview_mat, gear2_mat, 16*sizeof(float)); NvGl2DemoMatrixRotate(mview_mat, -2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f); glUniformMatrix4fv(mview_mat_index, 1, 0, mview_mat); glUniform3fv(material_index, 1, green); drawgear(gear2); // Transform, color, and draw gear 3 kdMemcpy(mview_mat, gear3_mat, 16*sizeof(float)); NvGl2DemoMatrixRotate(mview_mat, -2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f); glUniformMatrix4fv(mview_mat_index, 1, 0, mview_mat); glUniform3fv(material_index, 1, blue); drawgear(gear3); } // Clean up graphics objects static void cleanup(void) { if (gearShaderProgram) { glDeleteProgram(gearShaderProgram); } freegear(gear1); freegear(gear2); freegear(gear3); } //// Callback to close window //static void //closeCB(void) //{ // shutdown = GL_TRUE; //} // //// Callback to resize window //static void //resizeCB(int width, int height) //{ // glViewport(0, 0, width, height); //} // //// Callback to handle key presses //static void //keyCB(char key, int state) //{ // // Ignoring releases // if (!state) return; // // if ((key == 'q') || (key == 'Q')) shutdown = GL_TRUE; //} // //// Entry point of this demo program. //KDint //kdMain(int argc, const char *const *argv) //{ // double endTime = TIME_LIMIT; // int runforever = 0; // KDchar messageBuffer[256]; // // // Initialize window system and EGL // if (!NvGl2DemoInitialize(&argc, (char**)argv, "gears", // EGL_OPENGL_ES2_BIT)) { // return -1; // } // // // Initialize the GL state // if (!init()) { // goto done; // } // // // Set up callbacks // NvGl2DemoSetCloseCB(closeCB); // NvGl2DemoSetResizeCB(resizeCB); // NvGl2DemoSetKeyCB(keyCB); // // // Determine how long to run for // if (argc == 2) { // endTime = kdStrtof(argv[1], KD_NULL); // if (endTime < 0.0) { // runforever = 1; // kdLogMessage(" running forever...\n"); // } // else { // KDchar tmp[30]; // kdStrcpy_s(messageBuffer, 14, " running for "); // kdFtostr(tmp,30,(KDfloat32)endTime); // kdStrncat_s(messageBuffer, 256, tmp, 30); // kdStrncat_s(messageBuffer, 256, " seconds...", 10); // kdLogMessage(messageBuffer); // if (endTime == 0.0) { // kdLogMessage( // "Usage: gears [runTime] " // "\n\n" // ); // } // } // } else if (argc > 2) { // kdLogMessage( // "Usage: gears [runTime] " // "\n\n"); // goto done; // } // endTime *= 1000000000; //Convert endtime into nanoseconds // // endTime += kdGetTimeUST(); // // // Main loop. // do { // render(); // eglSwapBuffers(gfxState.display, gfxState.surface); // NvGl2DemoCheckEvents(); // if (!runforever && !shutdown) shutdown = (endTime <= kdGetTimeUST()); // } while (!shutdown); // // done: // // // Clean up graphics // cleanup(); // // // Clean up EGL and window system // NvGl2DemoShutdown(); // // return 0; //} void NvGl2DemoMatrixTranslate(float m[16], float x, float y, float z) { float m1[16]; NvGl2DemoMatrixIdentity(m1); m1[4 * 3 + 0] = x; m1[4 * 3 + 1] = y; m1[4 * 3 + 2] = z; NvGl2DemoMatrixMultiply(m, m1); } void NvGl2DemoMatrixRotate_create3x3(float m[9], float theta, float x, float y, float z) { float len = (float)kdSqrtf(x * x + y * y + z * z); float u0 = x / len; float u1 = y / len; float u2 = z / len; float rad = (float)(theta / 180 * M_PI); float c = (float)kdCosf(rad); float s = (float)kdSinf(rad); m[3 * 0 + 0] = u0 * u0 + c * (1 - u0 * u0) + s * 0; m[3 * 0 + 1] = u0 * u1 + c * (0 - u0 * u1) + s * u2; m[3 * 0 + 2] = u0 * u2 + c * (0 - u0 * u2) - s * u1; m[3 * 1 + 0] = u1 * u0 + c * (0 - u1 * u0) - s * u2; m[3 * 1 + 1] = u1 * u1 + c * (1 - u1 * u1) + s * 0; m[3 * 1 + 2] = u1 * u2 + c * (0 - u1 * u2) + s * u0; m[3 * 2 + 0] = u2 * u0 + c * (0 - u2 * u0) + s * u1; m[3 * 2 + 1] = u2 * u1 + c * (0 - u2 * u1) - s * u0; m[3 * 2 + 2] = u2 * u2 + c * (1 - u2 * u2) + s * 0; } void NvGl2DemoMatrixRotate(float m[16], float theta, float x, float y, float z) { float r[9]; NvGl2DemoMatrixRotate_create3x3(r, theta, x, y, z); NvGl2DemoMatrixMultiply_4x4_3x3(m, r); } void NvGl2DemoMatrixMultiply(float m0[16], float m1[16]) { int r, c, i; for(r = 0; r < 4; r++) { float m[4] = {0.0, 0.0, 0.0, 0.0}; for(c = 0; c < 4; c++) { for(i = 0; i < 4; i++) { m[c] += m0[4 * i + r] * m1[4 * c + i]; } } for(c = 0; c < 4; c++) { m0[4 * c + r] = m[c]; } } } void NvGl2DemoMatrixMultiply_4x4_3x3(float m0[16], float m1[9]) { int r, c, i; for(r = 0; r < 4; r++) { float m[3] = {0.0, 0.0, 0.0}; for(c = 0; c < 3; c++) { for(i = 0; i < 3; i++) { m[c] += m0[4 * i + r] * m1[3 * c + i]; } } for(c = 0; c < 3; c++) { m0[4 * c + r] = m[c]; } } } void NvGl2DemoMatrixIdentity(float m[16]) { kdMemset(m, 0, sizeof(float) * 16); m[4 * 0 + 0] = m[4 * 1 + 1] = m[4 * 2 + 2] = m[4 * 3 + 3] = 1.0; } void NvGl2DemoMatrixFrustum(float m[16], float l, float r, float b, float t, float n, float f) { float m1[16]; float rightMinusLeftInv, topMinusBottomInv, farMinusNearInv, twoNear; rightMinusLeftInv = 1.0f / (r - l); topMinusBottomInv = 1.0f / (t - b); farMinusNearInv = 1.0f / (f - n); twoNear = 2.0f * n; m1[ 0] = twoNear * rightMinusLeftInv; m1[ 1] = 0.0f; m1[ 2] = 0.0f; m1[ 3] = 0.0f; m1[ 4] = 0.0f; m1[ 5] = twoNear * topMinusBottomInv; m1[ 6] = 0.0f; m1[ 7] = 0.0f; m1[ 8] = (r + l) * rightMinusLeftInv; m1[ 9] = (t + b) * topMinusBottomInv; m1[10] = -(f + n) * farMinusNearInv; m1[11] = -1.0f; m1[12] = 0.0f; m1[13] = 0.0f; m1[14] = -(twoNear * f) * farMinusNearInv; m1[15] = 0.0f; NvGl2DemoMatrixMultiply(m, m1); } // Takes shader source files, compiles them, and builds a shader program GLuint NvGl2DemoLoadShaderHex( const char* vertSource, const char* fragSource) { GLuint prog = 0; GLint vertSourceLen; GLint fragSourceLen; GLuint vertShader; GLuint fragShader; // Load the shader files vertSourceLen = (GLint)kdStrlen(vertSource); fragSourceLen = (GLint)kdStrlen(fragSource); // Create the program prog = glCreateProgram(); // Create the GL shader objects vertShader = glCreateShader(GL_VERTEX_SHADER); fragShader = glCreateShader(GL_FRAGMENT_SHADER); // Load shader sources into GL and compile glShaderSource(vertShader, 1, (const char**)&vertSource, &vertSourceLen); glCompileShader(vertShader); glShaderSource(fragShader, 1, (const char**)&fragSource, &fragSourceLen); glCompileShader(fragShader); // Attach the shaders to the program glAttachShader(prog, vertShader); glAttachShader(prog, fragShader); glDeleteShader(vertShader); glDeleteShader(fragShader); // Link and validate the shader program glLinkProgram(prog); glValidateProgram(prog); return prog; }