├── CMakeLists.txt ├── README.md ├── etc └── index.html └── tests ├── hello-osg └── main.cpp ├── hello-wasm └── main.c ├── include ├── esShader.c ├── esShapes.c ├── esTransform.c ├── esUtil.c └── esUtil.h └── triangle-gl └── main.c /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # project (osg-wasm) 2 | # cmake_minimum_required(VERSION 3.5.1) 3 | # option(JS_ONLY "Compiles to native JS (No WASM)" OFF) 4 | 5 | # add_definitions(-std=c++11 -O3) 6 | # include_directories(include) 7 | 8 | # file(GLOB SOURCES src/*.cpp) 9 | 10 | # set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/public") 11 | # add_executable(a ${SOURCES}) 12 | 13 | # if(JS_ONLY) 14 | # message(STATUS "Setting compilation target to native JavaScript") 15 | # set(CMAKE_EXECUTABLE_SUFFIX ".js") 16 | # set_target_properties(osgwasm PROPERTIES LINK_FLAGS "-s EXPORTED_FUNCTIONS='[_main]'") 17 | # else(JS_ONLY) 18 | # message(STATUS "Setting compilation target to WASM") 19 | # set(CMAKE_EXECUTABLE_SUFFIX ".wasm.js") 20 | # set_target_properties(osgwasm PROPERTIES LINK_FLAGS "-s WASM=1 -s BINARYEN_METHOD='native-wasm' -s EXPORTED_FUNCTIONS='[_main]'") 21 | # endif(JS_ONLY) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | A repository to help compile OpenSceneGraph using WebAssembly and Emscripten. 4 | I am slowly migrating the existing, gnarly, research code and bringing it into 5 | this repo bit by bit. Documentation will keep pace. 6 | 7 | # Considerations 8 | 9 | - This project currently only builds under Unix-like environments (or WSL on 10 | Windows). In the future, support for pure Windows 10+ compilation will also be 11 | provided, if possible. 12 | 13 | - OSG and any library dependencies will need to all be compiled statically. 14 | Support for dynamic linkage is experimental. 15 | 16 | - The path of least resistance will be to use the "embedded" osgViewer mode, 17 | along with SDL2 for creating the OpenGL context (which emcc supports well). 18 | 19 | # Setup 20 | 21 | First you'll need to locally clone the EMSDK for this project. 22 | 23 | ``` 24 | # git clone https://github.com/emscripten-core/emsdk.git 25 | # cd emsdk 26 | # ./emsdk install latest 27 | # ./emsdk activate latest 28 | # source emsdk_env.sh --build=Release 29 | ``` 30 | Second, using the same environment/shell from above, checkout OSG and run the 31 | special **emconfigure** command to invoke cmake. 32 | 33 | ``` 34 | # git clone https://github.com/AlphaPixel/OpenSceneGraph.git 35 | # cd OpenSceneGraph 36 | # emconfigure cmake . -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake 37 | # make 38 | ``` 39 | 40 | Notice how we define the toolchain file at the commandline, which is key to 41 | properly building OSG using Emscripten. 42 | 43 | # TODO 44 | 45 | - Make the emsdk and OpenSceneGraph folders use git **submodules**. 46 | 47 | - Investigate using a toplevel CMake configuration to automake the steps above. 48 | -------------------------------------------------------------------------------- /etc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 26 | 27 | -------------------------------------------------------------------------------- /tests/hello-osg/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main( int argc, char** argv) { 6 | std::cout << "OSG version: " << osgGetVersion() << std::endl; 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /tests/hello-wasm/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | printf("hello-wasm!\n"); 5 | } 6 | -------------------------------------------------------------------------------- /tests/include/esShader.c: -------------------------------------------------------------------------------- 1 | // 2 | // Book: OpenGL(R) ES 2.0 Programming Guide 3 | // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 4 | // ISBN-10: 0321502795 5 | // ISBN-13: 9780321502797 6 | // Publisher: Addison-Wesley Professional 7 | // URLs: http://safari.informit.com/9780321563835 8 | // http://www.opengles-book.com 9 | // 10 | 11 | // ESShader.c 12 | // 13 | // Utility functions for loading shaders and creating program objects. 14 | // 15 | 16 | /// 17 | // Includes 18 | // 19 | #include "esUtil.h" 20 | #include 21 | 22 | ////////////////////////////////////////////////////////////////// 23 | // 24 | // Private Functions 25 | // 26 | // 27 | 28 | 29 | 30 | ////////////////////////////////////////////////////////////////// 31 | // 32 | // Public Functions 33 | // 34 | // 35 | 36 | // 37 | /// 38 | /// \brief Load a shader, check for compile errors, print error messages to output log 39 | /// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) 40 | /// \param shaderSrc Shader source string 41 | /// \return A new shader object on success, 0 on failure 42 | // 43 | GLuint ESUTIL_API esLoadShader ( GLenum type, const char *shaderSrc ) 44 | { 45 | GLuint shader; 46 | GLint compiled; 47 | 48 | // Create the shader object 49 | shader = glCreateShader ( type ); 50 | 51 | if ( shader == 0 ) 52 | return 0; 53 | 54 | // Load the shader source 55 | glShaderSource ( shader, 1, &shaderSrc, NULL ); 56 | 57 | // Compile the shader 58 | glCompileShader ( shader ); 59 | 60 | // Check the compile status 61 | glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled ); 62 | 63 | if ( !compiled ) 64 | { 65 | GLint infoLen = 0; 66 | 67 | glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen ); 68 | 69 | if ( infoLen > 1 ) 70 | { 71 | char* infoLog = malloc (sizeof(char) * infoLen ); 72 | 73 | glGetShaderInfoLog ( shader, infoLen, NULL, infoLog ); 74 | esLogMessage ( "Error compiling shader:\n%s\n", infoLog ); 75 | 76 | free ( infoLog ); 77 | } 78 | 79 | glDeleteShader ( shader ); 80 | return 0; 81 | } 82 | 83 | return shader; 84 | 85 | } 86 | 87 | 88 | // 89 | /// 90 | /// \brief Load a vertex and fragment shader, create a program object, link program. 91 | // Errors output to log. 92 | /// \param vertShaderSrc Vertex shader source code 93 | /// \param fragShaderSrc Fragment shader source code 94 | /// \return A new program object linked with the vertex/fragment shader pair, 0 on failure 95 | // 96 | GLuint ESUTIL_API esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc ) 97 | { 98 | GLuint vertexShader; 99 | GLuint fragmentShader; 100 | GLuint programObject; 101 | GLint linked; 102 | 103 | // Load the vertex/fragment shaders 104 | vertexShader = esLoadShader ( GL_VERTEX_SHADER, vertShaderSrc ); 105 | if ( vertexShader == 0 ) 106 | return 0; 107 | 108 | fragmentShader = esLoadShader ( GL_FRAGMENT_SHADER, fragShaderSrc ); 109 | if ( fragmentShader == 0 ) 110 | { 111 | glDeleteShader( vertexShader ); 112 | return 0; 113 | } 114 | 115 | // Create the program object 116 | programObject = glCreateProgram ( ); 117 | 118 | if ( programObject == 0 ) 119 | return 0; 120 | 121 | glAttachShader ( programObject, vertexShader ); 122 | glAttachShader ( programObject, fragmentShader ); 123 | 124 | // Link the program 125 | glLinkProgram ( programObject ); 126 | 127 | // Check the link status 128 | glGetProgramiv ( programObject, GL_LINK_STATUS, &linked ); 129 | 130 | if ( !linked ) 131 | { 132 | GLint infoLen = 0; 133 | 134 | glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen ); 135 | 136 | if ( infoLen > 1 ) 137 | { 138 | char* infoLog = malloc (sizeof(char) * infoLen ); 139 | 140 | glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog ); 141 | esLogMessage ( "Error linking program:\n%s\n", infoLog ); 142 | 143 | free ( infoLog ); 144 | } 145 | 146 | glDeleteProgram ( programObject ); 147 | return 0; 148 | } 149 | 150 | // Free up no longer needed shader resources 151 | glDeleteShader ( vertexShader ); 152 | glDeleteShader ( fragmentShader ); 153 | 154 | return programObject; 155 | } -------------------------------------------------------------------------------- /tests/include/esShapes.c: -------------------------------------------------------------------------------- 1 | // 2 | // Book: OpenGL(R) ES 2.0 Programming Guide 3 | // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 4 | // ISBN-10: 0321502795 5 | // ISBN-13: 9780321502797 6 | // Publisher: Addison-Wesley Professional 7 | // URLs: http://safari.informit.com/9780321563835 8 | // http://www.opengles-book.com 9 | // 10 | 11 | // ESShapes.c 12 | // 13 | // Utility functions for generating shapes 14 | // 15 | 16 | /// 17 | // Includes 18 | // 19 | #include "esUtil.h" 20 | #include 21 | #include 22 | #include 23 | 24 | /// 25 | // Defines 26 | // 27 | #define ES_PI (3.14159265f) 28 | 29 | ////////////////////////////////////////////////////////////////// 30 | // 31 | // Private Functions 32 | // 33 | // 34 | 35 | 36 | 37 | ////////////////////////////////////////////////////////////////// 38 | // 39 | // Public Functions 40 | // 41 | // 42 | 43 | // 44 | /// \brief Generates geometry for a sphere. Allocates memory for the vertex data and stores 45 | /// the results in the arrays. Generate index list for a TRIANGLE_STRIP 46 | /// \param numSlices The number of slices in the sphere 47 | /// \param vertices If not NULL, will contain array of float3 positions 48 | /// \param normals If not NULL, will contain array of float3 normals 49 | /// \param texCoords If not NULL, will contain array of float2 texCoords 50 | /// \param indices If not NULL, will contain the array of indices for the triangle strip 51 | /// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array 52 | /// if it is not NULL ) as a GL_TRIANGLE_STRIP 53 | // 54 | int ESUTIL_API esGenSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals, 55 | GLfloat **texCoords, GLushort **indices ) 56 | { 57 | int i; 58 | int j; 59 | int numParallels = numSlices; 60 | int numVertices = ( numParallels + 1 ) * ( numSlices + 1 ); 61 | int numIndices = numParallels * numSlices * 6; 62 | float angleStep = (2.0f * ES_PI) / ((float) numSlices); 63 | 64 | // Allocate memory for buffers 65 | if ( vertices != NULL ) 66 | *vertices = malloc ( sizeof(GLfloat) * 3 * numVertices ); 67 | 68 | if ( normals != NULL ) 69 | *normals = malloc ( sizeof(GLfloat) * 3 * numVertices ); 70 | 71 | if ( texCoords != NULL ) 72 | *texCoords = malloc ( sizeof(GLfloat) * 2 * numVertices ); 73 | 74 | if ( indices != NULL ) 75 | *indices = malloc ( sizeof(GLushort) * numIndices ); 76 | 77 | for ( i = 0; i < numParallels + 1; i++ ) 78 | { 79 | for ( j = 0; j < numSlices + 1; j++ ) 80 | { 81 | int vertex = ( i * (numSlices + 1) + j ) * 3; 82 | 83 | if ( vertices ) 84 | { 85 | (*vertices)[vertex + 0] = radius * sinf ( angleStep * (float)i ) * 86 | sinf ( angleStep * (float)j ); 87 | (*vertices)[vertex + 1] = radius * cosf ( angleStep * (float)i ); 88 | (*vertices)[vertex + 2] = radius * sinf ( angleStep * (float)i ) * 89 | cosf ( angleStep * (float)j ); 90 | } 91 | 92 | if ( normals ) 93 | { 94 | (*normals)[vertex + 0] = (*vertices)[vertex + 0] / radius; 95 | (*normals)[vertex + 1] = (*vertices)[vertex + 1] / radius; 96 | (*normals)[vertex + 2] = (*vertices)[vertex + 2] / radius; 97 | } 98 | 99 | if ( texCoords ) 100 | { 101 | int texIndex = ( i * (numSlices + 1) + j ) * 2; 102 | (*texCoords)[texIndex + 0] = (float) j / (float) numSlices; 103 | (*texCoords)[texIndex + 1] = ( 1.0f - (float) i ) / (float) (numParallels - 1 ); 104 | } 105 | } 106 | } 107 | 108 | // Generate the indices 109 | if ( indices != NULL ) 110 | { 111 | GLushort *indexBuf = (*indices); 112 | for ( i = 0; i < numParallels ; i++ ) 113 | { 114 | for ( j = 0; j < numSlices; j++ ) 115 | { 116 | *indexBuf++ = i * ( numSlices + 1 ) + j; 117 | *indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + j; 118 | *indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + ( j + 1 ); 119 | 120 | *indexBuf++ = i * ( numSlices + 1 ) + j; 121 | *indexBuf++ = ( i + 1 ) * ( numSlices + 1 ) + ( j + 1 ); 122 | *indexBuf++ = i * ( numSlices + 1 ) + ( j + 1 ); 123 | } 124 | } 125 | } 126 | 127 | return numIndices; 128 | } 129 | 130 | // 131 | /// \brief Generates geometry for a cube. Allocates memory for the vertex data and stores 132 | /// the results in the arrays. Generate index list for a TRIANGLES 133 | /// \param scale The size of the cube, use 1.0 for a unit cube. 134 | /// \param vertices If not NULL, will contain array of float3 positions 135 | /// \param normals If not NULL, will contain array of float3 normals 136 | /// \param texCoords If not NULL, will contain array of float2 texCoords 137 | /// \param indices If not NULL, will contain the array of indices for the triangle strip 138 | /// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array 139 | /// if it is not NULL ) as a GL_TRIANGLE_STRIP 140 | // 141 | int ESUTIL_API esGenCube ( float scale, GLfloat **vertices, GLfloat **normals, 142 | GLfloat **texCoords, GLushort **indices ) 143 | { 144 | int i; 145 | int numVertices = 24; 146 | int numIndices = 36; 147 | 148 | GLfloat cubeVerts[] = 149 | { 150 | -0.5f, -0.5f, -0.5f, 151 | -0.5f, -0.5f, 0.5f, 152 | 0.5f, -0.5f, 0.5f, 153 | 0.5f, -0.5f, -0.5f, 154 | -0.5f, 0.5f, -0.5f, 155 | -0.5f, 0.5f, 0.5f, 156 | 0.5f, 0.5f, 0.5f, 157 | 0.5f, 0.5f, -0.5f, 158 | -0.5f, -0.5f, -0.5f, 159 | -0.5f, 0.5f, -0.5f, 160 | 0.5f, 0.5f, -0.5f, 161 | 0.5f, -0.5f, -0.5f, 162 | -0.5f, -0.5f, 0.5f, 163 | -0.5f, 0.5f, 0.5f, 164 | 0.5f, 0.5f, 0.5f, 165 | 0.5f, -0.5f, 0.5f, 166 | -0.5f, -0.5f, -0.5f, 167 | -0.5f, -0.5f, 0.5f, 168 | -0.5f, 0.5f, 0.5f, 169 | -0.5f, 0.5f, -0.5f, 170 | 0.5f, -0.5f, -0.5f, 171 | 0.5f, -0.5f, 0.5f, 172 | 0.5f, 0.5f, 0.5f, 173 | 0.5f, 0.5f, -0.5f, 174 | }; 175 | 176 | GLfloat cubeNormals[] = 177 | { 178 | 0.0f, -1.0f, 0.0f, 179 | 0.0f, -1.0f, 0.0f, 180 | 0.0f, -1.0f, 0.0f, 181 | 0.0f, -1.0f, 0.0f, 182 | 0.0f, 1.0f, 0.0f, 183 | 0.0f, 1.0f, 0.0f, 184 | 0.0f, 1.0f, 0.0f, 185 | 0.0f, 1.0f, 0.0f, 186 | 0.0f, 0.0f, -1.0f, 187 | 0.0f, 0.0f, -1.0f, 188 | 0.0f, 0.0f, -1.0f, 189 | 0.0f, 0.0f, -1.0f, 190 | 0.0f, 0.0f, 1.0f, 191 | 0.0f, 0.0f, 1.0f, 192 | 0.0f, 0.0f, 1.0f, 193 | 0.0f, 0.0f, 1.0f, 194 | -1.0f, 0.0f, 0.0f, 195 | -1.0f, 0.0f, 0.0f, 196 | -1.0f, 0.0f, 0.0f, 197 | -1.0f, 0.0f, 0.0f, 198 | 1.0f, 0.0f, 0.0f, 199 | 1.0f, 0.0f, 0.0f, 200 | 1.0f, 0.0f, 0.0f, 201 | 1.0f, 0.0f, 0.0f, 202 | }; 203 | 204 | GLfloat cubeTex[] = 205 | { 206 | 0.0f, 0.0f, 207 | 0.0f, 1.0f, 208 | 1.0f, 1.0f, 209 | 1.0f, 0.0f, 210 | 1.0f, 0.0f, 211 | 1.0f, 1.0f, 212 | 0.0f, 1.0f, 213 | 0.0f, 0.0f, 214 | 0.0f, 0.0f, 215 | 0.0f, 1.0f, 216 | 1.0f, 1.0f, 217 | 1.0f, 0.0f, 218 | 0.0f, 0.0f, 219 | 0.0f, 1.0f, 220 | 1.0f, 1.0f, 221 | 1.0f, 0.0f, 222 | 0.0f, 0.0f, 223 | 0.0f, 1.0f, 224 | 1.0f, 1.0f, 225 | 1.0f, 0.0f, 226 | 0.0f, 0.0f, 227 | 0.0f, 1.0f, 228 | 1.0f, 1.0f, 229 | 1.0f, 0.0f, 230 | }; 231 | 232 | // Allocate memory for buffers 233 | if ( vertices != NULL ) 234 | { 235 | *vertices = malloc ( sizeof(GLfloat) * 3 * numVertices ); 236 | memcpy( *vertices, cubeVerts, sizeof( cubeVerts ) ); 237 | for ( i = 0; i < numVertices * 3; i++ ) 238 | { 239 | (*vertices)[i] *= scale; 240 | } 241 | } 242 | 243 | if ( normals != NULL ) 244 | { 245 | *normals = malloc ( sizeof(GLfloat) * 3 * numVertices ); 246 | memcpy( *normals, cubeNormals, sizeof( cubeNormals ) ); 247 | } 248 | 249 | if ( texCoords != NULL ) 250 | { 251 | *texCoords = malloc ( sizeof(GLfloat) * 2 * numVertices ); 252 | memcpy( *texCoords, cubeTex, sizeof( cubeTex ) ) ; 253 | } 254 | 255 | 256 | // Generate the indices 257 | if ( indices != NULL ) 258 | { 259 | GLushort cubeIndices[] = 260 | { 261 | 0, 2, 1, 262 | 0, 3, 2, 263 | 4, 5, 6, 264 | 4, 6, 7, 265 | 8, 9, 10, 266 | 8, 10, 11, 267 | 12, 15, 14, 268 | 12, 14, 13, 269 | 16, 17, 18, 270 | 16, 18, 19, 271 | 20, 23, 22, 272 | 20, 22, 21 273 | }; 274 | 275 | *indices = malloc ( sizeof(GLushort) * numIndices ); 276 | memcpy( *indices, cubeIndices, sizeof( cubeIndices ) ); 277 | } 278 | 279 | return numIndices; 280 | } 281 | -------------------------------------------------------------------------------- /tests/include/esTransform.c: -------------------------------------------------------------------------------- 1 | // 2 | // Book: OpenGL(R) ES 2.0 Programming Guide 3 | // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 4 | // ISBN-10: 0321502795 5 | // ISBN-13: 9780321502797 6 | // Publisher: Addison-Wesley Professional 7 | // URLs: http://safari.informit.com/9780321563835 8 | // http://www.opengles-book.com 9 | // 10 | 11 | // ESUtil.c 12 | // 13 | // A utility library for OpenGL ES. This library provides a 14 | // basic common framework for the example applications in the 15 | // OpenGL ES 2.0 Programming Guide. 16 | // 17 | 18 | /// 19 | // Includes 20 | // 21 | #include "esUtil.h" 22 | #include 23 | #include 24 | 25 | #define PI 3.1415926535897932384626433832795f 26 | 27 | void ESUTIL_API 28 | esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz) 29 | { 30 | result->m[0][0] *= sx; 31 | result->m[0][1] *= sx; 32 | result->m[0][2] *= sx; 33 | result->m[0][3] *= sx; 34 | 35 | result->m[1][0] *= sy; 36 | result->m[1][1] *= sy; 37 | result->m[1][2] *= sy; 38 | result->m[1][3] *= sy; 39 | 40 | result->m[2][0] *= sz; 41 | result->m[2][1] *= sz; 42 | result->m[2][2] *= sz; 43 | result->m[2][3] *= sz; 44 | } 45 | 46 | void ESUTIL_API 47 | esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz) 48 | { 49 | result->m[3][0] += (result->m[0][0] * tx + result->m[1][0] * ty + result->m[2][0] * tz); 50 | result->m[3][1] += (result->m[0][1] * tx + result->m[1][1] * ty + result->m[2][1] * tz); 51 | result->m[3][2] += (result->m[0][2] * tx + result->m[1][2] * ty + result->m[2][2] * tz); 52 | result->m[3][3] += (result->m[0][3] * tx + result->m[1][3] * ty + result->m[2][3] * tz); 53 | } 54 | 55 | void ESUTIL_API 56 | esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z) 57 | { 58 | GLfloat sinAngle, cosAngle; 59 | GLfloat mag = sqrtf(x * x + y * y + z * z); 60 | 61 | sinAngle = sinf ( angle * PI / 180.0f ); 62 | cosAngle = cosf ( angle * PI / 180.0f ); 63 | if ( mag > 0.0f ) 64 | { 65 | GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs; 66 | GLfloat oneMinusCos; 67 | ESMatrix rotMat; 68 | 69 | x /= mag; 70 | y /= mag; 71 | z /= mag; 72 | 73 | xx = x * x; 74 | yy = y * y; 75 | zz = z * z; 76 | xy = x * y; 77 | yz = y * z; 78 | zx = z * x; 79 | xs = x * sinAngle; 80 | ys = y * sinAngle; 81 | zs = z * sinAngle; 82 | oneMinusCos = 1.0f - cosAngle; 83 | 84 | rotMat.m[0][0] = (oneMinusCos * xx) + cosAngle; 85 | rotMat.m[0][1] = (oneMinusCos * xy) - zs; 86 | rotMat.m[0][2] = (oneMinusCos * zx) + ys; 87 | rotMat.m[0][3] = 0.0F; 88 | 89 | rotMat.m[1][0] = (oneMinusCos * xy) + zs; 90 | rotMat.m[1][1] = (oneMinusCos * yy) + cosAngle; 91 | rotMat.m[1][2] = (oneMinusCos * yz) - xs; 92 | rotMat.m[1][3] = 0.0F; 93 | 94 | rotMat.m[2][0] = (oneMinusCos * zx) - ys; 95 | rotMat.m[2][1] = (oneMinusCos * yz) + xs; 96 | rotMat.m[2][2] = (oneMinusCos * zz) + cosAngle; 97 | rotMat.m[2][3] = 0.0F; 98 | 99 | rotMat.m[3][0] = 0.0F; 100 | rotMat.m[3][1] = 0.0F; 101 | rotMat.m[3][2] = 0.0F; 102 | rotMat.m[3][3] = 1.0F; 103 | 104 | esMatrixMultiply( result, &rotMat, result ); 105 | } 106 | } 107 | 108 | void ESUTIL_API 109 | esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ) 110 | { 111 | float deltaX = right - left; 112 | float deltaY = top - bottom; 113 | float deltaZ = farZ - nearZ; 114 | ESMatrix frust; 115 | 116 | if ( (nearZ <= 0.0f) || (farZ <= 0.0f) || 117 | (deltaX <= 0.0f) || (deltaY <= 0.0f) || (deltaZ <= 0.0f) ) 118 | return; 119 | 120 | frust.m[0][0] = 2.0f * nearZ / deltaX; 121 | frust.m[0][1] = frust.m[0][2] = frust.m[0][3] = 0.0f; 122 | 123 | frust.m[1][1] = 2.0f * nearZ / deltaY; 124 | frust.m[1][0] = frust.m[1][2] = frust.m[1][3] = 0.0f; 125 | 126 | frust.m[2][0] = (right + left) / deltaX; 127 | frust.m[2][1] = (top + bottom) / deltaY; 128 | frust.m[2][2] = -(nearZ + farZ) / deltaZ; 129 | frust.m[2][3] = -1.0f; 130 | 131 | frust.m[3][2] = -2.0f * nearZ * farZ / deltaZ; 132 | frust.m[3][0] = frust.m[3][1] = frust.m[3][3] = 0.0f; 133 | 134 | esMatrixMultiply(result, &frust, result); 135 | } 136 | 137 | 138 | void ESUTIL_API 139 | esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ) 140 | { 141 | GLfloat frustumW, frustumH; 142 | 143 | frustumH = tanf( fovy / 360.0f * PI ) * nearZ; 144 | frustumW = frustumH * aspect; 145 | 146 | esFrustum( result, -frustumW, frustumW, -frustumH, frustumH, nearZ, farZ ); 147 | } 148 | 149 | void ESUTIL_API 150 | esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ) 151 | { 152 | float deltaX = right - left; 153 | float deltaY = top - bottom; 154 | float deltaZ = farZ - nearZ; 155 | ESMatrix ortho; 156 | 157 | if ( (deltaX == 0.0f) || (deltaY == 0.0f) || (deltaZ == 0.0f) ) 158 | return; 159 | 160 | esMatrixLoadIdentity(&ortho); 161 | ortho.m[0][0] = 2.0f / deltaX; 162 | ortho.m[3][0] = -(right + left) / deltaX; 163 | ortho.m[1][1] = 2.0f / deltaY; 164 | ortho.m[3][1] = -(top + bottom) / deltaY; 165 | ortho.m[2][2] = -2.0f / deltaZ; 166 | ortho.m[3][2] = -(nearZ + farZ) / deltaZ; 167 | 168 | esMatrixMultiply(result, &ortho, result); 169 | } 170 | 171 | 172 | void ESUTIL_API 173 | esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB) 174 | { 175 | ESMatrix tmp; 176 | int i; 177 | 178 | for (i=0; i<4; i++) 179 | { 180 | tmp.m[i][0] = (srcA->m[i][0] * srcB->m[0][0]) + 181 | (srcA->m[i][1] * srcB->m[1][0]) + 182 | (srcA->m[i][2] * srcB->m[2][0]) + 183 | (srcA->m[i][3] * srcB->m[3][0]) ; 184 | 185 | tmp.m[i][1] = (srcA->m[i][0] * srcB->m[0][1]) + 186 | (srcA->m[i][1] * srcB->m[1][1]) + 187 | (srcA->m[i][2] * srcB->m[2][1]) + 188 | (srcA->m[i][3] * srcB->m[3][1]) ; 189 | 190 | tmp.m[i][2] = (srcA->m[i][0] * srcB->m[0][2]) + 191 | (srcA->m[i][1] * srcB->m[1][2]) + 192 | (srcA->m[i][2] * srcB->m[2][2]) + 193 | (srcA->m[i][3] * srcB->m[3][2]) ; 194 | 195 | tmp.m[i][3] = (srcA->m[i][0] * srcB->m[0][3]) + 196 | (srcA->m[i][1] * srcB->m[1][3]) + 197 | (srcA->m[i][2] * srcB->m[2][3]) + 198 | (srcA->m[i][3] * srcB->m[3][3]) ; 199 | } 200 | memcpy(result, &tmp, sizeof(ESMatrix)); 201 | } 202 | 203 | 204 | void ESUTIL_API 205 | esMatrixLoadIdentity(ESMatrix *result) 206 | { 207 | memset(result, 0x0, sizeof(ESMatrix)); 208 | result->m[0][0] = 1.0f; 209 | result->m[1][1] = 1.0f; 210 | result->m[2][2] = 1.0f; 211 | result->m[3][3] = 1.0f; 212 | } 213 | 214 | -------------------------------------------------------------------------------- /tests/include/esUtil.c: -------------------------------------------------------------------------------- 1 | // 2 | // Book: OpenGL(R) ES 2.0 Programming Guide 3 | // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 4 | // ISBN-10: 0321502795 5 | // ISBN-13: 9780321502797 6 | // Publisher: Addison-Wesley Professional 7 | // URLs: http://safari.informit.com/9780321563835 8 | // http://www.opengles-book.com 9 | // 10 | 11 | // ESUtil.c 12 | // 13 | // A utility library for OpenGL ES. This library provides a 14 | // basic common framework for the example applications in the 15 | // OpenGL ES 2.0 Programming Guide. 16 | // 17 | 18 | /// 19 | // Includes 20 | // 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "esUtil.h" 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | // X11 related local variables 35 | static Display *x_display = NULL; 36 | 37 | /// 38 | // CreateEGLContext() 39 | // 40 | // Creates an EGL rendering context and all associated elements 41 | // 42 | EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay, 43 | EGLContext* eglContext, EGLSurface* eglSurface, 44 | EGLint attribList[]) 45 | { 46 | EGLint numConfigs; 47 | EGLint majorVersion; 48 | EGLint minorVersion; 49 | EGLDisplay display; 50 | EGLContext context; 51 | EGLSurface surface; 52 | EGLConfig config; 53 | EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE }; 54 | 55 | // Get Display 56 | display = eglGetDisplay((EGLNativeDisplayType)x_display); 57 | if ( display == EGL_NO_DISPLAY ) 58 | { 59 | return EGL_FALSE; 60 | } 61 | 62 | // Initialize EGL 63 | if ( !eglInitialize(display, &majorVersion, &minorVersion) ) 64 | { 65 | return EGL_FALSE; 66 | } 67 | 68 | // Get configs 69 | if ( !eglGetConfigs(display, NULL, 0, &numConfigs) ) 70 | { 71 | return EGL_FALSE; 72 | } 73 | 74 | // Choose config 75 | if ( !eglChooseConfig(display, attribList, &config, 1, &numConfigs) ) 76 | { 77 | return EGL_FALSE; 78 | } 79 | 80 | // Create a surface 81 | surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, NULL); 82 | if ( surface == EGL_NO_SURFACE ) 83 | { 84 | return EGL_FALSE; 85 | } 86 | 87 | // Create a GL context 88 | context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs ); 89 | if ( context == EGL_NO_CONTEXT ) 90 | { 91 | return EGL_FALSE; 92 | } 93 | 94 | // Make the context current 95 | if ( !eglMakeCurrent(display, surface, surface, context) ) 96 | { 97 | return EGL_FALSE; 98 | } 99 | 100 | *eglDisplay = display; 101 | *eglSurface = surface; 102 | *eglContext = context; 103 | return EGL_TRUE; 104 | } 105 | 106 | 107 | /// 108 | // WinCreate() 109 | // 110 | // This function initialized the native X11 display and window for EGL 111 | // 112 | EGLBoolean WinCreate(ESContext *esContext, const char *title) 113 | { 114 | Window root; 115 | XSetWindowAttributes swa; 116 | XSetWindowAttributes xattr; 117 | Atom wm_state; 118 | XWMHints hints; 119 | XEvent xev; 120 | EGLConfig ecfg; 121 | EGLint num_config; 122 | Window win; 123 | 124 | /* 125 | * X11 native display initialization 126 | */ 127 | 128 | x_display = XOpenDisplay(NULL); 129 | if ( x_display == NULL ) 130 | { 131 | return EGL_FALSE; 132 | } 133 | 134 | root = DefaultRootWindow(x_display); 135 | 136 | swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask; 137 | win = XCreateWindow( 138 | x_display, root, 139 | 0, 0, esContext->width, esContext->height, 0, 140 | CopyFromParent, InputOutput, 141 | CopyFromParent, CWEventMask, 142 | &swa ); 143 | 144 | xattr.override_redirect = FALSE; 145 | XChangeWindowAttributes ( x_display, win, CWOverrideRedirect, &xattr ); 146 | 147 | hints.input = TRUE; 148 | hints.flags = InputHint; 149 | XSetWMHints(x_display, win, &hints); 150 | 151 | // make the window visible on the screen 152 | XMapWindow (x_display, win); 153 | XStoreName (x_display, win, title); 154 | 155 | // get identifiers for the provided atom name strings 156 | wm_state = XInternAtom (x_display, "_NET_WM_STATE", FALSE); 157 | 158 | memset ( &xev, 0, sizeof(xev) ); 159 | xev.type = ClientMessage; 160 | xev.xclient.window = win; 161 | xev.xclient.message_type = wm_state; 162 | xev.xclient.format = 32; 163 | xev.xclient.data.l[0] = 1; 164 | xev.xclient.data.l[1] = FALSE; 165 | XSendEvent ( 166 | x_display, 167 | DefaultRootWindow ( x_display ), 168 | FALSE, 169 | SubstructureNotifyMask, 170 | &xev ); 171 | 172 | esContext->hWnd = (EGLNativeWindowType) win; 173 | return EGL_TRUE; 174 | } 175 | 176 | 177 | /// 178 | // userInterrupt() 179 | // 180 | // Reads from X11 event loop and interrupt program if there is a keypress, or 181 | // window close action. 182 | // 183 | GLboolean userInterrupt(ESContext *esContext) 184 | { 185 | XEvent xev; 186 | KeySym key; 187 | GLboolean userinterrupt = GL_FALSE; 188 | char text; 189 | 190 | // Pump all messages from X server. Keypresses are directed to keyfunc (if defined) 191 | while ( XPending ( x_display ) ) 192 | { 193 | XNextEvent( x_display, &xev ); 194 | if ( xev.type == KeyPress ) 195 | { 196 | if (XLookupString(&xev.xkey,&text,1,&key,0)==1) 197 | { 198 | if (esContext->keyFunc != NULL) 199 | esContext->keyFunc(esContext, text, 0, 0); 200 | } 201 | } 202 | if ( xev.type == DestroyNotify ) 203 | userinterrupt = GL_TRUE; 204 | } 205 | return userinterrupt; 206 | } 207 | 208 | 209 | ////////////////////////////////////////////////////////////////// 210 | // 211 | // Public Functions 212 | // 213 | // 214 | 215 | /// 216 | // esInitContext() 217 | // 218 | // Initialize ES utility context. This must be called before calling any other 219 | // functions. 220 | // 221 | void ESUTIL_API esInitContext ( ESContext *esContext ) 222 | { 223 | if ( esContext != NULL ) 224 | { 225 | memset( esContext, 0, sizeof( ESContext) ); 226 | } 227 | } 228 | 229 | 230 | /// 231 | // esCreateWindow() 232 | // 233 | // title - name for title bar of window 234 | // width - width of window to create 235 | // height - height of window to create 236 | // flags - bitwise or of window creation flags 237 | // ES_WINDOW_ALPHA - specifies that the framebuffer should have alpha 238 | // ES_WINDOW_DEPTH - specifies that a depth buffer should be created 239 | // ES_WINDOW_STENCIL - specifies that a stencil buffer should be created 240 | // ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created 241 | // 242 | GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char* title, GLint width, GLint height, GLuint flags ) 243 | { 244 | EGLint attribList[] = 245 | { 246 | EGL_RED_SIZE, 5, 247 | EGL_GREEN_SIZE, 6, 248 | EGL_BLUE_SIZE, 5, 249 | EGL_ALPHA_SIZE, (flags & ES_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE, 250 | EGL_DEPTH_SIZE, (flags & ES_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE, 251 | EGL_STENCIL_SIZE, (flags & ES_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE, 252 | EGL_SAMPLE_BUFFERS, (flags & ES_WINDOW_MULTISAMPLE) ? 1 : 0, 253 | EGL_NONE 254 | }; 255 | 256 | if ( esContext == NULL ) 257 | { 258 | return GL_FALSE; 259 | } 260 | 261 | esContext->width = width; 262 | esContext->height = height; 263 | 264 | if ( !WinCreate ( esContext, title) ) 265 | { 266 | return GL_FALSE; 267 | } 268 | 269 | 270 | if ( !CreateEGLContext ( esContext->hWnd, 271 | &esContext->eglDisplay, 272 | &esContext->eglContext, 273 | &esContext->eglSurface, 274 | attribList) ) 275 | { 276 | return GL_FALSE; 277 | } 278 | 279 | 280 | return GL_TRUE; 281 | } 282 | 283 | 284 | /// 285 | // esMainLoop() 286 | // 287 | // Start the main loop for the OpenGL ES application 288 | // 289 | 290 | void ESUTIL_API esMainLoop ( ESContext *esContext ) 291 | { 292 | struct timeval t1, t2; 293 | struct timezone tz; 294 | float deltatime; 295 | float totaltime = 0.0f; 296 | unsigned int frames = 0; 297 | 298 | gettimeofday ( &t1 , &tz ); 299 | 300 | // Just one iteration! while(userInterrupt(esContext) == GL_FALSE) 301 | { 302 | gettimeofday(&t2, &tz); 303 | deltatime = (float)(t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6); 304 | t1 = t2; 305 | 306 | if (esContext->updateFunc != NULL) 307 | esContext->updateFunc(esContext, deltatime); 308 | if (esContext->drawFunc != NULL) 309 | esContext->drawFunc(esContext); 310 | 311 | eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface); 312 | 313 | totaltime += deltatime; 314 | frames++; 315 | if (totaltime > 2.0f) 316 | { 317 | printf("%4d frames rendered in %1.4f seconds -> FPS=%3.4f\n", frames, totaltime, frames/totaltime); 318 | totaltime -= 2.0f; 319 | frames = 0; 320 | } 321 | } 322 | } 323 | 324 | 325 | /// 326 | // esRegisterDrawFunc() 327 | // 328 | void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) (ESContext* ) ) 329 | { 330 | esContext->drawFunc = drawFunc; 331 | } 332 | 333 | 334 | /// 335 | // esRegisterUpdateFunc() 336 | // 337 | void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) ) 338 | { 339 | esContext->updateFunc = updateFunc; 340 | } 341 | 342 | 343 | /// 344 | // esRegisterKeyFunc() 345 | // 346 | void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext, 347 | void (ESCALLBACK *keyFunc) (ESContext*, unsigned char, int, int ) ) 348 | { 349 | esContext->keyFunc = keyFunc; 350 | } 351 | 352 | 353 | /// 354 | // esLogMessage() 355 | // 356 | // Log an error message to the debug output for the platform 357 | // 358 | void ESUTIL_API esLogMessage ( const char *formatStr, ... ) 359 | { 360 | va_list params; 361 | char buf[BUFSIZ]; 362 | 363 | va_start ( params, formatStr ); 364 | vsprintf ( buf, formatStr, params ); 365 | 366 | printf ( "%s", buf ); 367 | 368 | va_end ( params ); 369 | } 370 | 371 | 372 | /// 373 | // esLoadTGA() 374 | // 375 | // Loads a 24-bit TGA image from a file. This is probably the simplest TGA loader ever. 376 | // Does not support loading of compressed TGAs nor TGAa with alpha channel. But for the 377 | // sake of the examples, this is sufficient. 378 | // 379 | 380 | char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height ) 381 | { 382 | char *buffer = NULL; 383 | FILE *f; 384 | unsigned char tgaheader[12]; 385 | unsigned char attributes[6]; 386 | unsigned int imagesize; 387 | 388 | f = fopen(fileName, "rb"); 389 | if(f == NULL) return NULL; 390 | 391 | if(fread(&tgaheader, sizeof(tgaheader), 1, f) == 0) 392 | { 393 | fclose(f); 394 | return NULL; 395 | } 396 | 397 | if(fread(attributes, sizeof(attributes), 1, f) == 0) 398 | { 399 | fclose(f); 400 | return 0; 401 | } 402 | 403 | *width = attributes[1] * 256 + attributes[0]; 404 | *height = attributes[3] * 256 + attributes[2]; 405 | imagesize = attributes[4] / 8 * *width * *height; 406 | buffer = malloc(imagesize); 407 | if (buffer == NULL) 408 | { 409 | fclose(f); 410 | return 0; 411 | } 412 | 413 | if(fread(buffer, 1, imagesize, f) != imagesize) 414 | { 415 | free(buffer); 416 | return NULL; 417 | } 418 | fclose(f); 419 | return buffer; 420 | } 421 | -------------------------------------------------------------------------------- /tests/include/esUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // Book: OpenGL(R) ES 2.0 Programming Guide 3 | // Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner 4 | // ISBN-10: 0321502795 5 | // ISBN-13: 9780321502797 6 | // Publisher: Addison-Wesley Professional 7 | // URLs: http://safari.informit.com/9780321563835 8 | // http://www.opengles-book.com 9 | // 10 | 11 | // 12 | /// \file ESUtil.h 13 | /// \brief A utility library for OpenGL ES. This library provides a 14 | /// basic common framework for the example applications in the 15 | /// OpenGL ES 2.0 Programming Guide. 16 | // 17 | #ifndef ESUTIL_H 18 | #define ESUTIL_H 19 | 20 | /// 21 | // Includes 22 | // 23 | #include 24 | #include 25 | 26 | #ifdef __cplusplus 27 | 28 | extern "C" { 29 | #endif 30 | 31 | 32 | /// 33 | // Macros 34 | // 35 | #define ESUTIL_API 36 | #define ESCALLBACK 37 | 38 | 39 | /// esCreateWindow flag - RGB color buffer 40 | #define ES_WINDOW_RGB 0 41 | /// esCreateWindow flag - ALPHA color buffer 42 | #define ES_WINDOW_ALPHA 1 43 | /// esCreateWindow flag - depth buffer 44 | #define ES_WINDOW_DEPTH 2 45 | /// esCreateWindow flag - stencil buffer 46 | #define ES_WINDOW_STENCIL 4 47 | /// esCreateWindow flat - multi-sample buffer 48 | #define ES_WINDOW_MULTISAMPLE 8 49 | 50 | 51 | /// 52 | // Types 53 | // 54 | 55 | #ifndef FALSE 56 | #define FALSE 0 57 | #endif 58 | #ifndef TRUE 59 | #define TRUE 1 60 | #endif 61 | 62 | typedef struct 63 | { 64 | GLfloat m[4][4]; 65 | } ESMatrix; 66 | 67 | typedef struct _escontext 68 | { 69 | /// Put your user data here... 70 | void* userData; 71 | 72 | /// Window width 73 | GLint width; 74 | 75 | /// Window height 76 | GLint height; 77 | 78 | /// Window handle 79 | EGLNativeWindowType hWnd; 80 | 81 | /// EGL display 82 | EGLDisplay eglDisplay; 83 | 84 | /// EGL context 85 | EGLContext eglContext; 86 | 87 | /// EGL surface 88 | EGLSurface eglSurface; 89 | 90 | /// Callbacks 91 | void (ESCALLBACK *drawFunc) ( struct _escontext * ); 92 | void (ESCALLBACK *keyFunc) ( struct _escontext *, unsigned char, int, int ); 93 | void (ESCALLBACK *updateFunc) ( struct _escontext *, float deltaTime ); 94 | } ESContext; 95 | 96 | 97 | /// 98 | // Public Functions 99 | // 100 | 101 | // 102 | /// 103 | /// \brief Initialize ES framework context. This must be called before calling any other functions. 104 | /// \param esContext Application context 105 | // 106 | void ESUTIL_API esInitContext ( ESContext *esContext ); 107 | 108 | // 109 | /// \brief Create a window with the specified parameters 110 | /// \param esContext Application context 111 | /// \param title Name for title bar of window 112 | /// \param width Width in pixels of window to create 113 | /// \param height Height in pixels of window to create 114 | /// \param flags Bitfield for the window creation flags 115 | /// ES_WINDOW_RGB - specifies that the color buffer should have R,G,B channels 116 | /// ES_WINDOW_ALPHA - specifies that the color buffer should have alpha 117 | /// ES_WINDOW_DEPTH - specifies that a depth buffer should be created 118 | /// ES_WINDOW_STENCIL - specifies that a stencil buffer should be created 119 | /// ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created 120 | /// \return GL_TRUE if window creation is succesful, GL_FALSE otherwise 121 | GLboolean ESUTIL_API esCreateWindow ( ESContext *esContext, const char *title, GLint width, GLint height, GLuint flags ); 122 | 123 | // 124 | /// \brief Start the main loop for the OpenGL ES application 125 | /// \param esContext Application context 126 | // 127 | void ESUTIL_API esMainLoop ( ESContext *esContext ); 128 | 129 | // 130 | /// \brief Register a draw callback function to be used to render each frame 131 | /// \param esContext Application context 132 | /// \param drawFunc Draw callback function that will be used to render the scene 133 | // 134 | void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) ( ESContext* ) ); 135 | 136 | // 137 | /// \brief Register an update callback function to be used to update on each time step 138 | /// \param esContext Application context 139 | /// \param updateFunc Update callback function that will be used to render the scene 140 | // 141 | void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) ); 142 | 143 | // 144 | /// \brief Register an keyboard input processing callback function 145 | /// \param esContext Application context 146 | /// \param keyFunc Key callback function for application processing of keyboard input 147 | // 148 | void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext, 149 | void (ESCALLBACK *drawFunc) ( ESContext*, unsigned char, int, int ) ); 150 | // 151 | /// \brief Log a message to the debug output for the platform 152 | /// \param formatStr Format string for error log. 153 | // 154 | void ESUTIL_API esLogMessage ( const char *formatStr, ... ); 155 | 156 | // 157 | /// 158 | /// \brief Load a shader, check for compile errors, print error messages to output log 159 | /// \param type Type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) 160 | /// \param shaderSrc Shader source string 161 | /// \return A new shader object on success, 0 on failure 162 | // 163 | GLuint ESUTIL_API esLoadShader ( GLenum type, const char *shaderSrc ); 164 | 165 | // 166 | /// 167 | /// \brief Load a vertex and fragment shader, create a program object, link program. 168 | /// Errors output to log. 169 | /// \param vertShaderSrc Vertex shader source code 170 | /// \param fragShaderSrc Fragment shader source code 171 | /// \return A new program object linked with the vertex/fragment shader pair, 0 on failure 172 | // 173 | GLuint ESUTIL_API esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc ); 174 | 175 | 176 | // 177 | /// \brief Generates geometry for a sphere. Allocates memory for the vertex data and stores 178 | /// the results in the arrays. Generate index list for a TRIANGLE_STRIP 179 | /// \param numSlices The number of slices in the sphere 180 | /// \param vertices If not NULL, will contain array of float3 positions 181 | /// \param normals If not NULL, will contain array of float3 normals 182 | /// \param texCoords If not NULL, will contain array of float2 texCoords 183 | /// \param indices If not NULL, will contain the array of indices for the triangle strip 184 | /// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array 185 | /// if it is not NULL ) as a GL_TRIANGLE_STRIP 186 | // 187 | int ESUTIL_API esGenSphere ( int numSlices, float radius, GLfloat **vertices, GLfloat **normals, 188 | GLfloat **texCoords, GLushort **indices ); 189 | 190 | // 191 | /// \brief Generates geometry for a cube. Allocates memory for the vertex data and stores 192 | /// the results in the arrays. Generate index list for a TRIANGLES 193 | /// \param scale The size of the cube, use 1.0 for a unit cube. 194 | /// \param vertices If not NULL, will contain array of float3 positions 195 | /// \param normals If not NULL, will contain array of float3 normals 196 | /// \param texCoords If not NULL, will contain array of float2 texCoords 197 | /// \param indices If not NULL, will contain the array of indices for the triangle strip 198 | /// \return The number of indices required for rendering the buffers (the number of indices stored in the indices array 199 | /// if it is not NULL ) as a GL_TRIANGLES 200 | // 201 | int ESUTIL_API esGenCube ( float scale, GLfloat **vertices, GLfloat **normals, 202 | GLfloat **texCoords, GLushort **indices ); 203 | 204 | // 205 | /// \brief Loads a 24-bit TGA image from a file 206 | /// \param fileName Name of the file on disk 207 | /// \param width Width of loaded image in pixels 208 | /// \param height Height of loaded image in pixels 209 | /// \return Pointer to loaded image. NULL on failure. 210 | // 211 | char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height ); 212 | 213 | 214 | // 215 | /// \brief multiply matrix specified by result with a scaling matrix and return new matrix in result 216 | /// \param result Specifies the input matrix. Scaled matrix is returned in result. 217 | /// \param sx, sy, sz Scale factors along the x, y and z axes respectively 218 | // 219 | void ESUTIL_API esScale(ESMatrix *result, GLfloat sx, GLfloat sy, GLfloat sz); 220 | 221 | // 222 | /// \brief multiply matrix specified by result with a translation matrix and return new matrix in result 223 | /// \param result Specifies the input matrix. Translated matrix is returned in result. 224 | /// \param tx, ty, tz Scale factors along the x, y and z axes respectively 225 | // 226 | void ESUTIL_API esTranslate(ESMatrix *result, GLfloat tx, GLfloat ty, GLfloat tz); 227 | 228 | // 229 | /// \brief multiply matrix specified by result with a rotation matrix and return new matrix in result 230 | /// \param result Specifies the input matrix. Rotated matrix is returned in result. 231 | /// \param angle Specifies the angle of rotation, in degrees. 232 | /// \param x, y, z Specify the x, y and z coordinates of a vector, respectively 233 | // 234 | void ESUTIL_API esRotate(ESMatrix *result, GLfloat angle, GLfloat x, GLfloat y, GLfloat z); 235 | 236 | // 237 | // \brief multiply matrix specified by result with a perspective matrix and return new matrix in result 238 | /// \param result Specifies the input matrix. new matrix is returned in result. 239 | /// \param left, right Coordinates for the left and right vertical clipping planes 240 | /// \param bottom, top Coordinates for the bottom and top horizontal clipping planes 241 | /// \param nearZ, farZ Distances to the near and far depth clipping planes. Both distances must be positive. 242 | // 243 | void ESUTIL_API esFrustum(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ); 244 | 245 | // 246 | /// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result 247 | /// \param result Specifies the input matrix. new matrix is returned in result. 248 | /// \param fovy Field of view y angle in degrees 249 | /// \param aspect Aspect ratio of screen 250 | /// \param nearZ Near plane distance 251 | /// \param farZ Far plane distance 252 | // 253 | void ESUTIL_API esPerspective(ESMatrix *result, float fovy, float aspect, float nearZ, float farZ); 254 | 255 | // 256 | /// \brief multiply matrix specified by result with a perspective matrix and return new matrix in result 257 | /// \param result Specifies the input matrix. new matrix is returned in result. 258 | /// \param left, right Coordinates for the left and right vertical clipping planes 259 | /// \param bottom, top Coordinates for the bottom and top horizontal clipping planes 260 | /// \param nearZ, farZ Distances to the near and far depth clipping planes. These values are negative if plane is behind the viewer 261 | // 262 | void ESUTIL_API esOrtho(ESMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ); 263 | 264 | // 265 | /// \brief perform the following operation - result matrix = srcA matrix * srcB matrix 266 | /// \param result Returns multiplied matrix 267 | /// \param srcA, srcB Input matrices to be multiplied 268 | // 269 | void ESUTIL_API esMatrixMultiply(ESMatrix *result, ESMatrix *srcA, ESMatrix *srcB); 270 | 271 | // 272 | //// \brief return an indentity matrix 273 | //// \param result returns identity matrix 274 | // 275 | void ESUTIL_API esMatrixLoadIdentity(ESMatrix *result); 276 | 277 | #ifdef __cplusplus 278 | } 279 | #endif 280 | 281 | #endif // ESUTIL_H 282 | -------------------------------------------------------------------------------- /tests/triangle-gl/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "esUtil.h" 4 | 5 | typedef struct { 6 | GLuint programObject; 7 | } UserData; 8 | 9 | GLuint LoadShader(GLenum type, const char *shaderSrc) { 10 | GLuint shader; 11 | GLint compiled; 12 | 13 | // Create the shader object 14 | shader = glCreateShader(type); 15 | 16 | if(shader == 0) 17 | return 0; 18 | 19 | // Load the shader source 20 | glShaderSource(shader, 1, &shaderSrc, NULL); 21 | 22 | // Compile the shader 23 | glCompileShader(shader); 24 | 25 | // Check the compile status 26 | glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); 27 | 28 | if(!compiled) 29 | { 30 | GLint infoLen = 0; 31 | 32 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); 33 | 34 | if(infoLen > 1) 35 | { 36 | char* infoLog = malloc (sizeof(char) * infoLen); 37 | 38 | glGetShaderInfoLog(shader, infoLen, NULL, infoLog); 39 | esLogMessage("Error compiling shader:\n%s\n", infoLog); 40 | 41 | free(infoLog); 42 | } 43 | 44 | glDeleteShader(shader); 45 | return 0; 46 | } 47 | 48 | return shader; 49 | } 50 | 51 | int Init(ESContext *esContext) 52 | { 53 | esContext->userData = malloc(sizeof(UserData)); 54 | 55 | UserData *userData = esContext->userData; 56 | GLbyte vShaderStr[] = 57 | "attribute vec4 vPosition; \n" 58 | "void main() \n" 59 | "{ \n" 60 | " gl_Position = vPosition; \n" 61 | "} \n"; 62 | 63 | GLbyte fShaderStr[] = 64 | "precision mediump float;\n"\ 65 | "void main() \n" 66 | "{ \n" 67 | " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" 68 | "} \n"; 69 | 70 | GLuint vertexShader; 71 | GLuint fragmentShader; 72 | GLuint programObject; 73 | GLint linked; 74 | 75 | // Load the vertex/fragment shaders 76 | vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr); 77 | fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr); 78 | 79 | // Create the program object 80 | programObject = glCreateProgram(); 81 | 82 | if(programObject == 0) 83 | return 0; 84 | 85 | glAttachShader(programObject, vertexShader); 86 | glAttachShader(programObject, fragmentShader); 87 | 88 | // Bind vPosition to attribute 0 89 | glBindAttribLocation(programObject, 0, "vPosition"); 90 | 91 | // Link the program 92 | glLinkProgram(programObject); 93 | 94 | // Check the link status 95 | glGetProgramiv(programObject, GL_LINK_STATUS, &linked); 96 | 97 | if(!linked) 98 | { 99 | GLint infoLen = 0; 100 | 101 | glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen); 102 | 103 | if(infoLen > 1) 104 | { 105 | char* infoLog = malloc (sizeof(char) * infoLen); 106 | 107 | glGetProgramInfoLog(programObject, infoLen, NULL, infoLog); 108 | esLogMessage("Error linking program:\n%s\n", infoLog); 109 | 110 | free(infoLog); 111 | } 112 | 113 | glDeleteProgram(programObject); 114 | return GL_FALSE; 115 | } 116 | 117 | // Store the program object 118 | userData->programObject = programObject; 119 | 120 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 121 | return GL_TRUE; 122 | } 123 | 124 | // Draw a triangle using the shader pair created in Init() 125 | void Draw(ESContext *esContext) 126 | { 127 | UserData *userData = esContext->userData; 128 | GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f, 129 | -0.5f, -0.5f, 0.0f, 130 | 0.5f, -0.5f, 0.0f }; 131 | 132 | // No clientside arrays, so do this in a webgl-friendly manner 133 | GLuint vertexPosObject; 134 | glGenBuffers(1, &vertexPosObject); 135 | glBindBuffer(GL_ARRAY_BUFFER, vertexPosObject); 136 | glBufferData(GL_ARRAY_BUFFER, 9*4, vVertices, GL_STATIC_DRAW); 137 | 138 | // Set the viewport 139 | glViewport(0, 0, esContext->width, esContext->height); 140 | 141 | // Clear the color buffer 142 | glClear(GL_COLOR_BUFFER_BIT); 143 | 144 | // Use the program object 145 | glUseProgram(userData->programObject); 146 | 147 | // Load the vertex data 148 | glBindBuffer(GL_ARRAY_BUFFER, vertexPosObject); 149 | glVertexAttribPointer(0 /* ? */, 3, GL_FLOAT, 0, 0, 0); 150 | glEnableVertexAttribArray(0); 151 | 152 | glDrawArrays(GL_TRIANGLES, 0, 3); 153 | } 154 | 155 | int main(int argc, char *argv[]) 156 | { 157 | ESContext esContext; 158 | UserData userData; 159 | 160 | esInitContext(&esContext); 161 | esContext.userData = &userData; 162 | 163 | esCreateWindow(&esContext, "Hello Triangle", 320, 240, ES_WINDOW_RGB); 164 | 165 | if(!Init(&esContext)) 166 | return 0; 167 | 168 | esRegisterDrawFunc(&esContext, Draw); 169 | 170 | esMainLoop(&esContext); 171 | } 172 | --------------------------------------------------------------------------------