Downloads |
Source - latest release
|
Source - weekly snapshot
|
|
Documentation |
Browse
|
Download tarball
|
|
|
|
|
Tutorial 3 - Textures
Last update: 22/Jan/2004
This tutorial covers texture loading and basic material management. New code not in
the previous tutorial is in bold.
#include <neoengine/core.h>
#include <neoengine/render.h>
#include <neoengine/logstream.h>
#include <neoengine/input.h>
#include <neoengine/filemanager.h>
#include <neoengine/renderprimitive.h>
#include <neoengine/vertex.h>
#include <neoengine/polygon.h>
#include <neoengine/material.h>
#include <neoengine/texture.h>
#ifdef BUILD_STATIC
#ifdef WIN32
#include <neodevd3d9/link.h>
#endif
#include <neodevopengl/link.h>
#include <neoicpng/link.h>
#endif
using namespace std;
using namespace NeoEngine;
filemanager.h defines the file manager class. This is the hub of the file subsystem of the
engine, and allows objects to add and remove directories and packages into the virtual filesystem,
and to locate files for loading and saving.
material.h defines the material class, blend modes, z buffer modes and texture layers used for
specifying material capabilities of a set of geometry.
texture.h defines the texture classes, and we also include the PNG codec link header for
static builds (we are loading a PNG image).
class InputListener : public InputEntity
{
public:
InputListener( InputGroup *pkGroup ) : InputEntity( pkGroup ) {}
virtual void Input( const InputEvent *pkEvent );
};
RenderDevice *g_pkRenderDevice = 0;
RenderCaps g_kRenderCaps;
LogFileSink g_kLogFile( "neoengine.log" );
InputGroup *g_pkInputGroup = 0;
InputListener *g_pkInputListener = 0;
bool g_bRun = true;
VertexBufferPtr g_pkVertexBuffer;
PolygonBufferPtr g_pkPolygonBuffer;
MaterialPtr g_pkMaterial;
g_pkMaterial is our material object. Materials are, just like the vertex/polygon buffers
and textures, reference counted and accessed through a smart pointer.
int main( int argc, char **argv )
{
neolog.SetLogThreshold( DEBUG );
neolog.AttachSink( Core::Get()->GetStdoutSink() );
neolog.AttachSink( &g_kLogFile );
Core::Get()->Initialize( argc, argv );
Core::Get()->GetFileManager()->AddPackage( "../common/data" );
To be able to locate and load our texture file, we need to tell the file manager where to look for
files in the real filesystem. We add a path to the data directory for the tutorials. This will cause
the file manager to index that directory and any subdirectories in the virtual filesystem the
manager keeps. We can now access any file in that directory through the manager.
if( !( g_pkRenderDevice = Core::Get()->CreateRenderDevice( "opengl" ) ) )
goto SHUTDOWN;
if( !g_pkRenderDevice->Open( RenderWindow( "Render Polygon & Basic Input", g_kRenderCaps, RenderResolution( 640, 480, 16 ) ) ) )
goto SHUTDOWN;
g_kRenderCaps = g_pkRenderDevice->GetCaps();
g_pkInputGroup = new InputGroup;
g_pkInputListener = new InputListener( g_pkInputGroup );
g_pkVertexBuffer = g_pkRenderDevice->CreateVertexBuffer( Buffer::NORMAL, 4, &DiffuseVertex::s_kDecl );
g_pkVertexBuffer->Lock( Buffer::WRITE );
{
DiffuseVertex *pkVertex = (DiffuseVertex*)g_pkVertexBuffer->GetVertex();
pkVertex->m_kPosition.Set( -10.0f, 5.0f, -20.0f );
pkVertex->m_afTexCoord[0] = 0.0f;
pkVertex->m_afTexCoord[1] = 0.0f;
++pkVertex;
pkVertex->m_kPosition.Set( -10.0f, -5.0f, -20.0f );
pkVertex->m_afTexCoord[0] = 0.0f;
pkVertex->m_afTexCoord[1] = 1.0f;
++pkVertex;
pkVertex->m_kPosition.Set( 10.0f, -5.0f, -20.0f );
pkVertex->m_afTexCoord[0] = 1.0f;
pkVertex->m_afTexCoord[1] = 1.0f;
++pkVertex;
pkVertex->m_kPosition.Set( 10.0f, 5.0f, -20.0f );
pkVertex->m_afTexCoord[0] = 1.0f;
pkVertex->m_afTexCoord[1] = 0.0f;
}
g_pkVertexBuffer->Unlock();
g_pkPolygonBuffer = g_pkRenderDevice->CreatePolygonBuffer( Buffer::NORMAL, 2 );
g_pkPolygonBuffer->Lock( Buffer::WRITE );
{
Polygon *pkPolygon = g_pkPolygonBuffer->GetPolygon();
pkPolygon->v[0] = 0;
pkPolygon->v[1] = 1;
pkPolygon->v[2] = 2;
++pkPolygon;
pkPolygon->v[0] = 0;
pkPolygon->v[1] = 2;
pkPolygon->v[2] = 3;
}
g_pkPolygonBuffer->Unlock();
Allocate 4 vertices and 2 polygons to build a quad. The vertices have position and texcoord data,
and we set the texture coordinates to map the whole texture to the quad. Then build two triangles
forming the quad.
g_pkRenderDevice->LoadCodec( "png" );
g_pkMaterial = new Material( "logo", 0 );
g_pkMaterial->m_pkTexture = g_pkRenderDevice->LoadTexture( "logo" );
First we request the texturing subsystem to load the codec to parse PNG files. We then create a new
named material (we pass 0 as material manager pointer, more about this in later tutorials) and set
the base texture by loading the logo.png texture. The LoadTexture method will automatically
locate already loaded textures matching the request to avoid multiple copies of a texture (remember,
textures are also reference counted objects in NeoEngine).
while( g_bRun )
{
Core::Get()->GetInputManager()->Process();
g_pkRenderDevice->Clear( RenderDevice::COLORBUFFER | RenderDevice::ZBUFFER | RenderDevice::STENCILBUFFER, Color::BLACK, 1.0f, 0 );
g_pkRenderDevice->Begin( Matrix::IDENTITY );
{
RenderPrimitive kPrim;
kPrim.m_ePrimitive = RenderPrimitive::TRIANGLES;
kPrim.m_pkMaterial = g_pkMaterial;
kPrim.m_pkVertexBuffer = g_pkVertexBuffer;
kPrim.m_pkPolygonBuffer = g_pkPolygonBuffer;
kPrim.m_uiNumPrimitives = 2;
g_pkRenderDevice->Render( kPrim );
}
g_pkRenderDevice->End();
g_pkRenderDevice->Flip();
}
Set the desired material in the render primitive and render 2 triangles.
SHUTDOWN:
g_pkMaterial = 0;
g_pkVertexBuffer = 0;
g_pkPolygonBuffer = 0;
Core::Get()->DeleteRenderDevice( g_pkRenderDevice );
delete g_pkInputListener;
delete g_pkInputGroup;
Core::Get()->Shutdown();
return 0;
}
Reset the material pointer to allow reference counter base class to cleanup the object
when it is no longer used. Remember, this is only needed since we must make sure all
resources are correctly deallocated before deleting the render device, otherwise the smart
pointers will try to clean up when they run out of scope and cause problems since the engine
has already been shutdown by that time.
void InputListener::Input( const InputEvent *pkEvent )
{
if( ( ( pkEvent->m_iType == IE_KEYDOWN ) && ( pkEvent->m_aArgs[0].m_iData == KC_ESCAPE ) ) ||
( ( pkEvent->m_iType == IE_SYSEVENT ) && ( pkEvent->m_aArgs[0].m_iData == IE_SYSEVENT_KILL ) ) )
g_bRun = false;
}
|
|