]> git.sesse.net Git - vlc/blob - modules/video_output/opengl.c
* Patch by Cédric Cocquebert to add several additional video effects to the opengl...
[vlc] / modules / video_output / opengl.c
1 /*****************************************************************************
2  * opengl.c: OpenGL video output
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *          Gildas Bazin <gbazin@videolan.org>
9  *          Eric Petit <titer@m0k.org>
10  *                  Cedric Cocquebert <cedric.cocquebert@supelec.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #include <errno.h>                                                 /* ENOMEM */
31 #include <stdlib.h>                                      /* malloc(), free() */
32 #include <string.h>
33
34 #include <vlc/vlc.h>
35 #include <vlc/vout.h>
36
37 #ifdef __APPLE__
38 #include <OpenGL/gl.h>
39 #include <OpenGL/glext.h>
40
41 /* On OS X, use GL_TEXTURE_RECTANGLE_EXT instead of GL_TEXTURE_2D.
42    This allows sizes which are not powers of 2 */
43 #define VLCGL_TARGET GL_TEXTURE_RECTANGLE_EXT
44
45 /* OS X OpenGL supports YUV. Hehe. */
46 #define VLCGL_FORMAT GL_YCBCR_422_APPLE
47 #define VLCGL_TYPE   GL_UNSIGNED_SHORT_8_8_APPLE
48 #else
49
50 #include <GL/gl.h>
51 #define VLCGL_TARGET GL_TEXTURE_2D
52
53 /* RV16 */
54 #ifndef GL_UNSIGNED_SHORT_5_6_5
55 #define GL_UNSIGNED_SHORT_5_6_5 0x8363
56 #endif
57 //#define VLCGL_RGB_FORMAT GL_RGB
58 //#define VLCGL_RGB_TYPE GL_UNSIGNED_SHORT_5_6_5
59
60 /* RV24 */
61 //#define VLCGL_RGB_FORMAT GL_RGB
62 //#define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
63
64 /* RV32 */
65 #define VLCGL_RGB_FORMAT GL_RGBA
66 #define VLCGL_RGB_TYPE GL_UNSIGNED_BYTE
67
68 /* YUY2 */
69 #ifndef YCBCR_MESA
70 #define YCBCR_MESA 0x8757
71 #endif
72 #ifndef UNSIGNED_SHORT_8_8_MESA
73 #define UNSIGNED_SHORT_8_8_MESA 0x85BA
74 #endif
75 #define VLCGL_YUV_FORMAT YCBCR_MESA
76 #define VLCGL_YUV_TYPE UNSIGNED_SHORT_8_8_MESA
77
78 /* Use RGB on Win32/GLX */
79 #define VLCGL_FORMAT VLCGL_RGB_FORMAT
80 #define VLCGL_TYPE   VLCGL_RGB_TYPE
81 //#define VLCGL_FORMAT VLCGL_YUV_FORMAT
82 //#define VLCGL_TYPE   VLCGL_YUV_TYPE
83 #endif
84
85 #ifndef GL_CLAMP_TO_EDGE
86 #   define GL_CLAMP_TO_EDGE 0x812F
87 #endif
88
89 /* OpenGL effects */
90 #define OPENGL_EFFECT_NONE             1
91 #define OPENGL_EFFECT_CUBE             2
92 #define OPENGL_EFFECT_TRANSPARENT_CUBE 4
93 #if defined( HAVE_GL_GLU_H ) || defined( SYS_DARWIN )
94     #define OPENGL_MORE_EFFECT             8
95 #endif
96
97 #ifdef OPENGL_MORE_EFFECT
98         #include <math.h>
99         #ifdef SYS_DARWIN
100                 #include <OpenGL/glu.h>
101         #else
102                 #include <GL/glu.h>
103         #endif
104 /* 3D MODEL */
105         #define CYLINDER 8
106         #define TORUS    16
107         #define SPHERE   32
108 /*GRID2D TRANSFORMATION */
109         #define SQUAREXY 64
110         #define SQUARER  128
111         #define ASINXY   256
112         #define ASINR    512
113         #define SINEXY   1024
114         #define SINER    2048
115         #define INIFILE  4096                                   // not used, just for mark end ...
116         #define SIGN(x)  (x < 0 ? (-1) : 1)
117         #define PID2     1.570796326794896619231322
118
119         static char *ppsz_effects[] = {
120                         "none", "cube", "transparent-cube", "cylinder", "torus", "sphere","SQUAREXY","SQUARER", "ASINXY", "ASINR", "SINEXY", "SINER" };
121         static char *ppsz_effects_text[] = {
122                         N_("None"), N_("Cube"), N_("Transparent Cube"), 
123                         N_("Cylinder"), N_("Torus"), N_("Sphere"), N_("SQUAREXY"),N_("SQUARER"), N_("ASINXY"), N_("ASINR"), N_("SINEXY"), N_("SINER") };
124 #endif
125
126 /*****************************************************************************
127  * Vout interface
128  *****************************************************************************/
129 static int  CreateVout   ( vlc_object_t * );
130 static void DestroyVout  ( vlc_object_t * );
131 static int  Init         ( vout_thread_t * );
132 static void End          ( vout_thread_t * );
133 static int  Manage       ( vout_thread_t * );
134 static void Render       ( vout_thread_t *, picture_t * );
135 static void DisplayVideo ( vout_thread_t *, picture_t * );
136 static int  Control      ( vout_thread_t *, int, va_list );
137
138 static inline int GetAlignedSize( int );
139
140 static int InitTextures( vout_thread_t * );
141 static int SendEvents( vlc_object_t *, char const *,
142                        vlc_value_t, vlc_value_t, void * );
143
144 /*****************************************************************************
145  * Module descriptor
146  *****************************************************************************/
147 #ifdef OPENGL_MORE_EFFECT
148 #define ACCURACY_TEXT N_( "OpenGL sampling accuracy " )
149 #define ACCURACY_LONGTEXT N_( "Select the accuracy of 3D object sampling(1 = min and 10 = max)" )
150 #define RADIUS_TEXT N_( "OpenGL Cylinder radius" )
151 #define RADIUS_LONGTEXT N_( "Radius of the OpenGL cylinder effect, if enabled" )
152 #define POV_X_TEXT N_("Point of view x-coordinate")
153 #define POV_X_LONGTEXT N_("Point of view (X coordinate) of the cube/cylinder "\
154                            "effect, if enabled.")
155 #define POV_Y_TEXT N_("Point of view y-coordinate")
156 #define POV_Y_LONGTEXT N_("Point of view (Y coordinate) of the cube/cylinder "\
157                            "effect, if enabled.")
158 #define POV_Z_TEXT N_("Point of view z-coordinate")
159 #define POV_Z_LONGTEXT N_("Point of view (Z coordinate) of the cube/cylinder "\
160                            "effect, if enabled.")
161 #endif
162 #define SPEED_TEXT N_( "OpenGL cube rotation speed" )
163 #define SPEED_LONGTEXT N_( "Rotation speed of the OpenGL cube effect, if " \
164         "enabled." )
165 #define EFFECT_TEXT N_("Effect")
166 #define EFFECT_LONGTEXT N_( \
167     "Several visual OpenGL effects are available." )
168
169 #ifndef OPENGL_MORE_EFFECT
170 static char *ppsz_effects[] = {
171         "none", "cube", "transparent-cube" };
172 static char *ppsz_effects_text[] = {
173         N_("None"), N_("Cube"), N_("Transparent Cube") };
174 #endif
175
176 vlc_module_begin();
177     set_shortname( "OpenGL" );
178     set_category( CAT_VIDEO );
179     set_subcategory( SUBCAT_VIDEO_VOUT );
180     set_description( _("OpenGL video output") );
181 #ifdef __APPLE__
182     set_capability( "video output", 200 );
183 #else
184     set_capability( "video output", 20 );
185 #endif
186     add_shortcut( "opengl" );
187     add_float( "opengl-cube-speed", 2.0, NULL, SPEED_TEXT,
188                     SPEED_LONGTEXT, VLC_TRUE );
189 #ifdef OPENGL_MORE_EFFECT
190     add_integer_with_range( "opengl-accuracy", 4, 1, 10, NULL, ACCURACY_TEXT,
191                     ACCURACY_LONGTEXT, VLC_TRUE );
192     add_float_with_range( "opengl-pov-x", 0.0, -1.0, 1.0, NULL, POV_X_TEXT,
193                     POV_X_LONGTEXT, VLC_TRUE );
194     add_float_with_range( "opengl-pov-y", 0.0, -1.0, 1.0, NULL, POV_Y_TEXT,
195                     POV_Y_LONGTEXT, VLC_TRUE );
196     add_float_with_range( "opengl-pov-z", -1.0, -1.0, 1.0, NULL, POV_Z_TEXT,
197                     POV_Z_LONGTEXT, VLC_TRUE );
198     add_float( "opengl-cylinder-radius", -100.0, NULL, RADIUS_TEXT,
199                     RADIUS_LONGTEXT, VLC_TRUE );
200
201 #endif
202     set_callbacks( CreateVout, DestroyVout );
203     add_string( "opengl-effect", "none", NULL, EFFECT_TEXT,
204                  EFFECT_LONGTEXT, VLC_FALSE );
205                 change_string_list( ppsz_effects, ppsz_effects_text, 0 );
206 vlc_module_end();
207
208 /*****************************************************************************
209  * vout_sys_t: video output method descriptor
210  *****************************************************************************
211  * This structure is part of the video output thread descriptor.
212  * It describes the OpenGL specific properties of the output thread.
213  *****************************************************************************/
214 struct vout_sys_t
215 {
216     vout_thread_t *p_vout;
217
218     uint8_t    *pp_buffer[2];
219     int         i_index;
220     int         i_tex_width;
221     int         i_tex_height;
222     GLuint      p_textures[2];
223
224     int         i_effect;
225
226     float       f_speed;
227     float       f_radius;
228 };
229
230 /*****************************************************************************
231  * CreateVout: This function allocates and initializes the OpenGL vout method.
232  *****************************************************************************/
233 static int CreateVout( vlc_object_t *p_this )
234 {
235     vout_thread_t *p_vout = (vout_thread_t *)p_this;
236     vout_sys_t *p_sys;
237
238     /* Allocate structure */
239     p_vout->p_sys = p_sys = malloc( sizeof( vout_sys_t ) );
240     if( p_sys == NULL )
241     {
242         msg_Err( p_vout, "out of memory" );
243         return VLC_EGENERIC;
244     }
245
246     var_Create( p_vout, "opengl-effect", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
247
248     p_sys->i_index = 0;
249 #ifdef __APPLE__
250     p_sys->i_tex_width  = p_vout->fmt_in.i_width;
251     p_sys->i_tex_height = p_vout->fmt_in.i_height;
252 #else
253     /* A texture must have a size aligned on a power of 2 */
254     p_sys->i_tex_width  = GetAlignedSize( p_vout->fmt_in.i_width );
255     p_sys->i_tex_height = GetAlignedSize( p_vout->fmt_in.i_height );
256 #endif
257
258     msg_Dbg( p_vout, "Texture size: %dx%d", p_sys->i_tex_width,
259              p_sys->i_tex_height );
260
261     /* Get window */
262     p_sys->p_vout =
263         (vout_thread_t *)vlc_object_create( p_this, VLC_OBJECT_OPENGL );
264     if( p_sys->p_vout == NULL )
265     {
266         msg_Err( p_vout, "out of memory" );
267         return VLC_ENOMEM;
268     }
269     vlc_object_attach( p_sys->p_vout, p_this );
270
271     p_sys->p_vout->i_window_width = p_vout->i_window_width;
272     p_sys->p_vout->i_window_height = p_vout->i_window_height;
273     p_sys->p_vout->b_fullscreen = p_vout->b_fullscreen;
274     p_sys->p_vout->render.i_width = p_vout->render.i_width;
275     p_sys->p_vout->render.i_height = p_vout->render.i_height;
276     p_sys->p_vout->render.i_aspect = p_vout->render.i_aspect;
277     p_sys->p_vout->fmt_render = p_vout->fmt_render;
278     p_sys->p_vout->fmt_in = p_vout->fmt_in;
279     p_sys->p_vout->b_scale = p_vout->b_scale;
280     p_sys->p_vout->i_alignment = p_vout->i_alignment;
281
282     p_sys->p_vout->p_module =
283         module_Need( p_sys->p_vout, "opengl provider", NULL, 0 );
284     if( p_sys->p_vout->p_module == NULL )
285     {
286         msg_Warn( p_vout, "No OpenGL provider found" );
287         vlc_object_detach( p_sys->p_vout );
288         vlc_object_destroy( p_sys->p_vout );
289         return VLC_ENOOBJ;
290     }
291
292     p_sys->f_speed = var_CreateGetFloat( p_vout, "opengl-cube-speed" );
293     p_sys->f_radius = var_CreateGetFloat( p_vout, "opengl-cylinder-radius" );
294
295     p_vout->pf_init = Init;
296     p_vout->pf_end = End;
297     p_vout->pf_manage = Manage;
298     p_vout->pf_render = Render;
299     p_vout->pf_display = DisplayVideo;
300     p_vout->pf_control = Control;
301
302     /* Forward events from the opengl provider */
303     var_Create( p_sys->p_vout, "mouse-x", VLC_VAR_INTEGER );
304     var_Create( p_sys->p_vout, "mouse-y", VLC_VAR_INTEGER );
305     var_Create( p_sys->p_vout, "mouse-moved/", VLC_VAR_BOOL );
306     var_Create( p_sys->p_vout, "mouse-clicked", VLC_VAR_INTEGER );
307     var_Create( p_sys->p_vout, "mouse-button-down", VLC_VAR_INTEGER );
308     var_Create( p_sys->p_vout, "video-on-top",
309                 VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
310
311     var_AddCallback( p_sys->p_vout, "mouse-x", SendEvents, p_vout );
312     var_AddCallback( p_sys->p_vout, "mouse-y", SendEvents, p_vout );
313     var_AddCallback( p_sys->p_vout, "mouse-moved", SendEvents, p_vout );
314     var_AddCallback( p_sys->p_vout, "mouse-clicked", SendEvents, p_vout );
315     var_AddCallback( p_sys->p_vout, "mouse-button-down", SendEvents, p_vout );
316
317     return VLC_SUCCESS;
318 }
319
320 /*****************************************************************************
321  * Init: initialize the OpenGL video thread output method
322  *****************************************************************************/
323 static int Init( vout_thread_t *p_vout )
324 {
325     vout_sys_t *p_sys = p_vout->p_sys;
326     int i_pixel_pitch;
327     vlc_value_t val;
328
329     p_sys->p_vout->pf_init( p_sys->p_vout );
330
331 /* TODO: We use YCbCr on Mac which is Y422, but on OSX it seems to == YUY2. Verify */
332 #if ( defined( WORDS_BIGENDIAN ) && VLCGL_FORMAT == GL_YCBCR_422_APPLE ) || (VLCGL_FORMAT == YCBCR_MESA)
333     p_vout->output.i_chroma = VLC_FOURCC('Y','U','Y','2');
334     i_pixel_pitch = 2;
335
336 #elif (VLCGL_FORMAT == GL_YCBCR_422_APPLE)
337     p_vout->output.i_chroma = VLC_FOURCC('U','Y','V','Y');
338     i_pixel_pitch = 2;
339
340 #elif VLCGL_FORMAT == GL_RGB
341 #   if VLCGL_TYPE == GL_UNSIGNED_BYTE
342     p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
343 #       if defined( WORDS_BIGENDIAN )
344     p_vout->output.i_rmask = 0x00ff0000;
345     p_vout->output.i_gmask = 0x0000ff00;
346     p_vout->output.i_bmask = 0x000000ff;
347 #       else
348     p_vout->output.i_rmask = 0x000000ff;
349     p_vout->output.i_gmask = 0x0000ff00;
350     p_vout->output.i_bmask = 0x00ff0000;
351 #       endif
352     i_pixel_pitch = 3;
353 #   else
354     p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
355 #       if defined( WORDS_BIGENDIAN )
356     p_vout->output.i_rmask = 0x001f;
357     p_vout->output.i_gmask = 0x07e0;
358     p_vout->output.i_bmask = 0xf800;
359 #       else
360     p_vout->output.i_rmask = 0xf800;
361     p_vout->output.i_gmask = 0x07e0;
362     p_vout->output.i_bmask = 0x001f;
363 #       endif
364     i_pixel_pitch = 2;
365 #   endif
366 #else
367     p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
368 #       if defined( WORDS_BIGENDIAN )
369     p_vout->output.i_rmask = 0xff000000;
370     p_vout->output.i_gmask = 0x00ff0000;
371     p_vout->output.i_bmask = 0x0000ff00;
372 #       else
373     p_vout->output.i_rmask = 0x000000ff;
374     p_vout->output.i_gmask = 0x0000ff00;
375     p_vout->output.i_bmask = 0x00ff0000;
376 #       endif
377     i_pixel_pitch = 4;
378 #endif
379
380     /* Since OpenGL can do rescaling for us, stick to the default
381      * coordinates and aspect. */
382     p_vout->output.i_width  = p_vout->render.i_width;
383     p_vout->output.i_height = p_vout->render.i_height;
384     p_vout->output.i_aspect = p_vout->render.i_aspect;
385
386     p_vout->fmt_out = p_vout->fmt_in;
387     p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
388
389     /* We know the chroma, allocate one buffer which will be used
390      * directly by the decoder */
391     p_sys->pp_buffer[0] =
392         malloc( p_sys->i_tex_width * p_sys->i_tex_height * i_pixel_pitch );
393     if( !p_sys->pp_buffer[0] )
394     {
395         msg_Err( p_vout, "out of memory" );
396         return -1;
397     }
398     p_sys->pp_buffer[1] =
399         malloc( p_sys->i_tex_width * p_sys->i_tex_height * i_pixel_pitch );
400     if( !p_sys->pp_buffer[1] )
401     {
402         msg_Err( p_vout, "out of memory" );
403         return -1;
404     }
405
406     p_vout->p_picture[0].i_planes = 1;
407     p_vout->p_picture[0].p->p_pixels = p_sys->pp_buffer[0];
408     p_vout->p_picture[0].p->i_lines = p_vout->output.i_height;
409     p_vout->p_picture[0].p->i_visible_lines = p_vout->output.i_height;
410     p_vout->p_picture[0].p->i_pixel_pitch = i_pixel_pitch;
411     p_vout->p_picture[0].p->i_pitch = p_vout->output.i_width *
412         p_vout->p_picture[0].p->i_pixel_pitch;
413     p_vout->p_picture[0].p->i_visible_pitch = p_vout->output.i_width *
414         p_vout->p_picture[0].p->i_pixel_pitch;
415
416     p_vout->p_picture[0].i_status = DESTROYED_PICTURE;
417     p_vout->p_picture[0].i_type   = DIRECT_PICTURE;
418
419     PP_OUTPUTPICTURE[ 0 ] = &p_vout->p_picture[0];
420
421     I_OUTPUTPICTURES = 1;
422
423     if( p_sys->p_vout->pf_lock &&
424         p_sys->p_vout->pf_lock( p_sys->p_vout ) )
425     {
426         msg_Warn( p_vout, "could not lock OpenGL provider" );
427         return 0;
428     }
429
430     InitTextures( p_vout );
431
432     glDisable(GL_BLEND);
433     glDisable(GL_DEPTH_TEST);
434     glDepthMask(GL_FALSE);
435     glDisable(GL_CULL_FACE);
436     glClear( GL_COLOR_BUFFER_BIT );
437
438     /* Check if the user asked for useless visual effects */
439     var_Get( p_vout, "opengl-effect", &val );
440     if( !val.psz_string || !strcmp( val.psz_string, "none" ))
441     {
442         p_sys->i_effect = OPENGL_EFFECT_NONE;
443     }
444     else if( !strcmp( val.psz_string, "cube" ) )
445     {
446         p_sys->i_effect = OPENGL_EFFECT_CUBE;
447
448         glEnable( GL_CULL_FACE);
449     }
450     else if( !strcmp( val.psz_string, "transparent-cube" ) )
451     {
452         p_sys->i_effect = OPENGL_EFFECT_TRANSPARENT_CUBE;
453
454         glDisable( GL_DEPTH_TEST );
455         glEnable( GL_BLEND );
456         glBlendFunc( GL_SRC_ALPHA, GL_ONE );
457     }
458     else
459     {
460 #ifdef OPENGL_MORE_EFFECT
461                 p_sys->i_effect = 3;
462         while (( strcmp( val.psz_string, ppsz_effects[p_sys->i_effect]) ) && (pow(2,p_sys->i_effect) < INIFILE))
463         {
464             p_sys->i_effect ++;
465         }
466                 if (pow(2,p_sys->i_effect) < INIFILE) 
467                         p_sys->i_effect = pow(2,p_sys->i_effect);
468                 else if ( strcmp( val.psz_string, ppsz_effects[p_sys->i_effect]))
469                 {
470                         msg_Warn( p_vout, "no valid opengl effect provided, using "
471                                           "\"none\"" );
472                         p_sys->i_effect = OPENGL_EFFECT_NONE;
473                 }
474 #else
475         msg_Warn( p_vout, "no valid opengl effect provided, using "
476                   "\"none\"" );
477         p_sys->i_effect = OPENGL_EFFECT_NONE;
478 #endif
479     }
480     if( val.psz_string ) free( val.psz_string );
481
482     if( p_sys->i_effect & ( OPENGL_EFFECT_CUBE |
483                 OPENGL_EFFECT_TRANSPARENT_CUBE ) )
484     {
485         /* Set the perpective */
486         glMatrixMode( GL_PROJECTION );
487         glLoadIdentity();
488         glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
489         glMatrixMode( GL_MODELVIEW );
490         glLoadIdentity();
491         glTranslatef( 0.0, 0.0, - 5.0 );
492     }
493 #ifdef OPENGL_MORE_EFFECT
494         else 
495     {
496         /* Set the perpective */
497         glMatrixMode( GL_PROJECTION );
498         glLoadIdentity();
499         glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
500         glMatrixMode( GL_MODELVIEW );
501         glLoadIdentity();
502         glTranslatef( 0.0, 0.0, -3.0 );
503
504                 float f_pov_x, f_pov_y, f_pov_z;
505                 f_pov_x = var_CreateGetFloat( p_vout, "opengl-pov-x");
506                 f_pov_y = var_CreateGetFloat( p_vout, "opengl-pov-y");
507                 f_pov_z = var_CreateGetFloat( p_vout, "opengl-pov-z");
508                 gluLookAt(0, 0, 0, f_pov_x, f_pov_y, f_pov_z, 0, 1, 0);
509     }
510 #endif
511     if( p_sys->p_vout->pf_unlock )
512     {
513         p_sys->p_vout->pf_unlock( p_sys->p_vout );
514     }
515
516     return 0;
517 }
518
519 /*****************************************************************************
520  * End: terminate GLX video thread output method
521  *****************************************************************************/
522 static void End( vout_thread_t *p_vout )
523 {
524     vout_sys_t *p_sys = p_vout->p_sys;
525
526     if( p_sys->p_vout->pf_lock &&
527         p_sys->p_vout->pf_lock( p_sys->p_vout ) )
528     {
529         msg_Warn( p_vout, "could not lock OpenGL provider" );
530         return;
531     }
532
533     glFinish();
534     glFlush();
535
536     if( p_sys->p_vout->pf_unlock )
537     {
538         p_sys->p_vout->pf_unlock( p_sys->p_vout );
539     }
540 }
541
542 /*****************************************************************************
543  * Destroy: destroy GLX video thread output method
544  *****************************************************************************
545  * Terminate an output method created by CreateVout
546  *****************************************************************************/
547 static void DestroyVout( vlc_object_t *p_this )
548 {
549     vout_thread_t *p_vout = (vout_thread_t *)p_this;
550     vout_sys_t *p_sys = p_vout->p_sys;
551
552     module_Unneed( p_sys->p_vout, p_sys->p_vout->p_module );
553     vlc_object_detach( p_sys->p_vout );
554     vlc_object_destroy( p_sys->p_vout );
555
556     /* Free the texture buffer*/
557     if( p_sys->pp_buffer[0] ) free( p_sys->pp_buffer[0] );
558     if( p_sys->pp_buffer[1] ) free( p_sys->pp_buffer[1] );
559
560     glDeleteTextures( 2, p_sys->p_textures );
561
562     free( p_sys );
563 }
564
565 /*****************************************************************************
566  * Manage: handle Sys events
567  *****************************************************************************
568  * This function should be called regularly by video output thread. It returns
569  * a non null value if an error occurred.
570  *****************************************************************************/
571 static int Manage( vout_thread_t *p_vout )
572 {
573     vout_sys_t *p_sys = p_vout->p_sys;
574     int i_ret, i_fullscreen_change;
575
576     i_fullscreen_change = ( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE );
577
578     p_vout->fmt_out.i_x_offset = p_sys->p_vout->fmt_in.i_x_offset =
579         p_vout->fmt_in.i_x_offset;
580     p_vout->fmt_out.i_y_offset = p_sys->p_vout->fmt_in.i_y_offset =
581         p_vout->fmt_in.i_y_offset;
582     p_vout->fmt_out.i_visible_width = p_sys->p_vout->fmt_in.i_visible_width =
583         p_vout->fmt_in.i_visible_width;
584     p_vout->fmt_out.i_visible_height = p_sys->p_vout->fmt_in.i_visible_height =
585         p_vout->fmt_in.i_visible_height;
586     p_vout->fmt_out.i_aspect = p_sys->p_vout->fmt_in.i_aspect =
587         p_vout->fmt_in.i_aspect;
588     p_vout->fmt_out.i_sar_num = p_sys->p_vout->fmt_in.i_sar_num =
589         p_vout->fmt_in.i_sar_num;
590     p_vout->fmt_out.i_sar_den = p_sys->p_vout->fmt_in.i_sar_den =
591         p_vout->fmt_in.i_sar_den;
592     p_vout->output.i_aspect = p_vout->fmt_in.i_aspect;
593
594     p_sys->p_vout->i_changes = p_vout->i_changes;
595     i_ret = p_sys->p_vout->pf_manage( p_sys->p_vout );
596     p_vout->i_changes = p_sys->p_vout->i_changes;
597
598 #ifdef __APPLE__
599     if( p_sys->p_vout->pf_lock &&
600         p_sys->p_vout->pf_lock( p_sys->p_vout ) )
601     {
602         msg_Warn( p_vout, "could not lock OpenGL provider" );
603         return i_ret;
604     }
605
606     /* On OS X, we create the window and the GL view when entering
607        fullscreen - the textures have to be inited again */
608     if( i_fullscreen_change )
609     {
610         InitTextures( p_vout );
611
612         switch( p_sys->i_effect )
613         {
614             case OPENGL_EFFECT_CUBE:
615 #ifdef OPENGL_MORE_EFFECT
616                         case CYLINDER:
617                         case TORUS:
618                         case SPHERE:
619                         case SQUAREXY:
620                         case SQUARER:
621                         case ASINXY:
622                         case ASINR:
623                         case SINEXY:
624                         case SINER:
625 #endif            
626                 glEnable( GL_CULL_FACE );
627                 break;
628
629             case OPENGL_EFFECT_TRANSPARENT_CUBE:
630                 glDisable( GL_DEPTH_TEST );
631                 glEnable( GL_BLEND );
632                 glBlendFunc( GL_SRC_ALPHA, GL_ONE );
633                 break;
634         }
635
636         if( p_sys->i_effect & ( OPENGL_EFFECT_CUBE |
637                     OPENGL_EFFECT_TRANSPARENT_CUBE ) )
638         {
639             /* Set the perpective */
640             glMatrixMode( GL_PROJECTION );
641             glLoadIdentity();
642             glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
643             glMatrixMode( GL_MODELVIEW );
644             glLoadIdentity();
645             glTranslatef( 0.0, 0.0, - 5.0 );
646         }
647 #ifdef OPENGL_MORE_EFFECT
648                 else 
649             {
650                 glMatrixMode( GL_PROJECTION );
651                 glLoadIdentity();
652                 glFrustum( -1.0, 1.0, -1.0, 1.0, 3.0, 20.0 );
653                 glMatrixMode( GL_MODELVIEW );
654                 glLoadIdentity();
655                 glTranslatef( 0.0, 0.0, -3.0 );
656         
657                         float f_pov_x, f_pov_y, f_pov_z;
658                         f_pov_x = var_CreateGetFloat( p_vout, "opengl-pov-x");
659                         f_pov_y = var_CreateGetFloat( p_vout, "opengl-pov-y");
660                         f_pov_z = var_CreateGetFloat( p_vout, "opengl-pov-z");
661                         gluLookAt(0, 0, 0, f_pov_x, f_pov_y, f_pov_z, 0, 1, 0);
662             }
663 #endif        
664     }
665
666     if( p_sys->p_vout->pf_unlock )
667     {
668         p_sys->p_vout->pf_unlock( p_sys->p_vout );
669     }
670 #endif
671
672     return i_ret;
673 }
674
675 /*****************************************************************************
676  * Render: render previously calculated output
677  *****************************************************************************/
678 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
679 {
680     vout_sys_t *p_sys = p_vout->p_sys;
681
682     /* On Win32/GLX, we do this the usual way:
683        + Fill the buffer with new content,
684        + Reload the texture,
685        + Use the texture.
686
687        On OS X with VRAM or AGP texturing, the order has to be:
688        + Reload the texture,
689        + Fill the buffer with new content,
690        + Use the texture.
691
692        (Thanks to gcc from the Arstechnica forums for the tip)
693
694        Therefore, we have to use two buffers and textures. On Win32/GLX,
695        we reload the texture to be displayed and use it right away. On
696        OS X, we first render, then reload the texture to be used next
697        time. */
698
699     if( p_sys->p_vout->pf_lock &&
700         p_sys->p_vout->pf_lock( p_sys->p_vout ) )
701     {
702         msg_Warn( p_vout, "could not lock OpenGL provider" );
703         return;
704     }
705
706 #ifdef __APPLE__
707     int i_new_index;
708     i_new_index = ( p_sys->i_index + 1 ) & 1;
709
710
711     /* Update the texture */
712     glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_new_index] );
713     glTexSubImage2D( VLCGL_TARGET, 0, 0, 0,
714                      p_vout->fmt_out.i_width,
715                      p_vout->fmt_out.i_height,
716                      VLCGL_FORMAT, VLCGL_TYPE, p_sys->pp_buffer[i_new_index] );
717
718     /* Bind to the previous texture for drawing */
719     glBindTexture( VLCGL_TARGET, p_sys->p_textures[p_sys->i_index] );
720
721     /* Switch buffers */
722     p_sys->i_index = i_new_index;
723     p_pic->p->p_pixels = p_sys->pp_buffer[p_sys->i_index];
724
725 #else
726     /* Update the texture */
727     glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
728                      p_vout->fmt_out.i_width,
729                      p_vout->fmt_out.i_height,
730                      VLCGL_FORMAT, VLCGL_TYPE, p_sys->pp_buffer[0] );
731 #endif
732
733     if( p_sys->p_vout->pf_unlock )
734     {
735         p_sys->p_vout->pf_unlock( p_sys->p_vout );
736     }
737 }
738
739
740 #ifdef OPENGL_MORE_EFFECT
741 /*****************************************************************************
742  *   Transform: Calculate the distorted grid coordinates
743  *****************************************************************************/
744 void Transform(float p, int distortion, float width, float height,int i, int j, int i_visible_width, int i_visible_height, double *ix,double *iy)
745 {
746    double x,y,xnew,ynew;
747    double r,theta,rnew,thetanew;
748
749    x = (double)i * (width / ((double)i_visible_width));
750    y = (double)j * (height / ((double)i_visible_height));
751
752    x = (2.0 * (double)x / width) - 1;
753    y = (2.0 * (double)y / height) - 1;
754    xnew = x;
755    ynew = y;
756    r = sqrt(x*x+y*y);
757    theta = atan2(y,x);
758
759    switch (distortion) 
760    {
761 /* GRID2D TRANSFORMATION */
762            case SINEXY:
763                   xnew = sin(PID2*x);
764                   ynew = sin(PID2*y);
765                   break;
766            case SINER:
767                   rnew = sin(PID2*r);
768                   thetanew = theta;
769                   xnew = rnew * cos(thetanew);
770                   ynew = rnew * sin(thetanew);
771                   break;
772            case SQUAREXY:
773                   xnew = x*x*SIGN(x);
774                   ynew = y*y*SIGN(y);
775                   break;
776            case SQUARER:
777                   rnew = r*r;
778                   thetanew = theta;
779                   xnew = rnew * cos(thetanew);
780                   ynew = rnew * sin(thetanew);
781                   break;
782            case ASINXY:
783                   xnew = asin(x) / PID2;
784                   ynew = asin(y) / PID2;
785                   break;
786            case ASINR:
787                   rnew = asin(r) / PID2;
788                   thetanew = theta;
789                   xnew = rnew * cos(thetanew);
790                   ynew = rnew * sin(thetanew);
791                   break;
792 /* OTHER WAY: 3D MODEL */
793            default:
794                   xnew = x;
795                   ynew = y;
796    }
797
798    *ix = width * (xnew + 1) / (2.0);
799    *iy = height * (ynew + 1) / (2.0);
800 }
801
802
803 /*****************************************************************************
804  *   Z_Compute: Calculate the Z-coordinate
805  *****************************************************************************/
806 float Z_Compute(float p, int distortion, float x, float y)
807 {
808   float f_z = 0.0;
809   double d_p = p / 100.0;
810
811   switch (distortion) 
812    {
813 /* 3D MODEL */
814            case CYLINDER:
815                   if (d_p > 0) 
816                         f_z = (1 - d_p * d_p) / (2 * d_p) - sqrt(fabs((d_p * d_p + 1) / (2 * d_p) * (d_p * d_p + 1) / (2 * d_p) - x * x));
817                   else
818                         f_z = (1 - d_p * d_p) / (2 * d_p) + d_p + sqrt(fabs((d_p * d_p + 1) / (2 * d_p) * (d_p * d_p + 1) / (2 * d_p) - x * x));
819                   break;
820            case TORUS:
821                   if (d_p > 0) 
822                     f_z =  (1 - d_p * d_p) / (d_p) - sqrt(fabs((d_p * d_p + 1) / (2 * d_p) * (d_p * d_p + 1) / (2 * d_p) - x * x)) - sqrt(fabs((d_p * d_p + 1) / (2 * d_p) * (d_p * d_p + 1) / (2 * d_p) - y * y));
823                   else
824                         f_z =  (1 - d_p * d_p) / (d_p) + 2 * d_p + sqrt(fabs((d_p * d_p + 1) / (2 * d_p) * (d_p * d_p + 1) / (2 * d_p) - x * x)) + sqrt(fabs((d_p * d_p + 1) / (2 * d_p) * (d_p * d_p + 1) / (2 * d_p) - y * y));
825                   break;
826            case SPHERE:
827                   if (d_p > 0) 
828                     f_z = (1 - d_p * d_p) / (2 * d_p) - sqrt(fabs((d_p * d_p + 1) / (2 * d_p) * (d_p * d_p + 1) / (2 * d_p) - x * x - y * y));
829                   else
830                         f_z = (1 - d_p * d_p) / (2 * d_p) + d_p + sqrt(fabs((d_p * d_p + 1) / (2 * d_p) * (d_p * d_p + 1) / (2 * d_p) - x * x - y * y));
831                   break;
832 /* OTHER WAY: GRID2D TRANSFORMATION */
833            case SINEXY:;
834            case SINER:
835            case SQUAREXY:
836            case SQUARER:;
837            case ASINXY:
838            case ASINR:
839                   f_z = 0.0;
840                   break;
841            default:
842                    f_z = 0.0;
843    }
844   return f_z;
845 }
846 #endif
847
848
849 /*****************************************************************************
850  * DisplayVideo: displays previously rendered output
851  *****************************************************************************/
852 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
853 {
854     vout_sys_t *p_sys = p_vout->p_sys;
855     float f_width, f_height, f_x, f_y;
856
857     if( p_sys->p_vout->pf_lock &&
858         p_sys->p_vout->pf_lock( p_sys->p_vout ) )
859     {
860         msg_Warn( p_vout, "could not lock OpenGL provider" );
861         return;
862     }
863
864     /* glTexCoord works differently with GL_TEXTURE_2D and
865        GL_TEXTURE_RECTANGLE_EXT */
866 #ifdef __APPLE__
867     f_x = (float)p_vout->fmt_out.i_x_offset;
868     f_y = (float)p_vout->fmt_out.i_y_offset;
869     f_width = (float)p_vout->fmt_out.i_x_offset +
870               (float)p_vout->fmt_out.i_visible_width;
871     f_height = (float)p_vout->fmt_out.i_y_offset +
872                (float)p_vout->fmt_out.i_visible_height;
873 #else
874     f_x = (float)p_vout->fmt_out.i_x_offset / p_sys->i_tex_width;
875     f_y = (float)p_vout->fmt_out.i_y_offset / p_sys->i_tex_height;
876     f_width = ( (float)p_vout->fmt_out.i_x_offset +
877                 p_vout->fmt_out.i_visible_width ) / p_sys->i_tex_width;
878     f_height = ( (float)p_vout->fmt_out.i_y_offset +
879                  p_vout->fmt_out.i_visible_height ) / p_sys->i_tex_height;
880 #endif
881
882     /* Why drawing here and not in Render()? Because this way, the
883        OpenGL providers can call pf_display to force redraw. Currently,
884        the OS X provider uses it to get a smooth window resizing */
885
886     glClear( GL_COLOR_BUFFER_BIT );
887
888     if( p_sys->i_effect == OPENGL_EFFECT_NONE )
889     {
890         glEnable( VLCGL_TARGET );
891         glBegin( GL_POLYGON );
892         glTexCoord2f( f_x, f_y ); glVertex2f( -1.0, 1.0 );
893         glTexCoord2f( f_width, f_y ); glVertex2f( 1.0, 1.0 );
894         glTexCoord2f( f_width, f_height ); glVertex2f( 1.0, -1.0 );
895         glTexCoord2f( f_x, f_height ); glVertex2f( -1.0, -1.0 );
896         glEnd();
897     }
898     else
899 #ifdef OPENGL_MORE_EFFECT
900                 if ((p_sys->i_effect > OPENGL_EFFECT_TRANSPARENT_CUBE) || 
901                         ((p_sys->i_effect == OPENGL_EFFECT_NONE)))
902                 {
903                    unsigned int i_i, i_j;
904                    unsigned int i_accuracy  = config_GetInt( p_vout, "opengl-accuracy");
905                    unsigned int i_n = pow(2, i_accuracy);       
906                    unsigned int i_n_x = (p_vout->fmt_out.i_visible_width / (i_n * 2));
907                    unsigned int i_n_y = (p_vout->fmt_out.i_visible_height / i_n);
908                    double d_x, d_y;
909                    int i_distortion = p_sys->i_effect;
910                    float f_p = p_sys->f_radius; 
911                 
912                    glEnable( VLCGL_TARGET );
913                    glBegin(GL_QUADS);                                                              
914                    for (i_i = 0; i_i < p_vout->fmt_out.i_visible_width; i_i += i_n_x) 
915                    {
916                           if ( i_i == i_n_x * i_n / 2) i_n_x += p_vout->fmt_out.i_visible_width % i_n;
917                           if ((i_i == (p_vout->fmt_out.i_visible_width / i_n) * i_n / 2 + i_n_x) &&
918                                   (p_vout->fmt_out.i_visible_width / i_n != i_n_x))
919                                         i_n_x -= p_vout->fmt_out.i_visible_width % i_n; 
920         
921                           int i_m;
922                           int i_index_max = 0;
923                                         
924                           for (i_j = 0; i_j < p_vout->fmt_out.i_visible_height; i_j += i_n_y) 
925                           {
926                                 if ( i_j == i_n_y * i_n / 2) i_n_y += p_vout->fmt_out.i_visible_height % i_n;
927                                 if ((i_j == (p_vout->fmt_out.i_visible_height / i_n) * i_n / 2 + i_n_y) &&
928                                         (p_vout->fmt_out.i_visible_height / i_n != i_n_y))
929                                                 i_n_y -= p_vout->fmt_out.i_visible_height % i_n;
930
931                                 for (i_m = i_index_max; i_m < i_index_max + 4; i_m++)
932                                 {
933                                         int i_k = ((i_m % 4) == 1) || ((i_m % 4) == 2);
934                                         int i_l = ((i_m % 4) == 2) || ((i_m % 4) == 3);
935
936                                         Transform(f_p, i_distortion, f_width, f_height, i_i + i_k * i_n_x, i_j + i_l * i_n_y, p_vout->fmt_out.i_visible_width, p_vout->fmt_out.i_visible_height, &d_x, &d_y);                                                           
937                                         glTexCoord2f(f_x + d_x, f_y + d_y);
938                                         d_x =  - 1.0 + 2.0 * ((double)(i_k * i_n_x + i_i) / (double)p_vout->fmt_out.i_visible_width);
939                                         d_y =    1.0 - 2.0 * (((double)i_l * i_n_y + i_j) / (double)p_vout->fmt_out.i_visible_height);
940                                         glVertex3f((float)d_x, (float)d_y, Z_Compute(f_p, i_distortion, (float)d_x, (float)d_y));       
941                                 }
942                           }
943                    } 
944                    glEnd();
945                 }
946                 else
947 #endif
948         {
949         glRotatef( 0.5 * p_sys->f_speed , 0.3, 0.5, 0.7 );
950
951         glEnable( VLCGL_TARGET );
952         glBegin( GL_QUADS );
953
954         /* Front */
955         glTexCoord2f( f_x, f_y ); glVertex3f( - 1.0, 1.0, 1.0 );
956         glTexCoord2f( f_x, f_height ); glVertex3f( - 1.0, - 1.0, 1.0 );
957         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, 1.0 );
958         glTexCoord2f( f_width, f_y ); glVertex3f( 1.0, 1.0, 1.0 );
959
960         /* Left */
961         glTexCoord2f( f_x, f_y ); glVertex3f( - 1.0, 1.0, - 1.0 );
962         glTexCoord2f( f_x, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
963         glTexCoord2f( f_width, f_height ); glVertex3f( - 1.0, - 1.0, 1.0 );
964         glTexCoord2f( f_width, f_y ); glVertex3f( - 1.0, 1.0, 1.0 );
965
966         /* Back */
967         glTexCoord2f( f_x, f_y ); glVertex3f( 1.0, 1.0, - 1.0 );
968         glTexCoord2f( f_x, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
969         glTexCoord2f( f_width, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
970         glTexCoord2f( f_width, f_y ); glVertex3f( - 1.0, 1.0, - 1.0 );
971
972         /* Right */
973         glTexCoord2f( f_x, f_y ); glVertex3f( 1.0, 1.0, 1.0 );
974         glTexCoord2f( f_x, f_height ); glVertex3f( 1.0, - 1.0, 1.0 );
975         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
976         glTexCoord2f( f_width, f_y ); glVertex3f( 1.0, 1.0, - 1.0 );
977
978         /* Top */
979         glTexCoord2f( f_x, f_y ); glVertex3f( - 1.0, 1.0, - 1.0 );
980         glTexCoord2f( f_x, f_height ); glVertex3f( - 1.0, 1.0, 1.0 );
981         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, 1.0, 1.0 );
982         glTexCoord2f( f_width, f_y ); glVertex3f( 1.0, 1.0, - 1.0 );
983
984         /* Bottom */
985         glTexCoord2f( f_x, f_y ); glVertex3f( - 1.0, - 1.0, 1.0 );
986         glTexCoord2f( f_x, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
987         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
988         glTexCoord2f( f_width, f_y ); glVertex3f( 1.0, - 1.0, 1.0 );
989         glEnd();
990     }
991
992     glDisable( VLCGL_TARGET );
993
994     p_sys->p_vout->pf_swap( p_sys->p_vout );
995
996     if( p_sys->p_vout->pf_unlock )
997     {
998         p_sys->p_vout->pf_unlock( p_sys->p_vout );
999     }
1000 }
1001
1002 int GetAlignedSize( int i_size )
1003 {
1004     /* Return the nearest power of 2 */
1005     int i_result = 1;
1006     while( i_result < i_size )
1007     {
1008         i_result *= 2;
1009     }
1010     return i_result;
1011 }
1012
1013 /*****************************************************************************
1014  * Control: control facility for the vout
1015  *****************************************************************************/
1016 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
1017 {
1018     vout_sys_t *p_sys = p_vout->p_sys;
1019
1020     switch( i_query )
1021     {
1022     case VOUT_SNAPSHOT:
1023         return vout_vaControlDefault( p_vout, i_query, args );
1024
1025     default:
1026         if( p_sys->p_vout->pf_control )
1027             return p_sys->p_vout->pf_control( p_sys->p_vout, i_query, args );
1028         else
1029             return vout_vaControlDefault( p_vout, i_query, args );
1030     }
1031 }
1032
1033 static int InitTextures( vout_thread_t *p_vout )
1034 {
1035     vout_sys_t *p_sys = p_vout->p_sys;
1036     int i_index;
1037
1038     glDeleteTextures( 2, p_sys->p_textures );
1039     glGenTextures( 2, p_sys->p_textures );
1040
1041     for( i_index = 0; i_index < 2; i_index++ )
1042     {
1043         glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_index] );
1044
1045         /* Set the texture parameters */
1046         glTexParameterf( VLCGL_TARGET, GL_TEXTURE_PRIORITY, 1.0 );
1047
1048         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1049         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1050
1051         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1052         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1053
1054         glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1055
1056 #ifdef __APPLE__
1057         /* Tell the driver not to make a copy of the texture but to use
1058            our buffer */
1059         glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
1060         glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );
1061
1062 #if 0
1063         /* Use VRAM texturing */
1064         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
1065                          GL_STORAGE_CACHED_APPLE );
1066 #else
1067         /* Use AGP texturing */
1068         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
1069                          GL_STORAGE_SHARED_APPLE );
1070 #endif
1071 #endif
1072
1073         /* Call glTexImage2D only once, and use glTexSubImage2D later */
1074         glTexImage2D( VLCGL_TARGET, 0, 3, p_sys->i_tex_width,
1075                       p_sys->i_tex_height, 0, VLCGL_FORMAT, VLCGL_TYPE,
1076                       p_sys->pp_buffer[i_index] );
1077     }
1078
1079     return 0;
1080 }
1081
1082 /*****************************************************************************
1083  * SendEvents: forward mouse and keyboard events to the parent p_vout
1084  *****************************************************************************/
1085 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
1086                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
1087 {
1088     return var_Set( (vlc_object_t *)_p_vout, psz_var, newval );
1089 }