1 /*
2 * GStreamer
3 * Copyright (C) 2008 Cyril Comparon <cyril.comparon@gmail.com>
4 * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 /**
23 * SECTION:element-glbumper
24 * @title: glbumper
25 *
26 * Bump mapping using the normal method.
27 *
28 * ## Examples
29 * |[
30 * gst-launch-1.0 -v videotestsrc ! glupload ! glbumper location=normalmap.bmp ! glimagesink
31 * ]| A pipeline to test normal mapping.
32 * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
33 *
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include <stdlib.h>
41 #include <png.h>
42
43 #include "gstglelements.h"
44 #include "gstglbumper.h"
45
46 #if PNG_LIBPNG_VER >= 10400
47 #define int_p_NULL NULL
48 #define png_infopp_NULL NULL
49 #endif
50
51 #define GST_CAT_DEFAULT gst_gl_bumper_debug
52 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
53
54 enum
55 {
56 PROP_0,
57 PROP_LOCATION
58 };
59
60 #define DEBUG_INIT \
61 GST_DEBUG_CATEGORY_INIT (gst_gl_bumper_debug, "glbumper", 0, "glbumper element");
62
63 G_DEFINE_TYPE_WITH_CODE (GstGLBumper, gst_gl_bumper, GST_TYPE_GL_FILTER,
64 DEBUG_INIT);
65 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (glbumper, "glbumper",
66 GST_RANK_NONE, GST_TYPE_GL_BUMPER, gl_element_init (plugin));
67
68 static void gst_gl_bumper_set_property (GObject * object, guint prop_id,
69 const GValue * value, GParamSpec * pspec);
70 static void gst_gl_bumper_get_property (GObject * object, guint prop_id,
71 GValue * value, GParamSpec * pspec);
72
73 static void gst_gl_bumper_reset (GstGLFilter * filter);
74 static gboolean gst_gl_bumper_init_shader (GstGLFilter * filter);
75 static gboolean gst_gl_bumper_filter_texture (GstGLFilter * filter,
76 guint in_tex, guint out_tex);
77 static void gst_gl_bumper_callback (gint width, gint height, guint texture,
78 gpointer stuff);
79
80 //vertex source
81 static const gchar *bumper_v_src =
82 "attribute vec3 aTangent;\n"
83 "\n"
84 "varying vec3 vNormal;\n"
85 "varying vec3 vTangent;\n"
86 "varying vec3 vVertexToLight0;\n"
87 "varying vec3 vVertexToLight1;\n"
88 "\n"
89 "void main()\n"
90 "{\n"
91 " // transform the vertex\n"
92 " gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;\n"
93 "\n"
94 " // transform the normal and the tangent to scene coords\n"
95 " vNormal = normalize(gl_NormalMatrix * gl_Normal);\n"
96 " vTangent = normalize(gl_NormalMatrix * aTangent);\n"
97 "\n"
98 " // transforming the vertex position to modelview-space\n"
99 " //const vec4 vertexInSceneCoords = gl_ModelViewMatrix * gl_Vertex;\n"
100 "\n"
101 " // calculate the vector from the vertex position to the light position\n"
102 " vVertexToLight0 = normalize(gl_LightSource[0].position).xyz;\n"
103 " vVertexToLight1 = normalize(gl_LightSource[1].position).xyz;\n"
104 "\n"
105 " // transit vertex color\n"
106 " gl_FrontColor = gl_BackColor = gl_Color;\n"
107 "\n"
108 " // use the two first sets of texture coordinates in the fragment shader\n"
109 " gl_TexCoord[0] = gl_MultiTexCoord0;\n"
110 " gl_TexCoord[1] = gl_MultiTexCoord1;\n" "}\n";
111
112 //fragment source
113 static const gchar *bumper_f_src =
114 "uniform sampler2D texture0;\n"
115 "uniform sampler2D texture1;\n"
116 "\n"
117 "varying vec3 vNormal;\n"
118 "varying vec3 vTangent;\n"
119 "varying vec3 vVertexToLight0;\n"
120 "varying vec3 vVertexToLight1;\n"
121 "\n"
122 "void main()\n"
123 "{\n"
124 " // get the color of the textures\n"
125 " vec4 textureColor = texture2D(texture0, gl_TexCoord[0].st);\n"
126 " vec3 normalmapItem = texture2D(texture1, gl_TexCoord[1].st).xyz * 2.0 - 1.0;\n"
127 "\n"
128 " // calculate matrix that transform from tangent space to normalmap space (contrary of intuition)\n"
129 " vec3 binormal = cross(vNormal, vTangent);\n"
130 " mat3 tangentSpace2normalmapSpaceMat = mat3(vTangent, binormal, vNormal);\n"
131 "\n"
132 " // disturb the normal\n"
133 " vec3 disturbedNormal = tangentSpace2normalmapSpaceMat * normalmapItem;\n"
134 "\n"
135 " // calculate the diffuse term and clamping it to [0;1]\n"
136 " float diffuseTerm0 = clamp(dot(disturbedNormal, vVertexToLight0), 0.0, 1.0);\n"
137 " float diffuseTerm1 = clamp(dot(disturbedNormal, vVertexToLight1), 0.0, 1.0);\n"
138 "\n"
139 " vec3 irradiance = (diffuseTerm0 * gl_LightSource[0].diffuse.rgb + diffuseTerm1 * gl_LightSource[1].diffuse.rgb);\n"
140 "\n"
141 " // calculate the final color\n"
142 " gl_FragColor = vec4(irradiance * textureColor.rgb, textureColor.w);\n"
143 "}\n";
144
145 #define LOAD_ERROR(context, msg) { gst_gl_context_set_error (context, "unable to load %s: %s", bumper->location, msg); return; }
146
147 //png reading error handler
148 static void
user_warning_fn(png_structp png_ptr,png_const_charp warning_msg)149 user_warning_fn (png_structp png_ptr, png_const_charp warning_msg)
150 {
151 g_warning ("%s\n", warning_msg);
152 }
153
154 //Called in the gl thread
155 static void
gst_gl_bumper_init_resources(GstGLFilter * filter)156 gst_gl_bumper_init_resources (GstGLFilter * filter)
157 {
158 GstGLBumper *bumper = GST_GL_BUMPER (filter);
159 GstGLContext *context = filter->context;
160 const GstGLFuncs *gl = context->gl_vtable;
161
162 png_structp png_ptr;
163 png_infop info_ptr;
164 png_uint_32 width = 0;
165 png_uint_32 height = 0;
166 gint bit_depth = 0;
167 gint color_type = 0;
168 gint interlace_type = 0;
169 png_FILE_p fp = NULL;
170 guint y = 0;
171 guchar *raw_data = NULL;
172 guchar **rows = NULL;
173 png_byte magic[8];
174 gint n_read;
175
176 if (!bumper->location) {
177 gst_gl_context_set_error (context, "A filename is required");
178 return;
179 }
180
181 /* BEGIN load png image file */
182
183 if ((fp = fopen (bumper->location, "rb")) == NULL)
184 LOAD_ERROR (context, "file not found");
185
186 /* Read magic number */
187 n_read = fread (magic, 1, sizeof (magic), fp);
188 if (n_read != sizeof (magic)) {
189 fclose (fp);
190 LOAD_ERROR (context, "can't read PNG magic number");
191 }
192
193 /* Check for valid magic number */
194 if (png_sig_cmp (magic, 0, sizeof (magic))) {
195 fclose (fp);
196 LOAD_ERROR (context, "not a valid PNG image");
197 }
198
199 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
200
201 if (png_ptr == NULL) {
202 fclose (fp);
203 LOAD_ERROR (context, "failed to initialize the png_struct");
204 }
205
206 png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn);
207
208 info_ptr = png_create_info_struct (png_ptr);
209 if (info_ptr == NULL) {
210 fclose (fp);
211 png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
212 LOAD_ERROR (context,
213 "failed to initialize the memory for image information");
214 }
215
216 png_init_io (png_ptr, fp);
217
218 png_set_sig_bytes (png_ptr, sizeof (magic));
219
220 png_read_info (png_ptr, info_ptr);
221
222 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
223 &interlace_type, int_p_NULL, int_p_NULL);
224
225 if (color_type != PNG_COLOR_TYPE_RGB) {
226 fclose (fp);
227 png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL);
228 LOAD_ERROR (context, "color type is not rgb");
229 }
230
231 raw_data = (guchar *) malloc (sizeof (guchar) * width * height * 3);
232
233 rows = (guchar **) malloc (sizeof (guchar *) * height);
234
235 for (y = 0; y < height; ++y)
236 rows[y] = (guchar *) (raw_data + y * width * 3);
237
238 png_read_image (png_ptr, rows);
239
240 free (rows);
241
242 png_read_end (png_ptr, info_ptr);
243 png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL);
244 fclose (fp);
245
246 /* END load png image file */
247
248 bumper->bumpmap_width = width;
249 bumper->bumpmap_height = height;
250
251 gl->GenTextures (1, &bumper->bumpmap);
252 gl->BindTexture (GL_TEXTURE_2D, bumper->bumpmap);
253 gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
254 bumper->bumpmap_width, bumper->bumpmap_height, 0,
255 GL_RGB, GL_UNSIGNED_BYTE, raw_data);
256 gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
257 gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
258 gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
259 gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
260
261 free (raw_data);
262 }
263
264 //Called in the gl thread
265 static void
gst_gl_bumper_reset_resources(GstGLFilter * filter)266 gst_gl_bumper_reset_resources (GstGLFilter * filter)
267 {
268 GstGLBumper *bumper = GST_GL_BUMPER (filter);
269
270 if (bumper->bumpmap) {
271 glDeleteTextures (1, &bumper->bumpmap);
272 bumper->bumpmap = 0;
273 }
274 }
275
276 static void
gst_gl_bumper_class_init(GstGLBumperClass * klass)277 gst_gl_bumper_class_init (GstGLBumperClass * klass)
278 {
279 GObjectClass *gobject_class;
280 GstElementClass *element_class;
281
282 gobject_class = (GObjectClass *) klass;
283 element_class = GST_ELEMENT_CLASS (klass);
284 gobject_class->set_property = gst_gl_bumper_set_property;
285 gobject_class->get_property = gst_gl_bumper_get_property;
286
287 gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
288
289 GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_bumper_filter_texture;
290 GST_GL_FILTER_CLASS (klass)->display_init_cb = gst_gl_bumper_init_resources;
291 GST_GL_FILTER_CLASS (klass)->display_reset_cb = gst_gl_bumper_reset_resources;
292 GST_GL_FILTER_CLASS (klass)->init_fbo = gst_gl_bumper_init_shader;
293 GST_GL_FILTER_CLASS (klass)->onReset = gst_gl_bumper_reset;
294
295 g_object_class_install_property (gobject_class,
296 PROP_LOCATION, g_param_spec_string ("location",
297 "Normal map location",
298 "Normal map location", NULL,
299 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
300
301 gst_element_class_set_metadata (element_class, "OpenGL bumper filter",
302 "Filter/Effect/Video", "Bump mapping filter",
303 "Cyril Comparon <cyril.comparon@gmail.com>, "
304 "Julien Isorce <julien.isorce@gmail.com>");
305
306 GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api = GST_GL_API_OPENGL;
307 }
308
309 static void
gst_gl_bumper_init(GstGLBumper * bumper)310 gst_gl_bumper_init (GstGLBumper * bumper)
311 {
312 bumper->shader = NULL;
313 bumper->bumpmap = 0;
314 bumper->bumpmap_width = 0;
315 bumper->bumpmap_height = 0;
316 bumper->location = NULL;
317 }
318
319 static void
gst_gl_bumper_reset(GstGLFilter * filter)320 gst_gl_bumper_reset (GstGLFilter * filter)
321 {
322 GstGLBumper *bumper_filter = GST_GL_BUMPER (filter);
323
324 //blocking call, wait the opengl thread has destroyed the shader
325 if (bumper_filter->shader)
326 gst_gl_context_del_shader (filter->context, bumper_filter->shader);
327 bumper_filter->shader = NULL;
328 bumper_filter->xrot = 0.0;
329 bumper_filter->yrot = 0.0;
330 bumper_filter->zrot = 0.0;
331 }
332
333 static void
gst_gl_bumper_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)334 gst_gl_bumper_set_property (GObject * object, guint prop_id,
335 const GValue * value, GParamSpec * pspec)
336 {
337 GstGLBumper *bumper = GST_GL_BUMPER (object);
338
339 switch (prop_id) {
340 case PROP_LOCATION:
341 g_free (bumper->location);
342 bumper->location = g_value_dup_string (value);
343 break;
344 default:
345 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
346 break;
347 }
348 }
349
350 static void
gst_gl_bumper_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)351 gst_gl_bumper_get_property (GObject * object, guint prop_id,
352 GValue * value, GParamSpec * pspec)
353 {
354 GstGLBumper *bumper = GST_GL_BUMPER (object);
355
356 switch (prop_id) {
357 case PROP_LOCATION:
358 g_value_set_string (value, bumper->location);
359 break;
360 default:
361 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
362 break;
363 }
364 }
365
366 static gboolean
gst_gl_bumper_init_shader(GstGLFilter * filter)367 gst_gl_bumper_init_shader (GstGLFilter * filter)
368 {
369 GstGLBumper *bumper = GST_GL_BUMPER (filter);
370
371 //blocking call, wait the opengl thread has compiled the shader
372 return gst_gl_context_gen_shader (filter->context, bumper_v_src, bumper_f_src,
373 &bumper->shader);
374 }
375
376 static gboolean
gst_gl_bumper_filter_texture(GstGLFilter * filter,guint in_tex,guint out_tex)377 gst_gl_bumper_filter_texture (GstGLFilter * filter, guint in_tex, guint out_tex)
378 {
379 gpointer bumper_filter = GST_GL_BUMPER (filter);
380
381 //blocking call, use a FBO
382 gst_gl_context_use_fbo (filter->context,
383 GST_VIDEO_INFO_WIDTH (&filter->out_info),
384 GST_VIDEO_INFO_HEIGHT (&filter->out_info),
385 filter->fbo, filter->depthbuffer, out_tex, gst_gl_bumper_callback,
386 GST_VIDEO_INFO_WIDTH (&filter->in_info),
387 GST_VIDEO_INFO_HEIGHT (&filter->in_info),
388 in_tex, 45,
389 (gdouble) GST_VIDEO_INFO_WIDTH (&filter->out_info) /
390 (gdouble) GST_VIDEO_INFO_HEIGHT (&filter->out_info), 0.1, 50,
391 GST_GL_DISPLAY_PROJECTION_PERSPECTIVE, bumper_filter);
392
393 return TRUE;
394 }
395
396 typedef struct _MeshData
397 {
398 float x, y, z; /* Vertex */
399 float nx, ny, nz; /* Normal */
400 float s0, t0; /* TexCoord0 */
401 float s1, t1; /* TexCoord1 */
402 float va0, vb0, vc0; /* VertexAttrib */
403 } MeshData;
404
405 //opengl scene, params: input texture (not the output filter->texture)
406 static void
gst_gl_bumper_callback(gint width,gint height,guint texture,gpointer stuff)407 gst_gl_bumper_callback (gint width, gint height, guint texture, gpointer stuff)
408 {
409 GstGLFuncs *gl;
410 GstGLBumper *bumper = GST_GL_BUMPER (stuff);
411 GstGLContext *context = GST_GL_FILTER (bumper)->context;
412 GLint locTangent = 0;
413
414 //choose the lights
415 GLfloat light_direction0[] = { 1.0, 0.0, -1.0, 0.0 }; // light goes along -x
416 GLfloat light_direction1[] = { -1.0, 0.0, -1.0, 0.0 }; // light goes along x
417 GLfloat light_diffuse0[] = { 1.0, 1.0, 1.0, 1.0 };
418 GLfloat light_diffuse1[] = { 1.0, 1.0, 1.0, 1.0 };
419 GLfloat mat_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
420
421 /* *INDENT-OFF* */
422 MeshData mesh[] = {
423 /* | Vertex | Normal |TexCoord0|TexCoord1| VertexAttrib | */
424 /*F*/ { 1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
425 /*r*/ { 1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0},
426 /*o*/ {-1.0, -1.0, -1.0, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0},
427 {-1.0, 1.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
428 /*R*/ {-1.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
429 /*i*/ {-1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0},
430 /*g*/ {-1.0, -1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0},
431 {-1.0, 1.0, 1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
432 /*B*/ {-1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
433 /*a*/ {-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0},
434 /*c*/ { 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0},
435 { 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
436 /*L*/ { 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0},
437 /*e*/ { 1.0, -1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0},
438 /*f*/ { 1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0},
439 { 1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0},
440 /*T*/ { 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0},
441 /*o*/ { 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0},
442 /*p*/ {-1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0},
443 {-1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0},
444 /*B*/ { 1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0},
445 /*o*/ { 1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0},
446 /*t*/ {-1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, -1.0},
447 {-1.0, -1.0, -1.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, -1.0},
448 };
449
450 GLushort indices[] = {
451 0, 1, 2,
452 0, 2, 3,
453 4, 5, 6,
454 4, 6, 7,
455 8, 9, 10,
456 8, 10, 11,
457 12, 13, 14,
458 12, 14, 15,
459 16, 17, 18,
460 16, 18, 19,
461 20, 21, 22,
462 20, 22, 23
463 };
464
465 /* *INDENT-ON* */
466
467 gl = GST_GL_FILTER (bumper)->context->gl_vtable;
468
469 //eye point
470 gl->MatrixMode (GL_PROJECTION);
471 gluLookAt (0.0, 0.0, -6.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
472 gl->MatrixMode (GL_MODELVIEW);
473
474 //scene conf
475 gl->Enable (GL_DEPTH_TEST);
476 gl->DepthFunc (GL_LEQUAL);
477 gl->Hint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
478
479 gl->ShadeModel (GL_SMOOTH);
480
481 //set the lights
482 gl->Lightfv (GL_LIGHT0, GL_POSITION, light_direction0);
483 gl->Lightfv (GL_LIGHT0, GL_DIFFUSE, light_diffuse0);
484 gl->Lightfv (GL_LIGHT1, GL_POSITION, light_direction1);
485 gl->Lightfv (GL_LIGHT1, GL_DIFFUSE, light_diffuse1);
486 gl->Materialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse);
487 gl->ColorMaterial (GL_FRONT_AND_BACK, GL_DIFFUSE);
488 gl->Enable (GL_COLOR_MATERIAL);
489 gl->Enable (GL_LIGHTING);
490 gl->Enable (GL_LIGHT0);
491 gl->Enable (GL_LIGHT1);
492 //configure shader
493 gst_gl_shader_use (bumper->shader);
494 locTangent =
495 gst_gl_shader_get_attribute_location (bumper->shader, "aTangent");
496
497 //set the normal map
498 gl->ActiveTexture (GL_TEXTURE1);
499 gst_gl_shader_set_uniform_1i (bumper->shader, "texture1", 1);
500 gl->BindTexture (GL_TEXTURE_2D, bumper->bumpmap);
501
502 //set the video texture
503 gl->ActiveTexture (GL_TEXTURE0);
504 gst_gl_shader_set_uniform_1i (bumper->shader, "texture0", 0);
505 gl->BindTexture (GL_TEXTURE_2D, texture);
506
507 gl->Rotatef (bumper->xrot, 1.0f, 0.0f, 0.0f);
508 gl->Rotatef (bumper->yrot, 0.0f, 1.0f, 0.0f);
509 gl->Rotatef (bumper->zrot, 0.0f, 0.0f, 1.0f);
510
511 gl->EnableVertexAttribArray (locTangent);
512
513 gl->ClientActiveTexture (GL_TEXTURE0);
514 gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
515 gl->EnableClientState (GL_VERTEX_ARRAY);
516 gl->EnableClientState (GL_NORMAL_ARRAY);
517
518 gl->VertexAttribPointer (locTangent, 3, GL_FLOAT, 0, sizeof (MeshData),
519 &mesh[0].va0);
520 gl->VertexPointer (3, GL_FLOAT, sizeof (MeshData), &mesh[0].x);
521 gl->NormalPointer (GL_FLOAT, sizeof (MeshData), &mesh[0].nx);
522 gl->TexCoordPointer (2, GL_FLOAT, sizeof (MeshData), &mesh[0].s0);
523
524 gl->ClientActiveTexture (GL_TEXTURE1);
525 gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
526 gl->TexCoordPointer (2, GL_FLOAT, sizeof (MeshData), &mesh[0].s1);
527
528 gl->DrawElements (GL_TRIANGLES, 36, GL_UNSIGNED_SHORT, indices);
529
530 gl->DisableClientState (GL_VERTEX_ARRAY);
531 gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
532 gl->DisableClientState (GL_NORMAL_ARRAY);
533
534 gl->ClientActiveTexture (GL_TEXTURE0);
535 gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
536
537 gl->DisableVertexAttribArray (locTangent);
538
539 gst_gl_context_clear_shader (context);
540
541 gl->Disable (GL_LIGHT0);
542 gl->Disable (GL_LIGHT1);
543 gl->Disable (GL_LIGHTING);
544 gl->Disable (GL_COLOR_MATERIAL);
545
546 bumper->xrot += 1.0f;
547 bumper->yrot += 0.9f;
548 bumper->zrot += 0.6f;
549 }
550