Introduction
In this tutorial, we will see how to draw 2D Textures. You must download the library to compile the sample. Click here to go to the download page. Using OAG_2D, you can save and open XML files (*.oagxml).
2D Textures And Wrap
Drawing 2D Textures
To draw fonts using the library, you need to create an instance of oag::TextureMappingTable
to store a texture and to create an instance of TextureMapping
. The class oag::TextureMappingTable
manages the textures used to draw. Once you choose a texture and store it in the class oag::TextureMappingTable
, it is added in an array list of textures in the class oag::TextureMappingTable
. The classes available for texture mapping are oag::OAGRectangleMapping
and oag::OAGTriangleMapping
. The class oag::OAGRectangleMapping
draws a texture as a rectangle, and the class oag::OAGTriangleMapping
draws a texture as a triangle. The classes oag::OAGRectangleMapping
and oag::OAGTriangleMapping
use a texture stored in the class oag::TextureMappingTable
to draw a texture on the screen.
Setting Up the Document Class
Members for the document:
oag::ObjectsMappingTable* pObjectsMappingTable;
oag::OAGScene* m_pScene;
Operations for the document:
void CreateLibraryObjects();
void UnloadLibraryObjects();
Constructor and destructor:
COAGMFCDoc::COAGMFCDoc()
:m_pScene(NULL)
,m_pObjectsMappingTable(NULL)
{
CreateLibraryObjects();
}
COAGMFCDoc::~COAGMFCDoc()
{
UnloadLibraryObjects();
}
void COAGMFCDoc::CreateLibraryObjects()
{
if( m_pObjectsMappingTable == NULL)
m_pObjectsMappingTable = new oag::ObjectsMappingTable();
if( m_pScene == NULL )
{
m_pScene = new oag::OAGScene();
m_pScene->SetFontMappingTable(
m_pObjectsMappingTable->GetFontMappingTable() );
m_pScene->SetTextureMappingTable(
m_pObjectsMappingTable->GetTextureMappingTable() );
}
}
void COAGMFCDoc::UnloadLibraryObjects()
{
if ( m_pScene )
{
m_pScene->DeleteAllObjects();
delete m_pScene;
m_pScene = NULL;
}
if ( m_pObjectsMappingTable )
{
delete m_pObjectsMappingTable;
m_pObjectsMappingTable = NULL;
}
}
When a new document is created, we need to delete all the objects and create them again.
BOOL COAGMFCDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
UnloadLibraryObjects();
CreateLibraryObjects();
UpdateAllViews(NULL);
return TRUE;
}
Inserting a Texture
To insert a Texture, click on the TableObjects menu, click on Texture, and choose a texture file.
For the demo, we will use one or two textures. If you choose one texture, you will see the object using one Texture
. If you choose two textures, you can draw objects using MultiTexture
. The filters for the texture are created when you choose a texture by clicking in a command menu item.
void COAGMFCDoc::OnInsertTexture()
{
CString filter;
filter.LoadString( IDS_TEXTURE_FILTER );
CFileDialog dlg(TRUE, "*.*", NULL,
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST, filter );
if(dlg.DoModal() == IDOK)
{
CString strFileName = dlg.GetPathName().GetString();
POSITION pos = GetFirstViewPosition();
COAGMFCView* pView = (COAGMFCView*) GetNextView(pos);
if ( pView->m_pWinGraphicContext->MakeCurrent() )
{
oag::OAGTexture* pTexture =
oag::OAGTextureLoader::LoadTextureFromDisk( strFileName.GetString() );
if( pTexture )
{
if( m_pScene->GetTextureMappingTable()->m_ListTexture.size() < 1)
pTexture->SetTextureName("Image1");
else
pTexture->SetTextureName("Image2");
oag::TextureMappingTable* pTexMapTable =
m_pObjectsMappingTable->GetTextureMappingTable();
if ( pTexMapTable == NULL || !pTexMapTable->AddTexture( pTexture ) )
delete pTexture;
else
pTexMapTable->AddTexture( pTexture );
}
pView->m_pWinGraphicContext->DeleteCurrent();
}
}
}
Inserting a 2D Texture
Now we can get the texture from m_pTextureMappingTable
using m_pScene->GetTextureMappingTable()->GetTexture("Image1") )
. Remember that Image1
is a texture name given for the texture loaded above.
Defining Texture Filters
ENUM OAG_TEXTURE_FILTER | OpenGL Command |
---|
MAG_FILTER_NEAREST | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) |
MAG_FILTER_LINEAR | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) |
MAG_FILTER_GL_NEAREST_MIPMAP_LINEAR | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR) |
MAG_FILTER_GL_NEAREST_MIPMAP_NEAREST | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_NEAREST); |
MAG_FILTER_GL_LINEAR_MIPMAP_LINEAR | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR) |
MAG_FILTER_GL_LINEAR_MIPMAP_NEAREST | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST) |
MIN_FILTER_NEAREST | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) |
MIN_FILTER_LINEAR | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) |
MIN_FILTER_GL_NEAREST_MIPMAP_LINEAR | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR) |
MIN_FILTER_GL_NEAREST_MIPMAP_NEAREST | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST) |
MIN_FILTER_GL_LINEAR_MIPMAP_LINEAR | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR) |
MIN_FILTER_GL_LINEAR_MIPMAP_NEAREST | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST) |
Adding Filters to the Texture
The function GetTexture
is used to choose a texture. In this case, we will use Image1.
oag::OAGTexture* t1 = GetTexture("Image1");
std::vector<OAG_TEXTURE_FILTER> filterList;
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
t1->SetTextureMode(GL_MODULATE);
t1->SetTextureFilter( filterList );
Defining Texture Wraps
ENUM OAG_TEXTURE_WRAP | OpenGL Command |
---|
WRAP_S_REPEAT | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT) |
WRAP_S_CLAMP | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP) |
WRAP_T_REPEAT | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT) |
WRAP_T_CLAMP | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP) |
Adding Wrap Repeating to the Texture
oag::OAGTexture* t1 = GetTexture("Image1");
std::vector<OAG_TEXTURE_FILTER> filterList;
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
t1->SetTextureFilter( filterList );
std::vector<OAG_TEXTURE_WRAP> wrapList;
wrapList.push_back( WRAP_S_REPEAT);
wrapList.push_back( WRAP_T_REPEAT);
t1->SetTextureWrap( wrapList );
t1->SetWrapValue( 4 );
t1->SetTextureMode(GL_MODULATE);
Adding Wrap Clamping to the Texture
oag::OAGTexture* t1 = GetTexture("Image1");
std::vector<OAG_TEXTURE_FILTER> filterList;
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
t1->SetTextureFilter( filterList );
std::vector<OAG_TEXTURE_WRAP> wrapList;
wrapList.push_back( WRAP_S_CLAMP);
wrapList.push_back( WRAP_T_CLAMP);
t1->SetTextureWrap( wrapList );
t1->SetWrapValue( 4 );
t1->SetTextureMode(GL_MODULATE);
Rectangle Mapping
To insert a 2D Texture of type Rectangle Mapping, select the TexureMapping menu, choose RasterImage Rectangle, or RasterImage Rectangle Repeating, or RasterImage Rectangle Clamping, and click on the screen to insert a rectangle texture mapping.
void CRasterImageRectTool::AddAllVerticesToScene()
{
m_pWinGraphicContext->MakeCurrent();
oag::OAGRectangleMapping* tex = new oag::OAGRectangleMapping();
oag::OAGVector3f vec1 = m_arrVector[0];
tex->SetPosition( oag::OAGVector3f( vec1.m_X, vec1.m_Y, vec1.m_Z ) );
oag::OAGTexture* t1 = m_pScene->GetTextureMappingTable()->GetTexture("Image1");
if ( t1 )
{
t1->ClearFiltersAndWraps();
std::vector<oag::OAGTexture::TEXTURE_FILTER> filterList;
switch( m_textureRenderMode)
{
case NORMAL:
{
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
}
break;
case REAPEATING:
{
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
std::vector<oag::OAGTexture::OAG_TEXTURE_WRAP> wrapList;
wrapList.push_back( WRAP_S_REPEAT);
wrapList.push_back( WRAP_T_REPEAT);
t1->SetTextureWrap( wrapList );
t1->SetWrapValue( 6 );
t1->SetTextureMode( GL_MODULATE );
}
break;
case CLAMPING:
{
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
std::vector<oag::OAGTexture::OAG_TEXTURE_WRAP> wrapList;
wrapList.push_back( WRAP_S_CLAMP);
wrapList.push_back( WRAP_T_CLAMP);
t1->SetTextureWrap( wrapList );
t1->SetWrapValue( 4 );
t1->SetTextureMode( GL_MODULATE );
}
break;
}
t1->SetTextureFilter( filterList );
t1->SetTextureHeight(256);
t1->SetTextureWidth(256);
t1->BuildTexture();
}
tex->SetTexture(t1);
m_pScene->AddObject( tex );
m_pWinGraphicContext->DeleteCurrent();
}
To insert a 2D texture of type Triangle Mapping, select the TexureMapping menu, choose RasterImage Triangle, or RasterImage Triangle Repeating, or RasterImage Triangle Clamping, and click on the screen to insert a triangle texture mapping.
void CRasterImageTriangleTool::AddAllVerticesToScene()
{
m_pWinGraphicContext->MakeCurrent();
oag::OAGTriangleMapping* tex = new oag::OAGTriangleMapping();
oag::OAGVector3f vec1 = m_arrVector[0];
tex->SetPosition( oag::OAGVector3f( vec1.m_X, vec1.m_Y, vec1.m_Z ) );
oag::OAGTexture* t1 = m_pScene->GetTextureMappingTable()->GetTexture("Image1");
if ( t1 )
{
t1->ClearFiltersAndWraps();
std::vector<oag::OAGTexture::TEXTURE_FILTER> filterList;
switch( m_textureRenderMode)
{
case NORMAL:
{
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
}
break;
case REAPEATING:
{
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
std::vector<oag::OAGTexture::OAG_TEXTURE_WRAP> wrapList;
wrapList.push_back( WRAP_S_REPEAT);
wrapList.push_back( WRAP_T_REPEAT);
t1->SetTextureWrap( wrapList );
t1->SetWrapValue( 6 );
t1->SetTextureMode( GL_MODULATE );
}
break;
case CLAMPING:
{
filterList.push_back( MAG_FILTER_LINEAR);
filterList.push_back( MIN_FILTER_LINEAR);
std::vector<oag::OAGTexture::OAG_TEXTURE_WRAP> wrapList;
wrapList.push_back( WRAP_S_CLAMP);
wrapList.push_back( WRAP_T_CLAMP);
t1->SetTextureWrap( wrapList );
t1->SetWrapValue( 4 );
t1->SetTextureMode( GL_MODULATE );
}
break;
}
t1->SetTextureFilter(filterList);
t1->SetTextureHeight(256);
t1->SetTextureWidth(256);
t1->BuildTexture();
}
tex->SetTexture( t1 );
m_pScene->AddObject( tex );
m_pWinGraphicContext->DeleteCurrent();
}
The XML File
In the XML shown below, the node Tables
stores a node Textures
. The node Textures
stores the textures used for drawing a 2D texture. For this sample, we used honda.bmp. The node <Texture Name="Image1" FileName="honda.bmp"/>
shows this.
The node Objects
stores the 2D textures to draw on the screen. The node TextureMapping
shows this. The node <UseTexture Name="Image1"/>
in TextureMappings
means that the two 2D textures will use the texture image1
to draw when this XML is loaded.
<OAGLibrary>
="1.0"="ISO-8859-1"
<OAGLibrary>
<Scene>
<Tables>
<Textures>
<Texture Name="Image1" FileName="honda-pcx.jpg"/>
</Textures>
</Tables>
<Objects>
<TextureMapping Name="" Type="Rectangle">
<Transform>
<Translation x="5." y="49." z="0."/>
</Transform>
<UseTexture Name="Image1"/>
</TextureMapping>
<TextureMapping Name="" Type="Triangle">
<Transform>
<Translation x="589." y="52." z="0."/>
</Transform>
<UseTexture Name="Image1"/>
</TextureMapping>
</Objects>
</Scene>
</OAGLibrary>
After loading the XML, you will see these two textures:
Creating the Texture Vertices
void oag::OAGTexture::CreateTextureVertices()
{
switch( m_enumTextureMapping )
{
case OAG_TEXTURE_MAP_RECT:
{
m_nNumberOfPoints = 4;
m_nTextureVertices.resize( 0 );
m_nTextureVertices.reserve( m_nNumberOfPoints );
m_nTextureVertices.push_back(
oag::OAGVector3d(m_position.m_X, m_position.m_Y, 0));
m_nTextureVertices.push_back( oag::OAGVector3d( m_position.m_X,
m_position.m_Y + m_nHeight, 0));
m_nTextureVertices.push_back( oag::OAGVector3d(m_position.m_X + m_nWidth,
m_position.m_Y + m_nHeight, 0) );
m_nTextureVertices.push_back( oag::OAGVector3d(m_position.m_X +
m_nWidth, m_position.m_Y) );
}
break;
case OAG_TEXTURE_MAP_TRIANGLE:
{
m_nNumberOfPoints = 3;
m_nTextureVertices.resize( 0 );
m_nTextureVertices.reserve( m_nNumberOfPoints );
m_nTextureVertices.push_back(
oag::OAGVector3d(m_position.m_X, m_position.m_Y, 0 ) );
m_nTextureVertices.push_back( oag::OAGVector3d(m_position.m_X +
m_nWidth, m_position.m_Y, 0) );
m_nTextureVertices.push_back( oag::OAGVector3d(m_position.m_X +
(m_nWidth/2.f), m_position.m_Y + m_nHeight, 0) );
}
break;
}
}
Creating the Texture Coordinates
void oag::OAGTexture::CreateTextureCoordinates()
{
m_nTextureCoordinates.resize(0);
switch( m_enumTextureMapping)
{
case OAG_TEXTURE_MAP_RECT:
{
m_nNumberOfCoordinates = 8;
float values[8] = { 0, 0, 0, m_fWrapValue, m_fWrapValue,
m_fWrapValue, m_fWrapValue, 0 };
m_nTextureCoordinates.reserve(8);
for(int i=0; i < 8; i++)
m_nTextureCoordinates.push_back( values[i] );
}
break;
case OAG_TEXTURE_MAP_TRIANGLE:
{
m_nNumberOfCoordinates = 6;
float values[6] = { 0, 0, m_fWrapValue, 0, 0.5, m_fWrapValue };
m_nTextureCoordinates.reserve(6);
for(int i=0; i < 6; i++)
m_nTextureCoordinates.push_back( values[i] );
}
break;
}
}