
// sg - A scene graph representation.

// Copyright (C) 2005-2006 Editopia Inc.
// Released under the LGPL.
// For more information, see http://www.openlibraries.org.

// simple example to exercise texturing in the draw action.

#include <GL/glew.h>

#ifdef HAVE_CONFIG_H
#include <openlibraries_global_config.hpp>
#endif

#include <openpluginlib/pl/openpluginlib.hpp>
#include <openpluginlib/pl/utf8_utils.hpp>

#include <openobjectlib/sg/sg.hpp>
#include <openobjectlib/sg/openobjectlib_plugin.hpp>
#include <openobjectlib/sg/hw_GL_renderer.hpp>

#if defined ( WIN32 ) || defined ( HAVE_GL_GLUT_H )
#include <GL/glut.h>
#else
#include <GLUT/glut.h>
#endif

using namespace std;

namespace opl = olib::openpluginlib;
namespace ool = olib::openobjectlib;
namespace fs  = boost::filesystem;
namespace sg  = olib::openobjectlib::sg;

const int WIN_WIDTH		= 400;
const int WIN_HEIGHT	= 350;

namespace
{
	sg::scene_ptr		scene;
	sg::hw_GL_renderer	r;

	struct query_traits
	{
		query_traits( const opl::wstring& filename )
			: filename_( filename )
		{ }
		
		opl::wstring libname( ) const
		{ return L"openobjectlib"; }
		
		opl::wstring to_match( ) const
		{ return filename_; }

		opl::wstring type( ) const
		{ return L""; }
		
		int merit( ) const
		{ return 0; }
		
		opl::wstring filename_;
	};
}

static sg::scene_ptr load_scene( const fs::path& path )
{
	typedef opl::discovery<query_traits> ool_discovery;
	
	ool_discovery plugins( query_traits( opl::to_wstring( path.native_file_string( ).c_str( ) ) ) );
	if( plugins.empty( ) )	
		return sg::scene_ptr( );
	
	ool_discovery::const_iterator i = plugins.begin( );
	boost::shared_ptr<sg::openobjectlib_plugin> plug = boost::shared_dynamic_cast<sg::openobjectlib_plugin>( i->create_plugin( "" ) );
	if( !plug )
		return sg::scene_ptr( );
	
	return plug->load( path );
}

static void display( void )
{
	glDisable( GL_DEPTH_TEST );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	glEnable( GL_DEPTH_TEST );

	r.render( scene->get_root( ) );

#ifndef NDEBUG
	GLenum error;
	while( ( error = glGetError( ) ) != GL_NO_ERROR )
		fprintf( stderr, "GLerror:%s\n", gluErrorString( error ) );
#endif // NDEBUG

	glutSwapBuffers( );
}

static void idle( void )
{
	glutPostRedisplay( );
}

static void reshape( int w, int h )
{
	glViewport( 0, 0, w, h );
	
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	
	float aspect_ratio;
	aspect_ratio = static_cast<float>( w ) / h;
	
	gluPerspective( 45.0f, aspect_ratio, 1.0f, 1000.0f );

	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity( );
	gluLookAt( -113.21155f, 146.54301f, -75.553253f, 0.0f, 0.0f, 0.0f, 0.59809780f, 0.68039572f, 0.42348647f );
}

static void keyboard( unsigned char k, int x, int y )
{
	switch( k )
	{
		case 27:
			exit( 0 );
			
		default:
			break;
	}
}

int main( int argc, char* argv[ ] )
{
	glutInit( &argc, argv );
	glutInitWindowSize( WIN_WIDTH, WIN_HEIGHT );
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA );
	glutCreateWindow( "OpenGL Texturing (Programmable Pipeline) Draw" );
	glutDisplayFunc( display );
	glutIdleFunc( idle );
	glutReshapeFunc( reshape );
	glutKeyboardFunc( keyboard );
	
	glewInit( );

	opl::init( "" );
	ool::init( );

	scene = load_scene( "../../../../media/models/disco_lighting.x3d" );

	glEnable( GL_CULL_FACE );
	
	glutMainLoop( );
}
