void Scene::optixInit(optix::Context context) {

	// Group containing each object transform
	Optix.group = context->createGroup();
	Optix.group->setAcceleration(context->createAcceleration(OPTIX_SCENE_BUILDER, OPTIX_SCENE_TRAVERSER)); // TODO: Look into different traversers/builders

	for (uint i = 0; i < objects.size(); i++) {
		objects[i]->optixInit(context);
		Optix.group->addChild(objects[i]->Optix.transform);
	}

	// Sky texture sampler
#if OPTIX_USE_OPENGL_TEXTURE
	Optix.sky = context->createTextureSamplerFromGLImage(sky->texture, RT_TARGET_GL_TEXTURE_2D);
#else
	optix::Buffer buf = context->createBuffer(RT_BUFFER_INPUT, RT_FORMAT_FLOAT4, sky->width, sky->height);
	memcpy(buf->map(), sky->pixels, sky->width * sky->height * sizeof(Color));
	buf->unmap();
	Optix.sky = context->createTextureSampler();
	Optix.sky->setArraySize(1);
	Optix.sky->setMipLevelCount(1);
	Optix.sky->setBuffer(0, 0, buf);
#endif
	Optix.sky->setWrapMode(0, RT_WRAP_REPEAT);
	Optix.sky->setWrapMode(1, RT_WRAP_REPEAT);
	Optix.sky->setIndexingMode(RT_TEXTURE_INDEX_NORMALIZED_COORDINATES);
	Optix.sky->setReadMode(RT_TEXTURE_READ_NORMALIZED_FLOAT);
	Optix.sky->setMaxAnisotropy(1.f);
	Optix.sky->setFilteringModes(RT_FILTER_LINEAR, RT_FILTER_LINEAR, RT_FILTER_NONE);

}
void OptiXRenderer::convertToOptiXScene(optix::Context context, int width, int height, float film_location) {
	// Setup lighting
	// TODO For now, we assume just one light
	context->setEntryPointCount( 1 );
	context->setRayGenerationProgram( 0, mScene->mLights[0]->getOptiXLight(context) );

	// Exception program
	context->setExceptionProgram( 0, context->createProgramFromPTXFile( "ptx/PhotonTracer.ptx", "exception" ) );

	// Miss program
	context->setMissProgram( 0, context->createProgramFromPTXFile( "ptx/PhotonTracer.ptx", "miss" ) );

	// Geometry group
	optix::GeometryGroup geometrygroup = context->createGeometryGroup();
	geometrygroup->setChildCount( mScene->mObjects.size() + 1 );
	geometrygroup->setAcceleration( context->createAcceleration("Bvh","Bvh") );

	// Add objects
	for(std::vector<RenderObject*>::size_type i = 0; i != mScene->mObjects.size(); i++) {
		optix::GeometryInstance gi = context->createGeometryInstance();
		// TODO we only support 1 material type per object
		gi->setMaterialCount(1);
		gi->setGeometry(   mScene->mObjects[i]->getOptiXGeometry(context));
		gi->setMaterial(0, mScene->mObjects[i]->getOptiXMaterial(context));
		geometrygroup->setChild(i, gi);
	}

	// Create Camera
	//
	mCameraMat = new CameraMaterial(width, height, 1);
	PlaneObject* plane = new PlaneObject(mCameraMat);
	plane->setPosition(0, 0, film_location); //-65
	mCameraObject = plane;
	// Convert to OptiX
	optix::GeometryInstance gi = context->createGeometryInstance();
	gi->setMaterialCount(1);
	gi->setGeometry(   mCameraObject->getOptiXGeometry(context));
	mCameraMatOptiX = mCameraObject->getOptiXMaterial(context);
	mCameraMatOptiX["width"]->setInt(width);
	mCameraMatOptiX["height"]->setInt(height);
	gi->setMaterial(0, mCameraMatOptiX);
	geometrygroup->setChild(mScene->mObjects.size(), gi);

	context["top_object"]->set(geometrygroup);
}
void Object::optixInit(optix::Context context) {

	try {
		
		// Make geometry group
		Optix.geometryGroup = context->createGeometryGroup();
		Optix.geometryGroup->setAcceleration(context->createAcceleration(OPTIX_GEOMETRY_BUILDER, OPTIX_GEOMETRY_TRAVERSER)); // TODO: Look into different traversers/builders

		// Add geometries
		for (uint i = 0; i < geometries.size(); i++) {
			geometries[i]->optixInit(context);
			Optix.geometryGroup->addChild(((TriangleMesh*)geometries[i])->Optix.geometryInstance);
		}

		// Make transform
		Optix.transform = context->createTransform();
		Optix.transform->setChild(Optix.geometryGroup);
		Optix.transform->setMatrix(true, matrix.e, NULL);

	} catch (optix::Exception e) {
		printException(e);
	}

}
optix::Group CornellSmall::getSceneRootGroup(optix::Context & context)
{
    m_pgram_bounding_box = context->createProgramFromPTXFile( "parallelogram.cu.ptx", "bounds" );
    m_pgram_intersection = context->createProgramFromPTXFile( "parallelogram.cu.ptx", "intersect" );

    // create geometry instances
    QVector<optix::GeometryInstance> gis;

    Diffuse diffuseWhite = Diffuse(optix::make_float3( 0.8f ));
    Diffuse diffuseGreen = Diffuse(optix::make_float3( 0.05f, 0.8f, 0.05f ));
    Diffuse diffuseRed = Diffuse(optix::make_float3( 1.f, 0.05f, 0.05f ));

    // colors as in SmallVCM
    if ((m_config & CornellSmall::SmallVCMColors) != 0)
    {
        diffuseWhite = Diffuse(optix::make_float3( 0.803922f, 0.803922f, 0.803922f ));
        diffuseGreen = Diffuse(optix::make_float3( 0.156863f, 0.803922f, 0.172549f ));
        diffuseRed = Diffuse(optix::make_float3( 0.803922f, 0.152941f, 0.152941f ));
    }
    Diffuse diffuseBlue = Diffuse(optix::make_float3( 0.156863f, 0.172549f, 0.803922f ));

    Mirror mirror = Mirror(optix::make_float3(1.f,1.f,1.f));
    Glossy glossyWhite = Glossy(optix::make_float3(.1f,.1f,.1f), optix::make_float3(.7f,.7f,.7f), 90.f);
    Glass glass = Glass(1.6, optix::make_float3(1.f,1.f,1.f), optix::make_float3(1.f,1.f,1.f) );
    DiffuseEmitter emitter = DiffuseEmitter(m_sceneLights[0].power, Vector3(1));

    // Set up materials
    // Floor
    Material *matFloor = &diffuseWhite;
    if ((m_config & Config::FloorMirror) != 0)
    {
        matFloor = &mirror;
    }
    else if ((m_config & Config::FloorGlossy) != 0)
    {
        matFloor = &glossyWhite;
    }

    // Ceiling
    Material *matCeiling = &diffuseWhite;

    // Back wall
    Material *matBackWall = &diffuseWhite;
    if ((m_config & Config::BackwallBlue) != 0)
    {
        matBackWall = &diffuseBlue;
    }

    // Right wall
    Material *matRightWall = &diffuseGreen;
    if ((m_config & CornellSmall::SmallVCMColors) != 0)
        matRightWall = &diffuseRed;

    // Left wall
    Material *matLeftWall = &diffuseRed;
    if ((m_config & CornellSmall::SmallVCMColors) != 0)
        matLeftWall = &diffuseGreen;

    // Short block
    Material *matShortBlock = &diffuseWhite;

    // Tall block
    Material *matTallBlock = &diffuseWhite;


    // Set geometry - Cornell box size in SmallVCM 2.56004, here rounded up slightly
    // Floor    
    gis.push_back( createParallelogram(0, context, optix::make_float3( 0.0f, 0.0f, 0.0f ),
        optix::make_float3( 0.0f, 0.0f, 2.5f ),
        optix::make_float3( 2.5f, 0.0f, 0.0f ),
        *matFloor ) );

    // Ceiling
    if ((m_config & Config::LightPointDistant) == 0)
    {
        gis.push_back( createParallelogram(1, context, optix::make_float3( 0.0f, 2.5f, 0.0f ),
            optix::make_float3( 2.5f, 0.0f, 0.0f ),
            optix::make_float3( 0.0f, 0.0f, 2.5f ),
            *matCeiling ) );
    }

    // Back wall
    gis.push_back( createParallelogram(2, context,optix::make_float3( 0.0f, 0.0f, 2.5f),
        optix::make_float3( 0.0f, 2.5f, 0.0f),
        optix::make_float3( 2.5f, 0.0f, 0.0f),
        *matBackWall));

    // Right wall
    gis.push_back( createParallelogram(3, context, optix::make_float3( 0.0f, 0.0f, 0.0f ),
        optix::make_float3( 0.0f, 2.5f, 0.0f ),
        optix::make_float3( 0.0f, 0.0f, 2.5f ),
        *matRightWall ) );

    // Left wall
    gis.push_back( createParallelogram(4, context, optix::make_float3( 2.5f, 0.0f, 0.0f ),
        optix::make_float3( 0.0f, 0.0f, 2.5f ),
        optix::make_float3( 0.0f, 2.5f, 0.0f ),
        *matLeftWall ) );


    if ((m_config & Config::Blocks) != 0)
    {
        // Short block
        gis.push_back( createParallelogram(5, context, 
            optix::make_float3( 130.0f, 165.0f, 65.0f) / 220.f,
            optix::make_float3( -48.0f, 0.0f, 160.0f) / 220.f,
            optix::make_float3( 160.0f, 0.0f, 49.0f) / 220.f,
            *matShortBlock ) );
        gis.push_back( createParallelogram(6, context, 
            optix::make_float3( 290.0f, 0.0f, 114.0f) / 220.f,
            optix::make_float3( 0.0f, 165.0f, 0.0f) / 220.f,
            optix::make_float3( -50.0f, 0.0f, 158.0f) / 220.f,
            *matShortBlock ) );
        gis.push_back( createParallelogram(7, context, 
            optix::make_float3( 130.0f, 0.0f, 65.0f) / 220.f,
            optix::make_float3( 0.0f, 165.0f, 0.0f) / 220.f,
            optix::make_float3( 160.0f, 0.0f, 49.0f) / 220.f,
            *matShortBlock ) );
        gis.push_back( createParallelogram(8, context, 
            optix::make_float3( 82.0f, 0.0f, 225.0f) / 220.f,
            optix::make_float3( 0.0f, 165.0f, 0.0f) / 220.f,
            optix::make_float3( 48.0f, 0.0f, -160.0f) / 220.f,
            *matShortBlock ) );
        gis.push_back( createParallelogram(9, context,
            optix::make_float3( 240.0f, 0.0f, 272.0f) / 220.f,
            optix::make_float3( 0.0f, 165.0f, 0.0f) / 220.f,
            optix::make_float3( -158.0f, 0.0f, -47.0f) / 220.f,
            *matShortBlock));
        
        // Tall block
        gis.push_back( createParallelogram(10, context, 
            optix::make_float3( 423.0f, 340.0f, 247.0f) / 220.f,
            optix::make_float3( -158.0f, 0.0f, 49.0f) / 220.f,
            optix::make_float3( 49.0f, 0.0f, 159.0f) / 220.f,
            *matTallBlock ) );
        gis.push_back( createParallelogram(11, context, 
            optix::make_float3( 423.0f, 0.0f, 247.0f) / 220.f,
            optix::make_float3( 0.0f, 340.0f, 0.0f) / 220.f,
            optix::make_float3( 49.0f, 0.0f, 159.0f) / 220.f,
            *matTallBlock ) );
        gis.push_back( createParallelogram(12, context, 
            optix::make_float3( 472.0f, 0.0f, 406.0f) / 220.f,
            optix::make_float3( 0.0f, 340.0f, 0.0f) / 220.f,
            optix::make_float3( -158.0f, 0.0f, 50.0f) / 220.f,
            *matTallBlock ) );
        gis.push_back( createParallelogram(13, context, 
            optix::make_float3( 314.0f, 0.0f, 456.0f) / 220.f,
            optix::make_float3( 0.0f, 340.0f, 0.0f) / 220.f,
            optix::make_float3( -49.0f, 0.0f, -160.0f) / 220.f,
            *matTallBlock ) );
        gis.push_back( createParallelogram(14, context, 
            optix::make_float3( 265.0f, 0.0f, 296.0f) / 220.f,
            optix::make_float3( 0.0f, 340.1f, 0.0f) / 220.f,
            optix::make_float3( 158.0f, 0.0f, -49.0f) / 220.f,
            *matTallBlock ) );
    }

    // Area light
    if ( ((m_config & Config::LightArea) != 0) || 
         ((m_config & Config::LightAreaUpwards) != 0) )
    {
        emitter.setInverseArea(m_sceneLights[0].inverseArea);
        for(int i = 0; i < m_sceneLights.size(); i++)
        {
            gis.push_back(createParallelogram(15 + i, context, m_sceneLights[i].position, 
                m_sceneLights[i].v1, m_sceneLights[i].v2, emitter));
        }
    }    


    // Large sphere
    if ((m_config & Config::LargeMirrorSphere) != 0 || (m_config & Config::LargeGlassSphere) != 0)
    {
        Material *matLargeSphere = &mirror;
        if ((m_config & Config::LargeGlassSphere) != 0)
            matLargeSphere = &glass;

        float radius = 0.8;
        SphereInstance sphere = SphereInstance(*matLargeSphere, Sphere(Vector3(1.25f, radius, 1.25f), radius));
        gis.push_back(sphere.getOptixGeometryInstance(context));
    }
    
    // Small glass sphere right
    if ((m_config & Config::SmallGlassSphere))
    {
        float radius = 0.5;
        SphereInstance sphere = SphereInstance(glass, Sphere(Vector3(1.25f - 0.535714269f, radius, 1.25f), radius));
        gis.push_back(sphere.getOptixGeometryInstance(context));
    }

    // Small mirror sphere left
    if ((m_config & Config::SmallMirrorSphere))
    {
        float radius = 0.5;
        SphereInstance sphere = SphereInstance(mirror, Sphere(Vector3(1.25f + 0.535714269f, radius, 1.25f), radius));
        gis.push_back(sphere.getOptixGeometryInstance(context));
    }

    // Create geometry group
    optix::GeometryGroup geometry_group = context->createGeometryGroup();
    geometry_group->setChildCount( static_cast<unsigned int>( gis.size() ) );
    for (int i = 0; i < gis.size(); ++i )
        geometry_group->setChild( i, gis[i] );

    geometry_group->setAcceleration(context->createAcceleration("NoAccel", "NoAccel")); // Bvh Sbvh Trbvh NoAccel // Bvh BvhCompact NoAccel

    optix::Group gro = context->createGroup();
    gro->setChildCount(1);
    gro->setChild(0, geometry_group);
    optix::Acceleration acceleration = context->createAcceleration("NoAccel", "NoAccel"); 
    gro->setAcceleration(acceleration);

    return gro;
}