Click here to Skip to main content
Click here to Skip to main content
Go to top

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

, 22 Oct 2010
Rate this:
Please Sign up or sign in to vote.
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 wrap Repeating Clamping

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()
{
   //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.

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.

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 )
    {
        //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.

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.

<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:

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:
   {
     //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)

Share

About the Author

Eduardo Tucci
Software Developer
Brazil Brazil
I live in Matão, a small city in Brazil. I studied as Programmer in a College for Software Development in Database.
After finishing the College I have been working with java, c# and Computer Graphics with searches for OpenGL.

Comments and Discussions

 
GeneralMy vote of 5 PinmemberAbhinav S23-Oct-10 18:08 
GeneralMy vote of 5 PinmemberGPUToaster28-Jul-10 19:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 22 Oct 2010
Article Copyright 2010 by Eduardo Tucci
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid