71cdfed744d1392e099b6d20133e01efe991490a
[vlc.git] / 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    ( float, 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, VLC_TRUE );
196 #ifdef OPENGL_MORE_EFFECT
197     add_integer_with_range( "opengl-accuracy", 4, 1, 10, NULL, ACCURACY_TEXT,
198                     ACCURACY_LONGTEXT, VLC_TRUE );
199     add_float_with_range( "opengl-pov-x", 0.0, -1.0, 1.0, NULL, POV_X_TEXT,
200                     POV_X_LONGTEXT, VLC_TRUE );
201     add_float_with_range( "opengl-pov-y", 0.0, -1.0, 1.0, NULL, POV_Y_TEXT,
202                     POV_Y_LONGTEXT, VLC_TRUE );
203     add_float_with_range( "opengl-pov-z", -1.0, -1.0, 1.0, NULL, POV_Z_TEXT,
204                     POV_Z_LONGTEXT, VLC_TRUE );
205     add_float( "opengl-cylinder-radius", -100.0, NULL, RADIUS_TEXT,
206                     RADIUS_LONGTEXT, VLC_TRUE );
207
208 #endif
209     /* Allow opengl provider plugin selection */
210     add_string( "opengl-provider", "default", NULL, PROVIDER_TEXT, 
211                     PROVIDER_LONGTEXT, VLC_TRUE );
212     set_callbacks( CreateVout, DestroyVout );
213     add_string( "opengl-effect", "none", NULL, EFFECT_TEXT,
214                  EFFECT_LONGTEXT, VLC_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_destroy( 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     if( val.psz_string ) 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     if( p_sys->pp_buffer[0] ) free( p_sys->pp_buffer[0] );
557     if( p_sys->pp_buffer[1] ) 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_destroy( 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     vout_sys_t *p_sys = p_vout->p_sys;
703
704     /* On Win32/GLX, we do this the usual way:
705        + Fill the buffer with new content,
706        + Reload the texture,
707        + Use the texture.
708
709        On OS X with VRAM or AGP texturing, the order has to be:
710        + Reload the texture,
711        + Fill the buffer with new content,
712        + Use the texture.
713
714        (Thanks to gcc from the Arstechnica forums for the tip)
715
716        Therefore, we have to use two buffers and textures. On Win32/GLX,
717        we reload the texture to be displayed and use it right away. On
718        OS X, we first render, then reload the texture to be used next
719        time. */
720
721     if( p_sys->p_vout->pf_lock &&
722         p_sys->p_vout->pf_lock( p_sys->p_vout ) )
723     {
724         msg_Warn( p_vout, "could not lock OpenGL provider" );
725         return;
726     }
727
728 #ifdef __APPLE__
729     int i_new_index;
730     i_new_index = ( p_sys->i_index + 1 ) & 1;
731
732
733     /* Update the texture */
734     glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_new_index] );
735     glTexSubImage2D( VLCGL_TARGET, 0, 0, 0,
736                      p_vout->fmt_out.i_width,
737                      p_vout->fmt_out.i_height,
738                      VLCGL_FORMAT, VLCGL_TYPE, p_sys->pp_buffer[i_new_index] );
739
740     /* Bind to the previous texture for drawing */
741     glBindTexture( VLCGL_TARGET, p_sys->p_textures[p_sys->i_index] );
742
743     /* Switch buffers */
744     p_sys->i_index = i_new_index;
745     p_pic->p->p_pixels = p_sys->pp_buffer[p_sys->i_index];
746
747 #else
748     /* Update the texture */
749     glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0,
750                      p_vout->fmt_out.i_width,
751                      p_vout->fmt_out.i_height,
752                      VLCGL_FORMAT, VLCGL_TYPE, p_sys->pp_buffer[0] );
753 #endif
754
755     if( p_sys->p_vout->pf_unlock )
756     {
757         p_sys->p_vout->pf_unlock( p_sys->p_vout );
758     }
759 }
760
761
762 #ifdef OPENGL_MORE_EFFECT
763 /*****************************************************************************
764  *   Transform: Calculate the distorted grid coordinates
765  *****************************************************************************/
766 static 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)
767 {
768     double x,y,xnew,ynew;
769     double r,theta,rnew,thetanew;
770
771     x = (double)i * (width / ((double)i_visible_width));
772     y = (double)j * (height / ((double)i_visible_height));
773
774     x = (2.0 * (double)x / width) - 1;
775     y = (2.0 * (double)y / height) - 1;
776     xnew = x;
777     ynew = y;
778     r = sqrt(x*x+y*y);
779     theta = atan2(y,x);
780
781     switch (distortion)
782     {
783 /* GRID2D TRANSFORMATION */
784         case SINEXY:
785             xnew = sin(PID2*x);
786             ynew = sin(PID2*y);
787             break;
788         case SINER:
789             rnew = sin(PID2*r);
790             thetanew = theta;
791             xnew = rnew * cos(thetanew);
792             ynew = rnew * sin(thetanew);
793             break;
794         case SQUAREXY:
795             xnew = x*x*SIGN(x);
796             ynew = y*y*SIGN(y);
797             break;
798         case SQUARER:
799             rnew = r*r;
800             thetanew = theta;
801             xnew = rnew * cos(thetanew);
802             ynew = rnew * sin(thetanew);
803             break;
804         case ASINXY:
805             xnew = asin(x) / PID2;
806             ynew = asin(y) / PID2;
807             break;
808         case ASINR:
809             rnew = asin(r) / PID2;
810             thetanew = theta;
811             xnew = rnew * cos(thetanew);
812             ynew = rnew * sin(thetanew);
813             break;
814 /* OTHER WAY: 3D MODEL */
815         default:
816             xnew = x;
817             ynew = y;
818     }
819
820     *ix = width * (xnew + 1) / (2.0);
821     *iy = height * (ynew + 1) / (2.0);
822 }
823
824 /*****************************************************************************
825  *   Z_Compute: Calculate the Z-coordinate
826  *****************************************************************************/
827 static float Z_Compute(float p, int distortion, float x, float y)
828 {
829     float f_z = 0.0;
830     double d_p = p / 100.0;
831
832     switch (distortion)
833     {
834 /* 3D MODEL */
835         case CYLINDER:
836             if (d_p > 0)
837                 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));
838             else
839                 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));
840             break;
841         case TORUS:
842             if (d_p > 0)
843                 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));
844             else
845                 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));
846             break;
847         case SPHERE:
848             if (d_p > 0)
849                 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));
850             else
851                 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));
852             break;
853 /* OTHER WAY: GRID2D TRANSFORMATION */
854         case SINEXY:;
855         case SINER:
856         case SQUAREXY:
857         case SQUARER:;
858         case ASINXY:
859         case ASINR:
860             f_z = 0.0;
861             break;
862         default:
863             f_z = 0.0;
864     }
865     return f_z;
866 }
867 #endif
868
869
870 /*****************************************************************************
871  * DisplayVideo: displays previously rendered output
872  *****************************************************************************/
873 static void DisplayVideo( vout_thread_t *p_vout, picture_t *p_pic )
874 {
875     vout_sys_t *p_sys = p_vout->p_sys;
876     float f_width, f_height, f_x, f_y;
877
878     if( p_sys->p_vout->pf_lock &&
879         p_sys->p_vout->pf_lock( p_sys->p_vout ) )
880     {
881         msg_Warn( p_vout, "could not lock OpenGL provider" );
882         return;
883     }
884
885     /* glTexCoord works differently with GL_TEXTURE_2D and
886        GL_TEXTURE_RECTANGLE_EXT */
887 #ifdef __APPLE__
888     f_x = (float)p_vout->fmt_out.i_x_offset;
889     f_y = (float)p_vout->fmt_out.i_y_offset;
890     f_width = (float)p_vout->fmt_out.i_x_offset +
891               (float)p_vout->fmt_out.i_visible_width;
892     f_height = (float)p_vout->fmt_out.i_y_offset +
893                (float)p_vout->fmt_out.i_visible_height;
894 #else
895     f_x = (float)p_vout->fmt_out.i_x_offset / p_sys->i_tex_width;
896     f_y = (float)p_vout->fmt_out.i_y_offset / p_sys->i_tex_height;
897     f_width = ( (float)p_vout->fmt_out.i_x_offset +
898                 p_vout->fmt_out.i_visible_width ) / p_sys->i_tex_width;
899     f_height = ( (float)p_vout->fmt_out.i_y_offset +
900                  p_vout->fmt_out.i_visible_height ) / p_sys->i_tex_height;
901 #endif
902
903     /* Why drawing here and not in Render()? Because this way, the
904        OpenGL providers can call pf_display to force redraw. Currently,
905        the OS X provider uses it to get a smooth window resizing */
906
907     glClear( GL_COLOR_BUFFER_BIT );
908
909     if( p_sys->i_effect == OPENGL_EFFECT_NONE )
910     {
911         glEnable( VLCGL_TARGET );
912         glBegin( GL_POLYGON );
913         glTexCoord2f( f_x, f_y ); glVertex2f( -1.0, 1.0 );
914         glTexCoord2f( f_width, f_y ); glVertex2f( 1.0, 1.0 );
915         glTexCoord2f( f_width, f_height ); glVertex2f( 1.0, -1.0 );
916         glTexCoord2f( f_x, f_height ); glVertex2f( -1.0, -1.0 );
917         glEnd();
918     }
919     else
920 #ifdef OPENGL_MORE_EFFECT
921     if ((p_sys->i_effect > OPENGL_EFFECT_TRANSPARENT_CUBE) ||
922         ((p_sys->i_effect == OPENGL_EFFECT_NONE)))
923     {
924        unsigned int i_i, i_j;
925        unsigned int i_accuracy  = config_GetInt( p_vout, "opengl-accuracy");
926        unsigned int i_n = pow(2, i_accuracy);
927        unsigned int i_n_x = (p_vout->fmt_out.i_visible_width / (i_n * 2));
928        unsigned int i_n_y = (p_vout->fmt_out.i_visible_height / i_n);
929        double d_x, d_y;
930        int i_distortion = p_sys->i_effect;
931        float f_p = p_sys->f_radius;
932  
933        glEnable( VLCGL_TARGET );
934        glBegin(GL_QUADS);
935        for (i_i = 0; i_i < p_vout->fmt_out.i_visible_width; i_i += i_n_x)
936        {
937           if ( i_i == i_n_x * i_n / 2) i_n_x += p_vout->fmt_out.i_visible_width % i_n;
938           if ((i_i == (p_vout->fmt_out.i_visible_width / i_n) * i_n / 2 + i_n_x) &&
939               (p_vout->fmt_out.i_visible_width / i_n != i_n_x))
940                 i_n_x -= p_vout->fmt_out.i_visible_width % i_n;
941
942           int i_m;
943           int i_index_max = 0;
944  
945           for (i_j = 0; i_j < p_vout->fmt_out.i_visible_height; i_j += i_n_y)
946           {
947             if ( i_j == i_n_y * i_n / 2) i_n_y += p_vout->fmt_out.i_visible_height % i_n;
948             if ((i_j == (p_vout->fmt_out.i_visible_height / i_n) * i_n / 2 + i_n_y) &&
949                 (p_vout->fmt_out.i_visible_height / i_n != i_n_y))
950                     i_n_y -= p_vout->fmt_out.i_visible_height % i_n;
951
952             for (i_m = i_index_max; i_m < i_index_max + 4; i_m++)
953             {
954                 int i_k = ((i_m % 4) == 1) || ((i_m % 4) == 2);
955                 int i_l = ((i_m % 4) == 2) || ((i_m % 4) == 3);
956
957                 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);
958                 glTexCoord2f(f_x + d_x, f_y + d_y);
959                 d_x =  - 1.0 + 2.0 * ((double)(i_k * i_n_x + i_i) / (double)p_vout->fmt_out.i_visible_width);
960                 d_y =    1.0 - 2.0 * (((double)i_l * i_n_y + i_j) / (double)p_vout->fmt_out.i_visible_height);
961                 glVertex3f((float)d_x, (float)d_y, Z_Compute(f_p, i_distortion, (float)d_x, (float)d_y));
962             }
963           }
964        }
965        glEnd();
966     }
967     else
968 #endif
969     {
970         glRotatef( 0.5 * p_sys->f_speed , 0.3, 0.5, 0.7 );
971
972         glEnable( VLCGL_TARGET );
973         glBegin( GL_QUADS );
974
975         /* Front */
976         glTexCoord2f( f_x, f_y ); glVertex3f( - 1.0, 1.0, 1.0 );
977         glTexCoord2f( f_x, f_height ); glVertex3f( - 1.0, - 1.0, 1.0 );
978         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, 1.0 );
979         glTexCoord2f( f_width, f_y ); glVertex3f( 1.0, 1.0, 1.0 );
980
981         /* Left */
982         glTexCoord2f( f_x, f_y ); glVertex3f( - 1.0, 1.0, - 1.0 );
983         glTexCoord2f( f_x, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
984         glTexCoord2f( f_width, f_height ); glVertex3f( - 1.0, - 1.0, 1.0 );
985         glTexCoord2f( f_width, f_y ); glVertex3f( - 1.0, 1.0, 1.0 );
986
987         /* Back */
988         glTexCoord2f( f_x, f_y ); glVertex3f( 1.0, 1.0, - 1.0 );
989         glTexCoord2f( f_x, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
990         glTexCoord2f( f_width, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
991         glTexCoord2f( f_width, f_y ); glVertex3f( - 1.0, 1.0, - 1.0 );
992
993         /* Right */
994         glTexCoord2f( f_x, f_y ); glVertex3f( 1.0, 1.0, 1.0 );
995         glTexCoord2f( f_x, f_height ); glVertex3f( 1.0, - 1.0, 1.0 );
996         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
997         glTexCoord2f( f_width, f_y ); glVertex3f( 1.0, 1.0, - 1.0 );
998
999         /* Top */
1000         glTexCoord2f( f_x, f_y ); glVertex3f( - 1.0, 1.0, - 1.0 );
1001         glTexCoord2f( f_x, f_height ); glVertex3f( - 1.0, 1.0, 1.0 );
1002         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, 1.0, 1.0 );
1003         glTexCoord2f( f_width, f_y ); glVertex3f( 1.0, 1.0, - 1.0 );
1004
1005         /* Bottom */
1006         glTexCoord2f( f_x, f_y ); glVertex3f( - 1.0, - 1.0, 1.0 );
1007         glTexCoord2f( f_x, f_height ); glVertex3f( - 1.0, - 1.0, - 1.0 );
1008         glTexCoord2f( f_width, f_height ); glVertex3f( 1.0, - 1.0, - 1.0 );
1009         glTexCoord2f( f_width, f_y ); glVertex3f( 1.0, - 1.0, 1.0 );
1010         glEnd();
1011     }
1012
1013     glDisable( VLCGL_TARGET );
1014
1015     p_sys->p_vout->pf_swap( p_sys->p_vout );
1016
1017     if( p_sys->p_vout->pf_unlock )
1018     {
1019         p_sys->p_vout->pf_unlock( p_sys->p_vout );
1020     }
1021 }
1022
1023 int GetAlignedSize( int i_size )
1024 {
1025     /* Return the nearest power of 2 */
1026     int i_result = 1;
1027     while( i_result < i_size )
1028     {
1029         i_result *= 2;
1030     }
1031     return i_result;
1032 }
1033
1034 /*****************************************************************************
1035  * Control: control facility for the vout
1036  *****************************************************************************/
1037 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
1038 {
1039     vout_sys_t *p_sys = p_vout->p_sys;
1040
1041     switch( i_query )
1042     {
1043     case VOUT_SNAPSHOT:
1044         return vout_vaControlDefault( p_vout, i_query, args );
1045
1046     default:
1047         if( p_sys->p_vout->pf_control )
1048             return p_sys->p_vout->pf_control( p_sys->p_vout, i_query, args );
1049         else
1050             return vout_vaControlDefault( p_vout, i_query, args );
1051     }
1052 }
1053
1054 static int InitTextures( vout_thread_t *p_vout )
1055 {
1056     vout_sys_t *p_sys = p_vout->p_sys;
1057     int i_index;
1058
1059     glDeleteTextures( 2, p_sys->p_textures );
1060     glGenTextures( 2, p_sys->p_textures );
1061
1062     for( i_index = 0; i_index < 2; i_index++ )
1063     {
1064         glBindTexture( VLCGL_TARGET, p_sys->p_textures[i_index] );
1065
1066         /* Set the texture parameters */
1067         glTexParameterf( VLCGL_TARGET, GL_TEXTURE_PRIORITY, 1.0 );
1068
1069         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
1070         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
1071
1072         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
1073         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
1074
1075         glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
1076
1077 #ifdef __APPLE__
1078         /* Tell the driver not to make a copy of the texture but to use
1079            our buffer */
1080         glEnable( GL_UNPACK_CLIENT_STORAGE_APPLE );
1081         glPixelStorei( GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE );
1082
1083 #if 0
1084         /* Use VRAM texturing */
1085         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
1086                          GL_STORAGE_CACHED_APPLE );
1087 #else
1088         /* Use AGP texturing */
1089         glTexParameteri( VLCGL_TARGET, GL_TEXTURE_STORAGE_HINT_APPLE,
1090                          GL_STORAGE_SHARED_APPLE );
1091 #endif
1092 #endif
1093
1094         /* Call glTexImage2D only once, and use glTexSubImage2D later */
1095         glTexImage2D( VLCGL_TARGET, 0, 3, p_sys->i_tex_width,
1096                       p_sys->i_tex_height, 0, VLCGL_FORMAT, VLCGL_TYPE,
1097                       p_sys->pp_buffer[i_index] );
1098     }
1099
1100     return 0;
1101 }
1102
1103 /*****************************************************************************
1104  * SendEvents: forward mouse and keyboard events to the parent p_vout
1105  *****************************************************************************/
1106 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
1107                        vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
1108 {
1109     return var_Set( (vlc_object_t *)_p_vout, psz_var, newval );
1110 }