/////////////////////////////////////////////////////////////////////////////// // glcube.cpp : OpenGL cube video output plugin for vlc /////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2002 VideoLAN // $Id: dummy.c,v 1.17 2002/03/01 00:33:18 massiot Exp $ // // Authors: Samuel Hocevar // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Preamble /////////////////////////////////////////////////////////////////////////////// #include // malloc(), free() #include #include #include #include #include #define GL_GLEXT_LEGACY #include #include "video.h" #include "video_output.h" #define WIDTH 256 #define HEIGHT 256 #define BPP8 //#define BPP16 //#define BPP32 /////////////////////////////////////////////////////////////////////////////// // vout_sys_t: video output method descriptor /////////////////////////////////////////////////////////////////////////////// // This structure is part of the video output thread descriptor. // It describes the specific properties of an output thread. /////////////////////////////////////////////////////////////////////////////// typedef class vout_sys { public: static void getfunctions( function_list_t * ); static int Create ( vout_thread_t * ); static int Init ( vout_thread_t * ); static void End ( vout_thread_t * ); static void Destroy ( vout_thread_t * ); static int Manage ( vout_thread_t * ); static void Render ( vout_thread_t *, picture_t * ); static void Display ( vout_thread_t *, picture_t * ); static void SetPalette( vout_thread_t *, u16 *, u16 *, u16 * ); private: vout_sys ( vout_thread_t * ); ~vout_sys (); vout_thread_t *p_vout; u8 *p_texture; float angle[3]; //int i_window; //bool b_die; void RunThread ( void ); static void Idle ( void ); static void DisplayBuffer ( void ); static void Reshape ( int, int ); static void HandleKey ( unsigned char, int, int ); } vout_sys_t; extern "C" { /////////////////////////////////////////////////////////////////////////////// // Build configuration tree. /////////////////////////////////////////////////////////////////////////////// MODULE_CONFIG_START MODULE_CONFIG_STOP MODULE_INIT_START SET_DESCRIPTION( "OpenGL cube module" ) ADD_CAPABILITY( VOUT, 1 ) ADD_SHORTCUT( "glcube" ) MODULE_INIT_STOP MODULE_ACTIVATE_START vout_sys::getfunctions( &p_module->p_functions->vout ); MODULE_ACTIVATE_STOP MODULE_DEACTIVATE_START MODULE_DEACTIVATE_STOP } // extern "C" /////////////////////////////////////////////////////////////////////////////// // Functions exported as capabilities. They are declared as static so that // we don't pollute the namespace too much. /////////////////////////////////////////////////////////////////////////////// void vout_sys::getfunctions( function_list_t * p_function_list ) { p_function_list->functions.vout.pf_create = vout_sys::Create; p_function_list->functions.vout.pf_init = vout_sys::Init; p_function_list->functions.vout.pf_end = vout_sys::End; p_function_list->functions.vout.pf_destroy = vout_sys::Destroy; p_function_list->functions.vout.pf_manage = vout_sys::Manage; p_function_list->functions.vout.pf_render = vout_sys::Render; p_function_list->functions.vout.pf_display = vout_sys::Display; } vlc_mutex_t gros_lock_bien_degueulasse_qui_pue; // Constructor vout_sys::vout_sys( vout_thread_t *p_vout ) { vlc_mutex_init( &gros_lock_bien_degueulasse_qui_pue ); this->p_vout = p_vout; } // Destructor vout_sys::~vout_sys() { vlc_mutex_destroy( &gros_lock_bien_degueulasse_qui_pue ); } static float Rot[3] = { 0, 0, 0 }; static bool b_die; static int i_window; GLuint texture[1]; float p[ 45 ][ 45 ][3]; int wiggle_count = 0; GLfloat hold; /////////////////////////////////////////////////////////////////////////////// // Create: allocates video thread output method /////////////////////////////////////////////////////////////////////////////// // This function allocates and initializes a vout method. /////////////////////////////////////////////////////////////////////////////// int vout_sys::Create( vout_thread_t *p_vout ) { // Allocate structure p_vout->p_sys = (struct vout_sys_s *)new vout_sys( p_vout ); return( 0 ); } /////////////////////////////////////////////////////////////////////////////// // Init: initialize video thread output method /////////////////////////////////////////////////////////////////////////////// int vout_sys::Init( vout_thread_t *p_vout ) { int i_index; picture_t *p_pic; I_OUTPUTPICTURES = 0; #if defined( BPP8 ) p_vout->output.i_chroma = FOURCC_RGB2; p_vout->output.pf_setpalette = SetPalette; #elif defined( BPP16 ) p_vout->output.i_chroma = FOURCC_RV16; p_vout->output.i_rmask = 0xf800; p_vout->output.i_gmask = 0x07e0; p_vout->output.i_bmask = 0x001f; #elif defined( BPP32 ) p_vout->output.i_chroma = FOURCC_RV24; p_vout->output.i_rmask = 0xff000000; p_vout->output.i_gmask = 0x00ff0000; p_vout->output.i_bmask = 0x0000ff00; #endif p_vout->output.i_width = WIDTH; p_vout->output.i_height = HEIGHT; p_vout->output.i_aspect = VOUT_ASPECT_FACTOR; p_pic = NULL; // Find an empty picture slot for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ ) { if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE ) { p_pic = p_vout->p_picture + i_index; break; } } // Allocate the picture if( p_pic == NULL ) { return -1; } #if defined( BPP8 ) // Allocate the memory buffer p_pic->p_data = (u8 *)malloc( WIDTH * WIDTH * sizeof( u8 ) ); memset( p_pic->p_data, 0x00, WIDTH * WIDTH * sizeof( u8 ) ); // Fill important structures p_pic->p->p_pixels = p_pic->p_data; p_pic->p->i_lines = WIDTH; p_pic->p->i_pitch = HEIGHT; p_pic->p->i_pixel_bytes = 1; p_pic->p->b_margin = 0; #elif defined( BPP16 ) // Allocate the memory buffer p_pic->p_data = (u8 *)malloc( WIDTH * WIDTH * sizeof( u16 ) ); memset( p_pic->p_data, 0x00, WIDTH * WIDTH * sizeof( u16 ) ); // Fill important structures p_pic->p->p_pixels = p_pic->p_data; p_pic->p->i_lines = WIDTH; p_pic->p->i_pitch = HEIGHT * 2; p_pic->p->i_pixel_bytes = 2; p_pic->p->b_margin = 0; #elif defined( BPP32 ) // Allocate the memory buffer p_pic->p_data = (u8 *)malloc( WIDTH * WIDTH * sizeof( u32 ) ); memset( p_pic->p_data, 0x00, WIDTH * WIDTH * sizeof( u32 ) ); // Fill important structures p_pic->p->p_pixels = p_pic->p_data; p_pic->p->i_lines = WIDTH; p_pic->p->i_pitch = HEIGHT * 4; p_pic->p->i_pixel_bytes = 4; p_pic->p->b_margin = 0; #endif // We allocated 1 plane p_pic->i_planes = 1; p_pic->i_status = DESTROYED_PICTURE; p_pic->i_type = DIRECT_PICTURE; PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic; I_OUTPUTPICTURES++; ((vout_sys *)p_vout->p_sys)->p_texture = p_pic->p_data; vlc_mutex_lock(&gros_lock_bien_degueulasse_qui_pue); ((vout_sys *)p_vout->p_sys)->RunThread(); return 0; } void vout_sys::RunThread () { vlc_thread_t thread_id; int argc = 1; char *arg = "foo"; char **argv = &arg; glutInit( &argc, argv ); //glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); //glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH); // Create our window glutInitWindowPosition( 0, 0 ); glutInitWindowSize( 200, 200 ); i_window = glutCreateWindow( VOUT_TITLE " (OpenGL cube output)" ); // Allocate 1 texture glGenTextures(1, &texture[0]); // The first texture glBindTexture(GL_TEXTURE_2D, texture[0]); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); #if defined( BPP8 ) glTexImage2D( GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, WIDTH, HEIGHT, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, p_texture ); #elif defined( BPP16 ) glTexImage2D( GL_TEXTURE_2D, 0, 3, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, p_texture ); #elif defined( BPP32 ) glTexImage2D( GL_TEXTURE_2D, 0, 3, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, p_texture ); #endif // Enable texture mapping glEnable( GL_TEXTURE_2D ); glShadeModel(GL_SMOOTH); // Clear background glClearColor(0.2f, 0.1f, 0.4f, 0.0f); glClearDepth(1.0); // Misc stuff glEnable(GL_DEPTH_TEST); //glDepthFunc(GL_LESS); glDepthFunc(GL_LEQUAL); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glPolygonMode(GL_FRONT, GL_FILL); glPolygonMode(GL_BACK, GL_LINE); for(int x=0; x<45; x++) { for(int y=0; y<45; y++) { // Apply The Wave To Our Mesh p[x][y][0]=float((x/8.0f)-2.8f); p[x][y][1]=-float((y/8.0f)-2.8f); p[x][y][2]=-float(sin((((x/5.0f)*40.0f)/360.0f)*3.141592654*2.0f)); } } glFlush(); glutReshapeFunc( this->Reshape ); glutKeyboardFunc( HandleKey ); glutDisplayFunc( DisplayBuffer ); glutIdleFunc( Idle ); //((vout_sys *)p_vout->p_sys)->b_die = 0; b_die = 0; vlc_thread_create( &thread_id, "glcube", (vlc_thread_func_t)glutMainLoop, NULL ); } /////////////////////////////////////////////////////////////////////////////// // End: terminate video thread output method /////////////////////////////////////////////////////////////////////////////// void vout_sys::End( vout_thread_t *p_vout ) { int i_index; //((vout_sys *)p_vout->p_sys)->b_die = 1; b_die = 1; return; // Free the fake output buffers we allocated for( i_index = I_OUTPUTPICTURES ; i_index ; ) { i_index--; free( PP_OUTPUTPICTURE[ i_index ]->p_data ); } } /////////////////////////////////////////////////////////////////////////////// // Destroy: destroy video thread output method /////////////////////////////////////////////////////////////////////////////// void vout_sys::Destroy( vout_thread_t *p_vout ) { delete (vout_sys*)p_vout->p_sys; } /////////////////////////////////////////////////////////////////////////////// // Manage: handle events /////////////////////////////////////////////////////////////////////////////// // This function should be called regularly by video output thread. It manages // console events. It returns a non null value on error. /////////////////////////////////////////////////////////////////////////////// int vout_sys::Manage( vout_thread_t *p_vout ) { return( 0 ); } /////////////////////////////////////////////////////////////////////////////// // Render: render previously calculated output /////////////////////////////////////////////////////////////////////////////// void vout_sys::Render( vout_thread_t *p_vout, picture_t *p_pic ) { vlc_mutex_lock(&gros_lock_bien_degueulasse_qui_pue); glBindTexture(GL_TEXTURE_2D, texture[0]); glTexImage2D( GL_TEXTURE_2D, 0, GL_COLOR_INDEX8_EXT, WIDTH, HEIGHT, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, p_pic->p->p_pixels ); vlc_mutex_unlock(&gros_lock_bien_degueulasse_qui_pue); } /////////////////////////////////////////////////////////////////////////////// // Display: displays previously rendered output /////////////////////////////////////////////////////////////////////////////// void vout_sys::Display( vout_thread_t *p_vout, picture_t *p_pic ) { ; } /////////////////////////////////////////////////////////////////////////////// // Idle: the GLUT idle loop /////////////////////////////////////////////////////////////////////////////// void vout_sys::Idle( void ) { vlc_mutex_unlock(&gros_lock_bien_degueulasse_qui_pue); if( b_die ) { // We were asked to die ... so, die ! glutDestroyWindow(i_window); msleep( 1000000 ); // BEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEUUUUUUHAR exit(0); } vlc_mutex_lock(&gros_lock_bien_degueulasse_qui_pue); glutPostRedisplay(); } /////////////////////////////////////////////////////////////////////////////// // Display: the GLUT display routine /////////////////////////////////////////////////////////////////////////////// void vout_sys::DisplayBuffer( void ) { int x, y; float fx, fy, fxb, fyb; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0f,0.0f,-12.0f); glRotatef(Rot[0], 0, 0, 1); glRotatef(Rot[1], 0, 1, 0); glRotatef(Rot[2], 1, 0, 0); glBindTexture(GL_TEXTURE_2D, texture[0]); glBegin(GL_QUADS); #if 0 glTexCoord2f(1, 0); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0, 0); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0, 1); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(1, 1); glVertex3f( 1.0f,-1.0f, 1.0f); #endif for( x = 0; x < 44; x++ ) { for( y = 0; y < 44; y++ ) { fx = float(x)/44.0f; fy = float(y)/44.0f; fxb = float(x+1)/44.0f; fyb = float(y+1)/44.0f; glTexCoord2f( fx, fy); glVertex3f( p[x][y][0], p[x][y][1], p[x][y][2] ); glTexCoord2f( fx, fyb ); glVertex3f( p[x][y+1][0], p[x][y+1][1], p[x][y+1][2] ); glTexCoord2f( fxb, fyb ); glVertex3f( p[x+1][y+1][0], p[x+1][y+1][1], p[x+1][y+1][2] ); glTexCoord2f( fxb, fy ); glVertex3f( p[x+1][y][0], p[x+1][y][1], p[x+1][y][2] ); } } glEnd(); for( y = 0; y < 45; y++ ) { hold=p[0][y][2]; for( x = 0; x < 44; x++) { p[x][y][2] = p[x+1][y][2]; } p[44][y][2]=hold; } #if 0 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glLoadIdentity(); glTranslatef(0.0f,0.0f,-10.0f); glRotatef(Rot[0], 0, 0, 1); glRotatef(Rot[1], 0, 1, 0); glRotatef(Rot[2], 1, 0, 0); glBegin(GL_QUADS); //glColor3f(1.0f,0.0f,1.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); //glColor3f(1.0f,0.5f,0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //glColor3f(1.0f,0.5f,0.0f); glVertex3f( 1.0f,-1.0f, 1.0f); glVertex3f(-1.0f,-1.0f, 1.0f); //glColor3f(1.0f,1.0f,0.0f); glVertex3f(-1.0f,-1.0f,-1.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glEnd(); glBegin(GL_QUADS); glBindTexture(GL_TEXTURE_2D, texture[0]); glTexCoord2f(1, 0); glVertex3f( 1.0f, 1.0f, 1.0f); glTexCoord2f(0, 0); glVertex3f(-1.0f, 1.0f, 1.0f); glTexCoord2f(0, 1); glVertex3f(-1.0f,-1.0f, 1.0f); glTexCoord2f(1, 1); glVertex3f( 1.0f,-1.0f, 1.0f); glEnd(); glBegin(GL_QUADS); //glColor3f(1.0f,1.0f,0.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glVertex3f(-1.0f,-1.0f,-1.0f); //glColor3f(1.0f,0.0f,0.0f); glVertex3f(-1.0f, 1.0f,-1.0f); glVertex3f( 1.0f, 1.0f,-1.0f); //glColor3f(0.0f,0.0f,1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); glVertex3f(-1.0f, 1.0f,-1.0f); //glColor3f(1.0f,0.5f,0.0f); glVertex3f(-1.0f,-1.0f,-1.0f); glVertex3f(-1.0f,-1.0f, 1.0f); //glColor3f(1.0f,0.0f,1.0f); glVertex3f( 1.0f, 1.0f,-1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //glColor3f(0.0f,0.0f,1.0f); glVertex3f( 1.0f,-1.0f, 1.0f); glVertex3f( 1.0f,-1.0f,-1.0f); glEnd(); #if 0 glBegin(GL_POLYGON); glTexCoord2f(0, 1); glVertex2f(-1, -.75); glTexCoord2f(1, 1); glVertex2f( 1, -.75); glTexCoord2f(1, 0); glVertex2f( 1, .75); glTexCoord2f(0, 0); glVertex2f(-1, .75); glEnd(); #endif #if 0 glTranslatef(1.5f,0.0f,-7.0f); glColor3f(0.0f,1.0f,0.0f); glBegin(GL_POLYGON); glTexCoord2f(0, 1); glVertex2f(-1, -.75); glTexCoord2f(1, 1); glVertex2f( 1, -.75); glTexCoord2f(1, 0); glVertex2f( 1, .75); glTexCoord2f(0, 0); glVertex2f(-1, .75); glEnd(); #endif #endif glutSwapBuffers(); } /////////////////////////////////////////////////////////////////////////////// // Reshape: the GLUT routine for resizing events /////////////////////////////////////////////////////////////////////////////// void vout_sys::Reshape( int width, int height ) { glViewport( 0, 0, width, height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); glTranslatef( 0.0, 0.0, -7.0 ); } /////////////////////////////////////////////////////////////////////////////// // HandleKey: handle GLUT keypresses /////////////////////////////////////////////////////////////////////////////// void vout_sys::HandleKey( unsigned char key, int x, int y ) { switch (key) { case 'a': Rot[0] += 5.0; break; case 'z': Rot[0] -= 5.0; break; case 'q': Rot[1] += 5.0; break; case 's': Rot[1] -= 5.0; break; case 'w': Rot[2] -= 5.0; break; case 'x': Rot[2] += 5.0; break; case 27: printf("eh oh, not quitting like a dégueulasse !!\n"); b_die = 1; break; } glutPostRedisplay(); } /////////////////////////////////////////////////////////////////////////////// // SetPalette: set the 8bpp palette /////////////////////////////////////////////////////////////////////////////// void vout_sys::SetPalette( vout_thread_t *p_vout, u16 *red, u16 *green, u16 *blue ) { GLubyte table[256][4]; int i; vlc_mutex_lock(&gros_lock_bien_degueulasse_qui_pue); if (!glutExtensionSupported("GL_EXT_paletted_texture")) { printf("Sorry, GL_EXT_paletted_texture not supported\n"); vlc_mutex_unlock(&gros_lock_bien_degueulasse_qui_pue); return; } // Fill colors with color information for( i = 0; i < 256; i++ ) { table[i][0] = red[i] >> 8; table[i][1] = green[i] >> 8; table[i][2] = blue[i] >> 8; table[i][3] = 0; } #ifdef GL_EXT_paletted_texture #if defined(GL_EXT_shared_texture_palette) && defined(USE_SHARED_PALETTE) glColorTableEXT( GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table ); glEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); #else glColorTableEXT( GL_TEXTURE_2D, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table ); #endif #endif vlc_mutex_unlock(&gros_lock_bien_degueulasse_qui_pue); }