Aprende a desarrollar aplicaciones gráficas 2D y 3D paso a paso.
Programacion Grafica: Desarrollo 2D/3D con C++ y DirectX/OpenGL/GLUT/SDL - Windows/Linux


  Crear una cuenta
 • Portada • Descargas • Tu Cuenta • 
Menú
 Portada
 Noticias
 Archivo de Noticias
 Temas
 Descargas
 Inicio
 Ver Nuevas
 Más Popular
 Más Votadas
 Contenido
 Contenido
 Secciones
 Enciclopedia
 Revisiones
 FAQ
 Tus Opciones
 Tu Cuenta
 Mensajes Privados
 Recomiéndenos
 Buscar
 Diarios
 Contacto
 Enlaces Web
 Inicio
 Enviar Enlace
 Ver Nuevos
 Más Popular
 Más Valorados
 Estadísticas
 Inicio
 Detalladas
 Top 10
 
Estadísticas
 
Tutorial 07 - Carga de Texturas. 
DirectX/Opengl

Vamos a ver en este ejemplo cómo cargar imágenes o también llamadas texturas. Usaremos la librería freeimage: http://freeimage.sourceforge.net/ que es gratuita y multiplataforma y nos permitirá leer ficheros gráficos de diferentes formatos (BMP,JPEG,GIF,TGA,PCX,PNG...).



En primer lugar debo indicar que para usar la librería freeimage es necesaria enlazar con ella. Los proyectos ya están preparados para ello, sólo que en Visual C, tendréis que especificar en qué directorio habéis instalado la librería, de la misma forma que se hace para configurar el entorno para que encuentre la librería DirectX. Revisad el Tutorial 4 para ver cómo hacerlo. En Dev-C++ tenéis que instalar del paquete FreeImage.DevPak

Definiremos una textura como una estructura con el nombre del fichero y un número que indica la posición dentro de un array declarado en el Driver de Vídeo. Tanto en la clase OpenGLVideoDriver como en DirectX9VideoDriver este array almacena cada textura creada y nosotros con idxTexture accedemos a ellas de forma indirecta.


///////////////////////////////////////////////////////////////////////////////
/// struct   Texture Estructura para gestionar las texturas.
///
/// rief   
/// author  Antonio Lucas Moreno version 1.0 date 27/10/2005 11:32:27
///////////////////////////////////////////////////////////////////////////////
struct Texture
{
    char            fileName[256];      ///< Nombre del fichero de textura.
    int             idxTexture;         ///< Índice al array donde se almacena la textura.
};

El método LoadTexture será el encargado de leer un fichero gráfico mediante la llamada a FreeImage_Load(). Sólo vamos a crear texturas para imágenes de 16 bits de color o superior, con lo que si tuvieran menos, la convertiríamos a 24 bits mediante FreeImage_ConvertTo24Bits() lo cual nos facilitará trabajar con 8 bits de color para cada componente.

Vemos a continuación el método LoadTexture() de la clase OpenGLVideoDriver que no difiere mucho del de DirectX9VideoDriver.


