예제 #1
0
HMDStereoRender::HMDStereoRender(irr::IrrlichtDevice *device, HMDDescriptor HMD, f32 worldScale)
  : _worldScale(worldScale),
    _renderTexture(NULL)
{
  _smgr = device->getSceneManager();
  _driver = device->getVideoDriver();
  _timer = device->getTimer();

  // Create perspectiva camera used for rendering
  _pCamera = _smgr->addCameraSceneNode();

  // Init shader parameters
  _distortionCB.scale[0] = 1.0f; _distortionCB.scale[1] = 1.0f;
  _distortionCB.scaleIn[0] = 1.0f; _distortionCB.scaleIn[1] = 1.0f;
  _distortionCB.lensCenter[0] = 0.0f;_distortionCB.lensCenter[1] = 0.0f;
  _distortionCB.hmdWarpParam[0] = 1.0f;_distortionCB.hmdWarpParam[1] = 0.0f;_distortionCB.hmdWarpParam[2] = 0.0f;_distortionCB.hmdWarpParam[3] = 0.0f;
  
  // Plane
  _planeVertices[0] = video::S3DVertex(-1.0f, -1.0f, 1.0f,1,1,0, video::SColor(255,0,255,255), 0.0f, 0.0f);
  _planeVertices[1] = video::S3DVertex(-1.0f,  1.0f, 1.0f,1,1,0, video::SColor(255,0,255,255), 0.0f, 1.0f);
  _planeVertices[2] = video::S3DVertex( 1.0f,  1.0f, 1.0f,1,1,0, video::SColor(255,0,255,255), 1.0f, 1.0f);
  _planeVertices[3] = video::S3DVertex( 1.0f, -1.0f, 1.0f,1,1,0, video::SColor(255,0,255,255), 1.0f, 0.0f);
  _planeIndices[0] = 0; _planeIndices[1] = 1; _planeIndices[2] = 2; _planeIndices[3] = 0; _planeIndices[4] = 2; _planeIndices[5] = 3;

  // Create shader material
  _renderMaterial.Wireframe = false;
  _renderMaterial.Lighting = false;
  _renderMaterial.TextureLayer[0].TextureWrapU = ETC_CLAMP;
  _renderMaterial.TextureLayer[0].TextureWrapV = ETC_CLAMP;

  IGPUProgrammingServices* gpu = _driver->getGPUProgrammingServices(); 
  _renderMaterial.MaterialType=(E_MATERIAL_TYPE)gpu->addHighLevelShaderMaterial(vertexShader, "main", EVST_VS_3_0, fragShader, "main", EPST_PS_3_0, &_distortionCB);

  setHMD(HMD);
}
PostProcessing::PostProcessing(video::IVideoDriver* video_driver)
{
    // Check if post-processing is supported on this hardware
    m_supported = false;
    if( irr_driver->isGLSL() )
    {
        m_supported = true;
    }

    //Check which texture dimensions are supported on this hardware
    bool nonsquare = video_driver->queryFeature(video::EVDF_TEXTURE_NSQUARE);
    bool nonpower = video_driver->queryFeature(video::EVDF_TEXTURE_NPOT);
    if (!nonpower) {
        Log::warn("PostProcessing",
                  "Only power of two textures are supported.");
    }
    if (!nonsquare) {
        Log::warn("PostProcessing", "Only square textures are supported.");
    }
    // Initialization
    if(m_supported)
    {
        // Render target
        core::dimension2du opt = video_driver->getScreenSize()
                                .getOptimalSize(!nonpower, !nonsquare);
        m_render_target =
            video_driver->addRenderTargetTexture(opt, "postprocess");
        if(!m_render_target)
        {
            Log::warn("PostProcessing", "Couldn't create the render target "
                      "for post-processing, disabling it.");
            UserConfigParams::m_postprocess_enabled = false;
        }

        // Material and shaders
        IGPUProgrammingServices* gpu =
            video_driver->getGPUProgrammingServices();
        s32 material_type = gpu->addHighLevelShaderMaterialFromFiles(
                   (file_manager->getShaderDir() + "motion_blur.vert").c_str(),
                   "main", video::EVST_VS_2_0,
                   (file_manager->getShaderDir() + "motion_blur.frag").c_str(),
                   "main", video::EPST_PS_2_0,
                   this, video::EMT_SOLID);
        m_blur_material.MaterialType = (E_MATERIAL_TYPE)material_type;
        m_blur_material.setTexture(0, m_render_target);
        m_blur_material.Wireframe = false;
        m_blur_material.Lighting = false;
        m_blur_material.ZWriteEnable = false;

    }
}   // PostProcessing
/** Initialization */
void PostProcessing::init(video::IVideoDriver* video_driver)
{
    // Check if post-processing is supported on this hardware
    m_supported = false;
    if( video_driver->queryFeature(video::EVDF_ARB_GLSL) &&
        video_driver->queryFeature(video::EVDF_PIXEL_SHADER_2_0) &&
        video_driver->queryFeature(video::EVDF_RENDER_TO_TARGET))
    {
        m_supported = true;
    }
    
    //Check which texture dimensions are supported on this hardware
    bool nonsquare = video_driver->queryFeature(video::EVDF_TEXTURE_NSQUARE);
    bool nonpower = video_driver->queryFeature(video::EVDF_TEXTURE_NPOT);
    if (!nonpower) {
        fprintf(stdout, "WARNING: Only power of two textures are supported.\n");
    }
    if (!nonsquare) {
        fprintf(stdout, "WARNING: Only square textures are supported.\n");
    }
    // Initialization
    if(m_supported)
    {
        // Render target
        m_render_target = video_driver->addRenderTargetTexture(video_driver->getScreenSize().getOptimalSize(!nonpower, !nonsquare), "postprocess");
        if(!m_render_target)
        {
            fprintf(stderr, "Couldn't create the render target for post-processing, disabling it\n");
            UserConfigParams::m_postprocess_enabled = false;
        }
        
        // Material and shaders
        IGPUProgrammingServices* gpu = video_driver->getGPUProgrammingServices();
        s32 material_type = gpu->addHighLevelShaderMaterialFromFiles(
                    (file_manager->getDataDir() + "shaders/motion_blur.vert").c_str(), "main", video::EVST_VS_2_0,
                    (file_manager->getDataDir() + "shaders/motion_blur.frag").c_str(), "main", video::EPST_PS_2_0,
                    this, video::EMT_SOLID);
        m_material.MaterialType = (E_MATERIAL_TYPE)material_type;
        m_material.setTexture(0, m_render_target);
        m_material.Wireframe = false;
        m_material.Lighting = false;
        m_material.ZWriteEnable = false;
    }
}
예제 #4
0
// ----------------------------------------------------------------------------
void Terrain::initMaterials()
{
    IVideoDriver* vd = Editor::getEditor()->getVideoDriver();

    IGPUProgrammingServices* gpu = vd->getGPUProgrammingServices();
    s32 material_type;
    material_type = gpu->addHighLevelShaderMaterial(
        vs, ps, this, EMT_SOLID);

    m_material.MaterialType = (E_MATERIAL_TYPE)material_type;

    m_material.setTexture(1, createSplattingImg());
    m_material.setTexture(2, vd->getTexture(L"dirt.jpg"));
    m_material.setTexture(3, vd->getTexture(L"grass2.jpg"));
    m_material.setTexture(4, vd->getTexture(L"rock_brown.jpg"));
    m_material.setTexture(5, vd->getTexture(L"sand2.jpg"));
    m_material.setTexture(0, m_material.getTexture(1));

    m_highlight_material.Lighting = false;
    m_highlight_material.MaterialType = EMT_TRANSPARENT_VERTEX_ALPHA;
    m_highlight_material.Wireframe = true;

    m_material.BackfaceCulling           = false;
}
예제 #5
0
int main( ) {
	// Boring stuff: set up the scene, object & camera as usual
	// To make things more interesting, we add many Sydneys and a textured floor this time
	IrrlichtDevice* device = createDevice( DRIVER, dimension2d<s32>( 640, 480 ), 16, false, false, false, 0 );
	IVideoDriver* driver = device->getVideoDriver( );
	ISceneManager* smgr = device->getSceneManager( );
	IGUIEnvironment* guienv = device->getGUIEnvironment( );
	device->getFileSystem( )->changeWorkingDirectoryTo( MEDIA_DIRECTORY );
	guienv->addStaticText( L"Sandbox", rect<s32>( 10, 10, 260, 22 ), true );
	IAnimatedMesh* mesh = smgr->getMesh("sydney.md2");
	IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices( );
	u32 matid;
	switch( driver->getDriverType( ) ) {
		case EDT_OPENGL:
			matid = gpu->addHighLevelShaderMaterial( GL_V_MAT, "main", EVST_VS_1_1, GL_PLAIN, "main", EPST_PS_1_1, new CTexturesShaderCallback( ), EMT_SOLID, 1 );
			break;
		case EDT_DIRECT3D8:
		case EDT_DIRECT3D9:
		default:
			matid = gpu->addHighLevelShaderMaterial( DX_V_MAT, "main", EVST_VS_1_1, DX_PLAIN, "main", EPST_PS_2_0, new CTexturesShaderCallback( ), EMT_SOLID, 0 );
	}
	for( u8 x = 0u; x != 2u; ++ x )
		for( u8 i = 0u; i != 5u; ++ i ) {
			IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
			node->setMaterialFlag(EMF_LIGHTING, false);
			node->setMD2Animation(scene::EMAT_STAND);
			node->setMaterialTexture( 0, driver->getTexture("sydney.bmp") );
			node->setMaterialType( (E_MATERIAL_TYPE) matid );
			node->setPosition( vector3df( -x * 20.0f, 0.0f, i * 40.0f ) );
		}
	ISceneNode* nodeF = smgr->addTerrainSceneNode( "terrain-heightmap.bmp" );
	nodeF->setMaterialFlag(EMF_LIGHTING, false);
	nodeF->setMaterialTexture( 0, driver->getTexture("terrain-heightmap.bmp") );
	nodeF->setPosition( vector3df( -512.0f, -50.0f, -512.0f ) );
	nodeF->setScale( vector3df( 4.0f, 0.2f, 4.0f ) );
	nodeF->setMaterialType( (E_MATERIAL_TYPE) matid );
	ICameraSceneNode* cam1 = smgr->addCameraSceneNode( 0, vector3df( 0.0f, 0.0f, -40.0f ), vector3df( 0.0f, 5.0f, 50.0f ) );

	IPostProc* ppRenderer1 = new CRendererPostProc( smgr, dimension2di( 1024, 512 ), true, true, SColor( 255, 130u, 180u, 230u ) );
	CWaterPostProc* ppWater = new CWaterPostProc( ppRenderer1, dimension2di( 1024, 512 ), -22.0f );
	ppWater->setTimer( device->getTimer( ) );
	wchar_t tmp[255];
	u8 t = 0u;
	while( device->run( ) ) {
//		cam1->setPosition( vector3df( 40.0f, 60.0f - (device->getCursorControl( )->getPosition( ).Y - 240.0f) * 0.1f, -40.0f ) );
		cam1->setPosition( vector3df( (device->getCursorControl( )->getPosition( ).X - 320.0f) * 0.1f, (device->getCursorControl( )->getPosition( ).Y - 240.0f) * 0.1f, -40.0f ) );
//		cam1->setTarget( vector3df( (device->getCursorControl( )->getPosition( ).X - 320.0f) * 0.1f, (device->getCursorControl( )->getPosition( ).Y - 240.0f) * 0.1f, 0.0f ) );
//		cam1->setTarget( cam1->getPosition( ) + vector3df( 0.0f, 0.0f, 10.0f ) );
//		cam1->setTarget( vector3df( -(device->getCursorControl( )->getPosition( ).X - 320.0f) * 0.1f, (device->getCursorControl( )->getPosition( ).Y - 240.0f) * 0.2f, 50.0f ) );

		driver->beginScene( false, driver->getDriverType( ) == video::EDT_DIRECT3D9 );
		ppWater->render( NULL );
		guienv->drawAll( );
		driver->endScene( );

		if( ++ t == 30u ) {
			t = 0u;
			swprintf(tmp, 255, L"%ls fps:%3d", driver->getName(), driver->getFPS() );
			device->setWindowCaption( tmp );
		}
	}

	delete ppWater;
	delete ppRenderer1;

	// Back to boring stuff
	device->drop();
	return 0;
}
예제 #6
0
int main( ) {
	// Boring stuff: set up the scene, object & camera as usual
	// To make things more interesting, we add many Sydneys and a textured floor this time
	IrrlichtDevice* device = createDevice( DRIVER, dimension2d<s32>( 640, 480 ), 16, false, false, false, 0 );
	IVideoDriver* driver = device->getVideoDriver( );
	ISceneManager* smgr = device->getSceneManager( );
	IGUIEnvironment* guienv = device->getGUIEnvironment( );
	device->getFileSystem( )->changeWorkingDirectoryTo( MEDIA_DIRECTORY );
	guienv->addStaticText( L"Heat Haze (with Depth dependence)", rect<s32>( 10, 10, 260, 22 ), true );
	IAnimatedMesh* mesh = smgr->getMesh("sydney.md2");
	ISceneManager* smgr2 = smgr->createNewSceneManager( false );
	ISceneNode* rootnode2 = smgr2->getRootSceneNode( );
	IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices( );
	u32 matid, matid2;
	switch( driver->getDriverType( ) ) {
		case EDT_OPENGL:
			matid = gpu->addHighLevelShaderMaterial( GL_V_MAT, "main", EVST_VS_1_1, GL_PLAIN, "main", EPST_PS_1_1, new CTexturesShaderCallback( ), EMT_SOLID, 1 );
			matid2 = gpu->addHighLevelShaderMaterial( GL_V_MAT, "main", EVST_VS_1_1, GL_HEATSOURCE, "main", EPST_PS_1_1, new CTexturesShaderCallback( ), EMT_TRANSPARENT_ALPHA_CHANNEL, 1 );
			break;
		case EDT_DIRECT3D8:
		case EDT_DIRECT3D9:
		default:
			matid = gpu->addHighLevelShaderMaterial( DX_V_MAT, "main", EVST_VS_1_1, DX_PLAIN, "main", EPST_PS_2_0, new CTexturesShaderCallback( ), EMT_SOLID, 0 );
			matid2 = gpu->addHighLevelShaderMaterial( DX_V_MAT, "main", EVST_VS_1_1, DX_HEATSOURCE, "main", EPST_PS_2_0, new CTexturesShaderCallback( ), EMT_TRANSPARENT_ALPHA_CHANNEL, 0 );
	}
	for( u8 x = 0u; x != 2u; ++ x )
		for( u8 i = 0u; i != 5u; ++ i ) {
			IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
			node->setMaterialFlag(EMF_LIGHTING, false);
			node->setMD2Animation(scene::EMAT_STAND);
			node->setMaterialTexture( 0, driver->getTexture("sydney.bmp") );
			node->setMaterialType( (E_MATERIAL_TYPE) matid );
			node->setPosition( vector3df( -x * 20.0f, 0.0f, i * 40.0f ) );
			ISceneNode* node2 = smgr2->addBillboardSceneNode( rootnode2, dimension2df( 30.0f, 80.0f ), vector3df( -x * 20.0f, 30.0f, i * 40.0f ) );
			node2->setMaterialFlag(EMF_LIGHTING, false);
			node2->setMaterialType( EMT_TRANSPARENT_ADD_COLOR );
			node2->setMaterialTexture( 0, driver->getTexture("fireball.bmp") );
			node2->setMaterialType( (E_MATERIAL_TYPE) matid2 );
		}
	ISceneNode* nodeF = smgr->addMeshSceneNode( smgr->addHillPlaneMesh( "", dimension2df( 200.0f, 200.0f ), dimension2d<u32>( 10, 10 ), NULL, 0.0f, dimension2df( 0.0f, 0.0f ), dimension2df( 100.0f, 100.0f ) ) );
	nodeF->setMaterialFlag(EMF_LIGHTING, false);
	nodeF->setMaterialTexture( 0, driver->getTexture("terrain-heightmap.bmp") );
	nodeF->setPosition( vector3df( 0.0f, -22.0f, 0.0f ) );
	nodeF->setMaterialType( (E_MATERIAL_TYPE) matid );
	ICameraSceneNode* cam1 = smgr->addCameraSceneNode( 0, vector3df( 40.0f, 60.0f, -40.0f ), vector3df( 0.0f, 5.0f, 50.0f ) );
	ICameraSceneNode* cam2 = smgr2->addCameraSceneNode( rootnode2, vector3df( 40.0f, 60.0f, -40.0f ), vector3df( 0.0f, 5.0f, 50.0f ) );

	IPostProc* ppRenderer1 = new CRendererPostProc( smgr, dimension2di( 1024, 512 ), true, true, SColor( 255u, 100u, 101u, 140u ) );
	IPostProc* ppRenderer2 = new CRendererPostProc( smgr2, dimension2di( 1024, 512 ), true, true, SColor( 255u, 0u, 0u, 0u ) );
	CEffectPostProc* ppHaze = new CEffectPostProc( ppRenderer1, dimension2di( 1024, 512 ), PP_HAZEDEPTH );
	ppHaze->setInput( 1, ppRenderer2 );
	ppHaze->setTimer( device->getTimer( ) );

	// These variables aren't important - they are just for showing the FPS
	wchar_t tmp[255]; u8 t = 0u;

	while( device->run( ) ) {
		cam1->setPosition( vector3df( 40.0f, 60.0f - (device->getCursorControl( )->getPosition( ).Y - 240.0f) * 0.1f, -40.0f ) );
		cam1->setTarget( vector3df( -(device->getCursorControl( )->getPosition( ).X - 320.0f) * 0.1f, (device->getCursorControl( )->getPosition( ).Y - 240.0f) * 0.2f, 50.0f ) );
		cam2->setPosition( cam1->getPosition( ) );
		cam2->setTarget( cam1->getTarget( ) );
		cam2->setUpVector( cam1->getUpVector( ) );

		driver->beginScene( false, driver->getDriverType( ) == video::EDT_DIRECT3D9 );
		ppHaze->render( NULL );
		guienv->drawAll( );
		driver->endScene( );

		// Show the current FPS
		if( ++ t == 30u ) { t = 0u; swprintf(tmp, 255, L"%ls fps:%3d", driver->getName(), driver->getFPS() ); device->setWindowCaption( tmp ); }
	}

	delete ppHaze;
	delete ppRenderer1;
	delete ppRenderer2;

	// Back to boring stuff
	device->drop();
	return 0;
}
예제 #7
0
int main( ) {
	// Boring stuff: set up the scene, object & camera as usual
	// To make things more interesting, we add many Sydneys and a textured floor this time
	IrrlichtDevice* device = createDevice( DRIVER, dimension2d<s32>( 640, 480 ), 16, false, false, false, 0 );
	IVideoDriver* driver = device->getVideoDriver( );
	ISceneManager* smgr = device->getSceneManager( );
	IGUIEnvironment* guienv = device->getGUIEnvironment( );
	device->getFileSystem( )->changeWorkingDirectoryTo( MEDIA_DIRECTORY );
	guienv->addStaticText( L"Depth of Field", rect<s32>( 10, 10, 260, 22 ), true );
	IAnimatedMesh* mesh = smgr->getMesh("sydney.md2");

	// Create the required material. This is a simple shader which draws the texture with no lights.
	// Use GL_PLAIN1 / DX_PLANE1 or GL_PLAIN2 / DX_PLANE2 to support 1 or 2 basic point-lights
	u32 matid;
	IGPUProgrammingServices* gpu = driver->getGPUProgrammingServices( );
	switch( driver->getDriverType( ) ) {
		case EDT_OPENGL:
			matid = gpu->addHighLevelShaderMaterial( GL_V_MAT, "main", EVST_VS_1_1, GL_PLAIN, "main", EPST_PS_1_1, new CTexturesShaderCallback( ), EMT_SOLID, 1 );
			break;
		case EDT_DIRECT3D8:
		case EDT_DIRECT3D9:
		default:
			matid = gpu->addHighLevelShaderMaterial( DX_V_MAT, "main", EVST_VS_1_1, DX_PLAIN, "main", EPST_PS_2_0, new CTexturesShaderCallback( ), EMT_SOLID, 0 );
	}

	for( u8 x = 0u; x != 2u; ++ x )
		for( u8 i = 0u; i != 5u; ++ i ) {
			IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
			node->setMaterialFlag(EMF_LIGHTING, false);
			node->setMD2Animation(scene::EMAT_STAND);
			node->setMaterialTexture( 0, driver->getTexture("sydney.bmp") );
			node->setMaterialType( (E_MATERIAL_TYPE) matid );
			node->setPosition( vector3df( -x * 20.0f, 0.0f, i * 40.0f ) );
		}
	ISceneNode* node2 = smgr->addMeshSceneNode( smgr->addHillPlaneMesh( "", dimension2df( 200.0f, 200.0f ), dimension2d<u32>( 10, 10 ), NULL, 0.0f, dimension2df( 0.0f, 0.0f ), dimension2df( 100.0f, 100.0f ) ) );
	node2->setMaterialFlag(EMF_LIGHTING, false);
	node2->setMaterialTexture( 0, driver->getTexture("terrain-heightmap.bmp") );
	node2->setMaterialType( (E_MATERIAL_TYPE) matid );
	node2->setPosition( vector3df( 0.0f, -22.0f, 0.0f ) );
	ICameraSceneNode* cam = smgr->addCameraSceneNode( 0, vector3df( 40.0f, 60.0f, -40.0f ), vector3df( 0.0f, 5.0f, 50.0f ) );

	IPostProc* ppRenderer = new CRendererPostProc( smgr, dimension2di( 1024, 512 ), true, true, SColor( 255u, 100u, 101u, 140u ) );
	CEffectPostProc* ppBlurDOF = new CEffectPostProc( ppRenderer, dimension2di( 1024, 512 ), PP_BLURDOF );
	// We could set parameters on creation, but no need since we will animate it anyway.
	// Parameters are: near blur, near focus, far focus, far blur, blur level
	// You can also use PP_BLURDOFNEAR or PP_BLURDOFFAR to have only near or far blurring

	// These variables aren't important - they are just for showing the FPS
	wchar_t tmp[255]; u8 t = 0u;

	while( device->run( ) ) {
		// Change the camera angle
		cam->setTarget( vector3df( -(device->getCursorControl( )->getPosition( ).X - 320.0f) * 0.1f, (device->getCursorControl( )->getPosition( ).Y - 240.0f) * 0.2f, 0.0f ) );

		// Animate the depth of field:
		f32 p = sinf( device->getTimer( )->getTime( ) * 0.0005f ) * 0.5f - 0.2f;
		ppBlurDOF->setParameters( p * 100.0f + 80.0f, p * 100.0f + 110.0f, p * 100.0f + 160.0f, p * 100.0f + 240.0f, 0.01f );

		driver->beginScene( false, driver->getDriverType( ) == video::EDT_DIRECT3D9 );
		ppBlurDOF->render( NULL );
		guienv->drawAll( );
		driver->endScene( );

		// Show the current FPS
		if( ++ t == 30u ) { t = 0u; swprintf(tmp, 255, L"%ls fps:%3d", driver->getName(), driver->getFPS() ); device->setWindowCaption( tmp ); }
	}

	delete ppBlurDOF;
	delete ppRenderer;

	// Back to boring stuff
	device->drop();
	return 0;
}
예제 #8
0
int main(int argc, char **argv) {

	// Help?
	if (argv[1] && argv[1][0] == '-') die(helpmsg);

	putenv((char *) "vblank_mode=0"); // No vsync for us, thanks.

	MyEventReceiver *r = new MyEventReceiver();
	IrrlichtDevice *dev = createDevice(EDT_OPENGL, core::dimension2d<u32>(1024,768), 32,
				false, false, false, r);
	if (!dev) die("Can't initialize Irrlicht");

	IVideoDriver *drv = dev->getVideoDriver();
	ISceneManager *smgr = dev->getSceneManager();
	IGPUProgrammingServices *gpu = drv->getGPUProgrammingServices();
	ICameraSceneNode *cam = NULL;
	ITexture *pic = NULL;
	IMeshSceneNode *ball = NULL;
	bool showpic = false;

	IReadFile *areamap = createMemoryReadFile(AreaMap33, sizeof(AreaMap33), "AreaMap33", false);
	if (!areamap) die("Failed to load areamap");
	ITexture *areamaptex = drv->getTexture(areamap);
	areamap->drop();

	// If there's an argument, assume it is a pic to load; otherwise, draw a sphere

	if (argv[1] && access(argv[1], R_OK) == 0) {
		showpic = true;
		pic = drv->getTexture(argv[1]);
		if (!pic) die("Can't load image");

		cam = smgr->addCameraSceneNode();
	} else {
		cam = smgr->addCameraSceneNodeMaya();
		cam->setTarget(vector3df(0, 0, 0));
		ball = smgr->addSphereSceneNode(40, 8);

		int ballshader = gpu->addHighLevelShaderMaterial(rnd,0,EVST_VS_1_1,0);
		ball->setMaterialType((E_MATERIAL_TYPE) ballshader);

		ISceneNodeAnimator *cool = smgr->createRotationAnimator(vector3df(-0.1, 0.1, -0.1));
		ball->addAnimator(cool);
		cool->drop();
	}

	// Set up static defines, RTTs, quads
	dimension2d<u32> screensize = drv->getScreenSize();
	char defines[128];
	snprintf(defines, 128,
		"#define PIXEL_SIZE vec2(1.0f / %u.0, 1.0f / %u.0)\n"
		"#define MAX_SEARCH_STEPS 8.0\n#define MAX_DISTANCE 33.0\n",
		screensize.Width, screensize.Height);

	ITexture *rt1 = drv->addRenderTargetTexture(screensize, "rt1", ECF_A8R8G8B8);
	ITexture *rt2 = drv->addRenderTargetTexture(screensize, "rt2", ECF_A8R8G8B8);
	ITexture *rt3 = drv->addRenderTargetTexture(screensize, "rt3", ECF_A8R8G8B8);
	if (!rt1 || !rt2 || !rt3) die("No RTT");

	ScreenQuad *def = new ScreenQuad(drv);
	ScreenQuad *sq = new ScreenQuad(drv);
	ScreenQuad *sq2 = new ScreenQuad(drv);
	ScreenQuad *sq3 = new ScreenQuad(drv);
	ScreenQuad *norm = new ScreenQuad(drv);
	if (showpic) def->SetTexture(pic);
	sq->SetTexture(rt1);
	sq->GetMaterial().setFlag(EMF_BILINEAR_FILTER, false);
	norm->SetTexture(rt1);
	norm->GetMaterial().setFlag(EMF_BILINEAR_FILTER, false);

	sq2->SetTexture(rt2);
	sq2->SetTexture(rt2, 1);
	sq2->SetTexture(areamaptex, 2);
	sq2->GetMaterial().TextureLayer[2].BilinearFilter = false;

	sq3->SetTexture(rt3);
	sq3->GetMaterial().setFlag(EMF_BILINEAR_FILTER, false);
	sq3->SetTexture(rt1,1);
	state_t state = MLAA_OFF;

	stringc tmp1, tmp2;
	tmp1 = defines;
	tmp1 += offsetvs;
	tmp2 = defines;
	tmp2 += color1fs;

	// Load shaders
	int edge = gpu->addHighLevelShaderMaterial(tmp1.c_str(),0,EVST_VS_1_1,tmp2.c_str());
	sq->SetMaterialType((E_MATERIAL_TYPE) edge);

	tmp2 = defines;
	tmp2 += blend2fs;

	blendcb *bcb = new blendcb();
	edge = gpu->addHighLevelShaderMaterial(tmp1.c_str(),0,EVST_VS_1_1,tmp2.c_str(),0,EPST_PS_1_1,bcb);
	sq2->SetMaterialType((E_MATERIAL_TYPE) edge);

	tmp2 = defines;
	tmp2 += neigh3fs;

	neighcb *ncb = new neighcb();
	edge = gpu->addHighLevelShaderMaterial(tmp1.c_str(),0,EVST_VS_1_1,tmp2.c_str(),0,EPST_PS_1_1,ncb);
	sq3->SetMaterialType((E_MATERIAL_TYPE) edge);

	// Record start time
	int lastfps = -1, minfps = 10000;
	unsigned long long total_frames = 0, fxtimer = 0, tmplong, onframes = 0;
	struct timeval starttime, tick1, tick2;
	float glsltime = 0;
	gettimeofday(&starttime, NULL);
	wchar_t cap[20];
	glEnable(GL_STENCIL_TEST);
	unsigned char firstrun = 1; // To avoid the glsl compiler in the timing

	// Main loop
	while (dev->run()) {

		gettimeofday(&tick1, NULL);
		drv->beginScene();

		switch (state) {
			case MLAA_OFF:
				if (showpic) def->Render(false);
				else smgr->drawAll();
			break;
			case MLAA_ON:
				if (showpic) def->Render(rt1);
				else {
					drv->setRenderTarget(rt1);
					smgr->drawAll();
				}


				glClear(GL_STENCIL_BUFFER_BIT);
				glStencilFunc(GL_ALWAYS, 1, ~0);
				glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
				sq->Render(rt2);

				glStencilFunc(GL_EQUAL, 1, ~0);
				glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
				sq2->Render(rt3);
				drv->setRenderTarget(rt1, false, false);

				// Overlay the smoothed edges on the initial image
				sq3->Render(false);

				// Blit the final image to the framebuffer
				glStencilFunc(GL_ALWAYS, 1, ~0);
				norm->Render();

			break;
		}

		drv->endScene();

		if (state == MLAA_ON) {
			gettimeofday(&tick2, NULL);
			if (!firstrun) {
				tmplong = (tick2.tv_sec - tick1.tv_sec) * 10000;
				tmplong += (tick2.tv_usec - tick1.tv_usec) / 100;
				fxtimer += tmplong;

				onframes++;
			} else {
				firstrun = 0;

				glsltime = tick2.tv_sec - tick1.tv_sec;
				glsltime += (tick2.tv_usec - tick1.tv_usec) / 1000000.0;
			}
		}

		int fps = drv->getFPS();
		if (minfps > fps) minfps = fps;
		if (lastfps != fps) {
			swprintf(cap, 20, L"%d fps, MLAA %s", fps, state == MLAA_ON ? "on" : "off");
			dev->setWindowCaption(cap);
			lastfps = fps;
		}

		if (r->IsKeyDown(KEY_KEY_M)) {
			if (state == MLAA_ON) state = MLAA_OFF;
			else state = MLAA_ON;

			lastfps++;
		}

		usleep(1); // 16?
		total_frames++;
	}

	dev->drop();
	delete ncb;
	delete bcb;
	delete def;
	delete sq;
	delete sq2;
	delete sq3;
	delete norm;
	delete r;

	struct timeval endtime;
	gettimeofday(&endtime, NULL);
	float sec = endtime.tv_sec - starttime.tv_sec;
	sec += ((float) endtime.tv_usec - starttime.tv_usec) / 1000000;
	printf("\nRan %.3fs, ", sec);
	sec -= glsltime;

	printf("average fps %.2f, min %d\n", (float) total_frames/sec, minfps);

	if (onframes) {
		printf("\nAverage on fps %.2f, average off fps %.2f\n\n", (float) onframes/(fxtimer/10000.0),
					(float) (total_frames - onframes)/(sec - (fxtimer/10000.0)));

//		printf("MLAA took on average %.1fms\n", (float) (fxtimer / onframes) / 10.0);
	}

	return 0;
}