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