///////////////////////////////////////////////////////////////////////////////
///     LoadTexture: Crea una textura a partir de un fichero.
///
///     @param  char *fileName: Nombre del fichero de la textura.
///     @param  Texture &texture: Estructura a la que se copiará la información
///                 sobre la textura.
///
///     @return  int:   
///                     - -1  : error.
///                     - otro: correcto.
///////////////////////////////////////////////////////////////////////////////
int OpenGLVideoDriver::LoadTexture(char *fileName, Texture &texture)
{
    int idTexture= -1;
    char msgError[512];
    FREE_IMAGE_FORMAT imageFormat= FIF_UNKNOWN;
    FIBITMAP *pImage= NULL;
    FIBITMAP *pImageCopy;

    // Comprobamos el formato del fichero.
    imageFormat= FreeImage_GetFileType(fileName,0);
    if (imageFormat == FIF_UNKNOWN)
        imageFormat= FreeImage_GetFIFFromFilename(fileName);

    // Si es un formato soportado por la librera lo cargamos
    if ( (imageFormat != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(imageFormat) )
    {
        // Cargamos el fichero
        pImage= FreeImage_Load(imageFormat,fileName,0);
        if (pImage)
        {

            // Si la imagen es de menos de 16 bpp la convertimos
            if ( FreeImage_GetBPP(pImage) < 16 )
            {
                // Si no, convertimos la imagen a 24 bits
                pImageCopy= FreeImage_ConvertTo24Bits( pImage );
                FreeImage_Unload(pImage);
                pImage= pImageCopy;
            }

            // Creamos la textura
            idTexture= CreateTexture(pImage);
            FreeImage_Unload(pImage);
        }
    }

    if ( idTexture != -1)
    {
        strcpy( texture.fileName, fileName );
        m_TextureArray[ m_TextureRefs ]= idTexture;
        texture.idxTexture= m_TextureRefs++;
    }
    else
    {
        sprintf(msgError,"OpenGLVideoDriver::LoadTexture("%s"): error al cargar la textura.",fileName);
        System::ShowMessage("ERROR: ",msgError,true);
        texture.idxTexture= -1;
    }

    return texture.idxTexture;
}

LoadTexture el método LoadTexture() llama a CreateTexture() que es quién crea la textura según la librería gráfica. Recibe como parámetro un puntero a una estructura FIBITMAP de freeimage que contiene los datos del fichero leído.

  • OpenGL:
  • 
    ///////////////////////////////////////////////////////////////////////////////
    ///     CreateTexture Crea una textura a partir de un bitmap.
    ///
    ///     @param  FIBITMAP *pImage: Imagen a partir de la que se crear la textura.
    ///
    ///     @return  int:   
    ///                     - -1  : error.
    ///                     - otro: correcto.
    ///////////////////////////////////////////////////////////////////////////////
    int OpenGLVideoDriver::CreateTexture( FIBITMAP *pImage )
    {
        unsigned int idTexture;
        char msgError[512];
        int error=0;
        GLenum pixelFormat;
        unsigned int width, height, bpp;
    
        try
        {
            if (!pImage)
                throw -1; // error
    
            width = FreeImage_GetWidth (pImage);
            height= FreeImage_GetHeight(pImage);
            bpp   = FreeImage_GetBPP   (pImage);
    
            // Generamos una referencia para la textura
            CHECK_GL_ERROR( glGenTextures(1, &idTexture) );
    
            // Asociamos la referencia de la textura que se renderizar?
            CHECK_GL_ERROR( glBindTexture(GL_TEXTURE_2D, idTexture) );
    
            // GENERAMOS LA TEXTURA:
            // En este caso nosotros utilizaremos MIPMAPS.
            // ¿Qué es un MIPMAP?, para mejor rendimiento, en vez de filtrar las textura 
            // dinámicamente, al crear un mipmap, creamos varias texturas de diferentes 
            // tamaños (del original hacia más pequeño). OpenGL, decidirá en función de 
            // lo lejano que esté el objeto con esa textura, de qué mipmap utilizar.
            // OpenGL restringe las texturas a que sean cuadradas y potencias de 2 (glTexImage2D).
            // Con gluBuild2DMipmaps podemos saltarnos una o las dos restricciones anteriores.
            switch ( bpp )
            {
                case 32:
                    pixelFormat= GL_BGRA_EXT;
                    break;
                case 24:
                case 16:
                    pixelFormat= GL_BGR_EXT;
                    break;
                default:
                    throw -1; // error
            }
    
            // Copiamos el bitmap
            CHECK_GL_ERROR( gluBuild2DMipmaps(GL_TEXTURE_2D, bpp/8, width, height, pixelFormat, GL_UNSIGNED_BYTE,
                                              FreeImage_GetBits(pImage)) );
    
            // Alineamos los p?xeles en memoria.
            CHECK_GL_ERROR( glPixelStorei(GL_UNPACK_ALIGNMENT,1) );
    
            // Las dos siguientes funciones especifican cómo encaja los téxteles renderizados con
            // los píxeles de pantalla una vez realizada la proyección.
            CHECK_GL_ERROR( glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST) );
            // Sólo para texturas que NO son potencias de 2.
            CHECK_GL_ERROR( glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) );
        }
        catch (GLenum iError)
        {
            sprintf(msgError,"GLApplication::LoadTexture(): %s",(char*)gluErrorString(iError));
            System::ShowMessage("Error al cargar la textura",msgError,true);
            error= -1;
        }
        catch (int iError)
        {
            System::ShowMessage("Error al cargar la textura","GLApplication::LoadTexture():bpp incorrecto.",true);
            error= -1;
        }
    
        if (!error)
            return idTexture;
        else
            return error;
    }
    
  • DirectX:
  • 
    ///////////////////////////////////////////////////////////////////////////////
    ///     CreateTexture Crea una textura a partir de un bitmap.
    ///
    ///     @param  FIBITMAP *pImage: Imagen a partir de la que se creará la textura.
    ///
    ///     @return  int:   
    ///                     - NULL: error.
    ///                     - otro: correcto.
    ///////////////////////////////////////////////////////////////////////////////
    LPDIRECT3DTEXTURE9 DirectX9VideoDriver::CreateTexture( FIBITMAP *pImage )
    {
        HRESULT hResult= S_OK;
        LPDIRECT3DTEXTURE9 pIfaceTexture= NULL;
        D3DLOCKED_RECT destinationSurface;
        RECT region;
        UINT textureLevel=0;
        D3DFORMAT textureFormat;
        unsigned int width, height, bpp;
        FIBITMAP *pImageCopy;
    
        try
        {
            width = FreeImage_GetWidth (pImage);
            height= FreeImage_GetHeight(pImage);
            bpp   = FreeImage_GetBPP   (pImage);
    
            // Si el formato del pixel es de 32 bits sin canal alpha
            if ( m_D3DFormat == D3DFMT_X8R8G8B8 )
                textureFormat= D3DFMT_A8R8G8B8; // Añadimos el soporte para el canal alpha
            else
                textureFormat= m_D3DFormat;
    
            // Comprobamos si el tipo de formato de textura que deseamos crear,
            // es posible según el formato definido para el BackBuffer.
            hResult= m_pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT,
                                                D3DDEVTYPE_HAL,
    //                                          D3DDEVTYPE_REF,
                                                m_D3DFormat,            // Formato del BackBuffer
                                                D3DUSAGE_RENDERTARGET,
                                                D3DRTYPE_TEXTURE,
                                                textureFormat );        // Formato de la Textura
            if (hResult != S_OK)
                throw hResult;
    
            // Creamos la textura
            hResult= m_pD3DDevice->CreateTexture( width, height,
                                                textureLevel,           // Levels
                                                0,  // Usage
    //                                          D3DUSAGE_RENDERTARGET,  // Usage
                                                textureFormat,          // Formato de la Textura
    //                                          D3DPOOL_DEFAULT,        // Pool
                                                D3DPOOL_MANAGED,        // Pool
                                                &pIfaceTexture, NULL );
            if (hResult != S_OK)
                throw hResult;
    
            region.left     = 0;
            region.top      = 0;
            region.right    = width;
            region.bottom   = height;
    
            // Bloqueamos la superficie destino
            hResult= pIfaceTexture->LockRect( textureLevel, &destinationSurface,
                                                ®ion, D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK );
            if (hResult != S_OK)
                throw hResult;
    
            BYTE* pBits= (BYTE*)destinationSurface.pBits;
    
            // Copiamos los bytes según el formato de pixel del BackBuffer
            switch ( m_D3DFormat )
            {
                case D3DFMT_A8R8G8B8:   // 32-bit con canal alpha
                case D3DFMT_X8R8G8B8:   // 32-bit BGR
                    switch ( bpp )
                    {
                        case 24: // 24 -> 32
                        case 16: // 16 -> 32
                            pImage= FreeImage_ConvertTo32Bits( pImage );
                            break;
                    }
                    break;
    
                case D3DFMT_R8G8B8:     // 24-bit BGR
                    switch ( bpp )
                    {
                        case 32: // 32 -> 24
                        case 16: // 16 -> 24
                            pImage= FreeImage_ConvertTo24Bits( pImage );
                            break;
                    }
                    break;
    
                case D3DFMT_R5G6B5:
                    // 16-bit con 5 bits para el rojo, 6 para el verde y 5 para el azul. 
                    pImageCopy= FreeImage_ConvertTo16Bits565( pImage );
                    FreeImage_Unload(pImage);
                    pImage= pImageCopy;
                    break;
    
                case D3DFMT_X1R5G5B5:
                case D3DFMT_A1R5G5B5:
                    // 16-bit con 5 bits para cada color y 1 bit para el canal alpha. 
                    pImageCopy= FreeImage_ConvertTo16Bits555( pImage );
                    FreeImage_Unload(pImage);
                    pImage= pImageCopy;
                    break;
    
                default:
                    // Formato no válido
                    throw E_FAIL;
            }
    
            // Copiamos el mapa de bits a la textura
            memcpy( pBits, FreeImage_GetBits(pImage), (FreeImage_GetBPP(pImage)/8)*width*height );
    
            // Desbloqueamos la superficie
            hResult= pIfaceTexture->UnlockRect( textureLevel );
            if (hResult != S_OK)
                throw hResult;
        }
        catch (HRESULT error)
        {
    #if defined (_MSC_VER) && (_MSC_VER < 1310)
            // No funciona la gestión de errores de DirectX con Visual Studio 6 o inferior
            System::ShowMessage( "DirectX9VideoDriver::CreateTexture()",
                                 "Error al cargar la textura", true );
    #else
            System::ShowMessage( "DirectX9VideoDriver::CreateTexture()",
                                (char*)DXGetErrorDescription9(error), true );
    #endif
            if ( pIfaceTexture )
            {
                pIfaceTexture->UnlockRect( textureLevel );
                pIfaceTexture->Release();
                pIfaceTexture= NULL;
            }
        }
    
        return pIfaceTexture;
    }
    

    Posteriormente, para hacer uso de la textura, hay que habilitar el uso de éstas con EnableTexture() y seleccionar la textura que vamos a usar SetTexture().

    A continuación, se "mapea" la textura sobre los vértices. Especificamos qué pixel de la imagen se asocia al vértice que se va a renderizar. Es como colocar una pegatina, especificando qué esquina de la imagen se asocia con qué vértice. Para ello el valor de las dimensiones de la textura varían de 0 a 1 tanto a lo ancho como a lo largo. El valor (0,0) corresponde con la esquina inferior izquierda de la imagen y el (1,1) con la esquina superior derecha de la imagen. Para ello se han definido dos nuevas entradas en la estructura Vertex (su,tv) que almacenan los valores descritos anteriormente.

    
    ///////////////////////////////////////////////////////////////////////////////
    /// struct  Vertex Estructura del vértice.
    ///
    /// rief   
    /// author  Antonio Lucas Moreno version 1.01 date 26/08/2005 9:24:19
    ///////////////////////////////////////////////////////////////////////////////
    struct Vertex
    {
        float           x, y, z;            ///< Coordenadas del vértice.
        ulColorRGBA     color;              ///< Color del vértice.
    // ********************************* NEW **************************************
        float           su, tv;             ///< Coordenadas de textura.
    // ****************************************************************************
    };
    
    ///////////////////////////////////////////////////////////////////////////////
    ///     RenderObjects: Dibuja las geometrías.
    ///
    ///     @param  nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::RenderObjects()
    {
        Vertex vertexArray[8];
    
        if ( m_pVideoDriver )
        {
            m_pVideoDriver->EnableLighting  ( false );
    // ********************************* NEW **************************************
            m_pVideoDriver->EnableTexture   ( true  );
            m_pVideoDriver->SetTexture      ( m_IdTexture );
    // ****************************************************************************
    
            // Definimos un cuadrado (formado por dos triángulos consecutivos)
            //
            // v0   v2
            //  *---*
            //  |  /|
            //  |/  |
            //  *---*
            // v1   v3
            //
            vertexArray[0].x= 150, vertexArray[0].y= 400, vertexArray[0].z= 0;  // v0
            vertexArray[1].x= 150, vertexArray[1].y=  50, vertexArray[1].z= 0;  // v1
            vertexArray[2].x= 450, vertexArray[2].y= 400, vertexArray[2].z= 0;  // v2
            vertexArray[3].x= 450, vertexArray[3].y=  50, vertexArray[3].z= 0;  // v3
    
    // ********************************* NEW **************************************
            vertexArray[0].su= 0, vertexArray[0].tv= 1; // v0
            vertexArray[1].su= 0, vertexArray[1].tv= 0; // v1
            vertexArray[2].su= 1, vertexArray[2].tv= 1; // v2
            vertexArray[3].su= 1, vertexArray[3].tv= 0; // v3
    // ****************************************************************************
    
            m_pVideoDriver->RenderVertexArray( eTriangleStrip, (BYTE*)vertexArray,
                                                sizeof(Vertex), 0, 4, eFVF_XYZ|eFVF_DIFFUSE|eFVF_TEX1 );
        }
    }
    

    Por último, que para liberar una textura se podría hacer llamando al método ReleaseTexture() de IVideoDriver, pero de momento no es necesario ya que al finalizar el Driver de Vídeo liberar todos los recursos incluídas las texturas creadas.

    Podéis descargaros el ejemplo: tutorial-07.zip



    Nota: Compartir en Facebook
    Enviado el Martes, 04 septiembre a las 20:22:57 por administrador
     
    Enlaces Relacionados
    · Más Acerca de DirectX/Opengl
    · Noticias de administrador


    Noticia más leída sobre DirectX/Opengl:
    Tutorial 16 - Movimiento-3D - (Tercera Persona)

     
    Votos del Artículo
    Puntuación Promedio: 4
    votos: 2


    Por favor tómate un segundo y vota por este artículo:
    Excelente
    Muy Bueno
    Bueno
    Regular
    Malo

     
    Opciones

     Versión Imprimible  Versión Imprimible

     
    "Tutorial 07 - Carga de Texturas." | Entrar / Crear Cuenta | 0 Comentarios
    Los comentarios son propiedad de quien los envió. No somos responsables por su contenido.

    No se permiten comentarios Anónimos, Regístrese por favor

    Sitio potenciado por NukeProjects.Net        NukeStilo 1.0 se basa en PHP-Nuke        Theme Diseñado por NukeMods

    © Antonio Lucas Moreno