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