Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / multimedia / OpenGL

OAG Library (OpenGL) Part 2.3 - Drawing 2D Textures Using the Mouse and Programatically

4.29/5 (6 votes)
22 Oct 2010CPOL3 min read 34.5K   1.3K  
This tutorial shows library code for 2D Textures and how to draw them programatically using the mouse in an MFC application.

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

No wrapRepeatingClamping

Image 1

Image 2

Image 3

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:

C++
oag::ObjectsMappingTable*    pObjectsMappingTable;
oag::OAGScene*                m_pScene;

Operations for the document:

C++
void CreateLibraryObjects();
void UnloadLibraryObjects();

Constructor and destructor:

C++
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()
{
   //Deletes the scene and all objects from the memory
   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.

C++
BOOL COAGMFCDoc::OnNewDocument()
{
  if (!CDocument::OnNewDocument())
   return FALSE;
 
 
  //Deleting all library objects when a new document is started.
 
  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.

Image 4

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.

C++
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.

Image 5

Defining Texture Filters

ENUM OAG_TEXTURE_FILTEROpenGL Command
MAG_FILTER_NEARESTglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
MAG_FILTER_LINEARglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
MAG_FILTER_GL_NEAREST_MIPMAP_LINEARglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_LINEAR)
MAG_FILTER_GL_NEAREST_MIPMAP_NEARESTglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_NEAREST);
MAG_FILTER_GL_LINEAR_MIPMAP_LINEARglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR)
MAG_FILTER_GL_LINEAR_MIPMAP_NEARESTglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST)
MIN_FILTER_NEARESTglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
MIN_FILTER_LINEARglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
MIN_FILTER_GL_NEAREST_MIPMAP_LINEARglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR)
MIN_FILTER_GL_NEAREST_MIPMAP_NEARESTglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST)
MIN_FILTER_GL_LINEAR_MIPMAP_LINEARglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR)
MIN_FILTER_GL_LINEAR_MIPMAP_NEARESTglTexParameteri(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.

C++
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_WRAPOpenGL Command
WRAP_S_REPEATglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
WRAP_S_CLAMPglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
WRAP_T_REPEATglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
WRAP_T_CLAMPglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)

Adding Wrap Repeating to the Texture

C++
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

C++
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.

Image 6

C++
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 )
    {
        //Clear filters and wraps set for the texture
        t1->ClearFiltersAndWraps();

        std::vector<oag::OAGTexture::TEXTURE_FILTER> filterList;

        switch( m_textureRenderMode)
        {
            case NORMAL:
                {
                    //Filters
                    filterList.push_back( MAG_FILTER_LINEAR);
                    filterList.push_back( MIN_FILTER_LINEAR);
                }
                break;
            case REAPEATING:
                {
                    //Filters
                    filterList.push_back( MAG_FILTER_LINEAR);
                    filterList.push_back( MIN_FILTER_LINEAR);

                    //Reapeating
                    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 );//Value for texture reapeating
    
                    t1->SetTextureMode( GL_MODULATE );
                }
                break;
            case CLAMPING:
                {
                    //Filters
                    filterList.push_back( MAG_FILTER_LINEAR);
                    filterList.push_back( MIN_FILTER_LINEAR);

                    //Clamping
                    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 ); //Value for texture clamping

                    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.

Image 7

C++
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 )
    {
        //Clear filters and wraps set for the texture
        t1->ClearFiltersAndWraps();

        std::vector<oag::OAGTexture::TEXTURE_FILTER> filterList;

        switch( m_textureRenderMode)
        {
            case NORMAL:
            {
                //Filters
                filterList.push_back( MAG_FILTER_LINEAR);
                filterList.push_back( MIN_FILTER_LINEAR);
            }
            break;
        case REAPEATING:
            {
                //Filters
                filterList.push_back( MAG_FILTER_LINEAR);
                filterList.push_back( MIN_FILTER_LINEAR);
    
                //Reapeating
                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 );//Value for texture reapeating
        
                t1->SetTextureMode( GL_MODULATE );
            }
            break;
        case CLAMPING:
            {
                //Filters
                filterList.push_back( MAG_FILTER_LINEAR);
                filterList.push_back( MIN_FILTER_LINEAR);
    
                //Clamping
                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 ); //Value for texture clamping
    
                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.

XML
<OAGLibrary>
<?xml version="1.0" encoding="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:

Image 8

Creating the Texture Vertices

C++
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

C++
void oag::OAGTexture::CreateTextureCoordinates()
{
  m_nTextureCoordinates.resize(0);

  switch( m_enumTextureMapping)
  {
   case OAG_TEXTURE_MAP_RECT:
   {
     //Rectangle
     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:
   {
     //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;
  }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)