Hello world!


This tutorial uses high-level REDsdk 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 )

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 )

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 REDsdk 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,
                                     RED::Color::WHITE, 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() ) );

Bump mapping as well as environmental mapping are amongst the various effects natively supported by REDsdk.