Hello World!
Description
This tutorial uses high-level HOOPS Luminate API to build a very simple scene and demonstrates matrix-based animation.
The mesh data are created using the RED::IMeshShape
interface which provides some helpers to create basic primitives:
// Scene creation:
// ---------------
// Create a torus and a plane.
RED::Object* torus = RED::Factory::CreateInstance( CID_REDMeshShape );
if( torus == NULL )
RC_TEST( RED_ALLOC_FAILURE );
RED::IMeshShape* itorus = torus->As< RED::IMeshShape >();
RC_TEST( itorus->Torus( RED::Vector3( 0, 0, 8 ), 20.f, 8.f, 64, 64, iresmgr->GetState() ) );
RED::Object* plane = RED::Factory::CreateInstance( CID_REDMeshShape );
if( plane == NULL )
RC_TEST( RED_ALLOC_FAILURE );
RED::IMeshShape* iplane = plane->As< RED::IMeshShape >();
RC_TEST( iplane->Quad( RED::Vector3( 0, 0, 0 ), 100.f, 100.f, iresmgr->GetState() ) );
// Compute the plan tangent vectors to apply bump mapping on it.
RC_TEST( iplane->BuildTangents( RED::MCL_USER0, RED::MCL_TEX0, iresmgr->GetState() ) );
Note that we call RED::IMeshShape::BuildTangents
on the plane mesh in order to compute plane tangents vector. Those vectors are required when bump mapping is applied to a geometry.
Materials are then created for each geometry, based on the HOOPS Luminate Generic material (see RED::IMaterial::SetupGenericMaterial
):
// Create materials.
RED::Object* mat_torus;
RC_TEST( iresmgr->CreateMaterial( mat_torus, iresmgr->GetState() ) );
RED::IMaterial* imat = mat_torus->As< RED::IMaterial >();
RED::LayerSet ls = RED::LayerSet::ALL_LAYERS;
RC_TEST( imat->SetupGenericMaterial( false, false,
RED::Color::BLACK, NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0,
RED::Color( 0.1f, 0.25f, 0.5f ), NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0,
RED::Color( 0.1f, 0.25f, 0.5f ), NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0,
RED::Color::BLACK, NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0, 0.f,
RED::Color( 0.4f ), NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0, 0.f,
true, false,
NULL, RED::Matrix::IDENTITY,
1.f, true,
RED::Color::BLACK, NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0, 0.f,
NULL, RED::Matrix::IDENTITY, RED::MCL_TEX0, RED::MCL_USER0,
&ls, NULL,
RFK::TutorialApplication::GetResourceManager(), iresmgr->GetState() ) );
RC_TEST( torus->As< RED::IShape >()->SetMaterial( mat_torus, iresmgr->GetState() ) )
RED::Object* mat_plane;
RC_TEST( iresmgr->CreateMaterial( mat_plane, iresmgr->GetState() ) );
imat = mat_plane->As< RED::IMaterial >();
RED::Object* bump = NULL, *texture = NULL;
RC_TEST( iresmgr->CreateImage2D( bump, iresmgr->GetState() ) );
RC_TEST( RED::ImageTools::Load( bump, "../resources/bump.jpg", RED::FMT_RGB, false, false, RED::TGT_TEX_2D, iresmgr->GetState() ) );
RC_TEST( iresmgr->CreateImage2D( texture, iresmgr->GetState() ) );
RC_TEST( RED::ImageTools::Load( texture, "../resources/hello_grid.png", RED::FMT_RGB, false, false, RED::TGT_TEX_2D, iresmgr->GetState() ) );
// Bump textures are normal maps in RED. So, we convert the texture to a valid
// normal map before using it as a bump texture.
RC_TEST( bump->As< RED::IImage2D >()->NormalMap( RED::FMT_RGB, RED::TGT_TEX_2D, 0.85f, bump, iresmgr->GetState() ) );
RED::Matrix tex_mat;
tex_mat.Scale( 4.f );
RC_TEST( imat->SetupGenericBumpyDiffuseMaterial( false,
RED::Color::GREY, texture, tex_mat, RED::MCL_TEX0,
bump, tex_mat, RED::MCL_TEX0, RED::MCL_USER0,
&ls, NULL,
RFK::TutorialApplication::GetResourceManager(), iresmgr->GetState() ) );
RC_TEST( plane->As< RED::IShape >()->SetMaterial( mat_plane, iresmgr->GetState() ) );
We are almost done as we just need to build a light and a camera before being able to render our scene. This is covered in Setup a Spot Light and in Setting Up a Simple Camera.
The framework automatically sends a RFK::EVT_UPDATE
event each time the main loop is evaluated. This is the perfect signal to handle to update our light animation. To catch this event, we simply register a custom callback on it:
RFK::TutorialApplication::SetEventCallback( RFK::EVT_UPDATE, OnIdle );
Then, in the OnIdle callback, we implement a basic light rotation using a time-based rotation matrix:
RED::ILightShape* ilight = light->As< RED::ILightShape >();
RED::Vector3 pos, newpos;
RED::Vector3 sight, newsight;
RED::Vector3 top, newtop;
RED::Vector3 right, newright;
RC_TEST( ilight->GetPos( pos ) );
RC_TEST( ilight->GetSight( sight ) );
RC_TEST( ilight->GetTop( top ) );
RC_TEST( ilight->GetRight( right ) );
RED::Matrix mrot;
mrot.RotationAxisMatrix( RED::Vector3( 30.0f, 0.0f, 0.0f ), RED::Vector3( 0.0f, 0.0f, 1.0f ), 0.001f * ( RFK::TutorialApplication::GetTime() - time_elapsed ) );
time_elapsed = RFK::TutorialApplication::GetTime();
newpos = mrot * pos;
newsight = mrot.RotateNormalize( sight );
newtop = mrot.RotateNormalize( top );
newright = mrot.RotateNormalize( right );
RC_TEST( ilight->SetPos( newpos, iresmgr->GetState() ) );
RC_TEST( ilight->SetSight( newsight, iresmgr->GetState() ) );
RC_TEST( ilight->SetTop( newtop, iresmgr->GetState() ) );
RC_TEST( ilight->SetRight( newright, iresmgr->GetState() ) );