├── 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 |
--------------------------------------------------------------------------------