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 22 - Texto 2D 
DirectX/Opengl

Este tutorial quizás debería haberlo hecho al principio cuando veíamos las 2D, pero bueno, nunca es tarde.

Vamos a dibujar texto 2D mediante el uso de una textura con el juego de caracteres ASCII del idioma en el que trabajemos.



Para obtener dicha textura lo que hice fué usar un procesador de texto e ir escribiendo los caracteres en orden ASCII creciente, esto es, mediante la combinación de teclas ALT-GR+[CODIGO-ASCII] se iban mostrando los caracteres. Usé una fuente monoespacio (por ejemplo Courier New), lo que quiere decir, es que TODOS los caracteres los representa con EL MISMO ANCHO. Lo cual es muy importante para poder mapear luego la textura.

Por comodidad, la textura TABLA-ASCII-160x713x24.bmp contiene 10 caracteres por fila. Esto nos permite comprobar más fácilmente cómo se realizan los cálculos al dividir por 10.

La idea es sencilla, calculamos cuántos píxeles de ancho y alto tiene cada carácter. Y el salto que habrá que realizar para encontrar el carácter no es más que obtener su código ASCII y dividir por 10 para saber en qué fila se encuentra y posteriormente el resto de la división nos dará su ubicación en la fila.

Debido a que los primeros caractes ASCII son de control (no imprimibles) el primer carácter representado es el espacio en blanco, y por ello se lo restamos a la hora de obtener el desplazamiento dentro de la textura.

Utilizaremos la técnica de color-key para poder dibujar el texto sobre otros elementos.

Se ha definido la clase Font2D para gestionar el uso del texto. Básicamente lo único que tiene es la función LoadTexture() para cargar la textura y fijar los parámetros que definen sus dimensiones y los elementos que la componen y la función de renderizado.


    ///////////////////////////////////////////////////////////////////////////////
    ///     LoadTexture: Inicializa las dimensiones del texto.
    ///
    ///     @param  char *fileName: Nombre del fichero de la textura.
    ///     @param  int width: Ancho de la textura.
    ///     @param  int height: Alto de la textura.
    ///     @param  int charsPerLine: Nº de caracteres por línea en el bitmap.
    ///     @param  int totalChars: Nº total de caracteres en el bitmap.
    ///     @param  ulColorRGBA colorKey: Color de la textura que será transparente.
    ///
    ///     @return  int:   
    ///                     - -1  : error.
    ///                     - otro: correcto.
    ///////////////////////////////////////////////////////////////////////////////
    int Font2D::LoadTexture( char *fileName, int width, int height, int charsPerLine,
                             int totalChars, ulColorRGBA colorKey )
    {
        IVideoDriver *pVideoDriver= IVideoDriver::GetVideoDriver();

        if ( pVideoDriver )
        {
            m_CharsPerLine  = charsPerLine;
            m_WidthChar     = (width  / (float)m_CharsPerLine );
            m_HeightChar    = (height / (float)(totalChars/m_CharsPerLine) );
            m_WidthBitmap   = width;
            m_HeightBitmap  = height;

            return pVideoDriver->LoadTexture( fileName, m_FontTexture, colorKey );
        }
        else
        {
            return -1;
        }
    }

    ///////////////////////////////////////////////////////////////////////////////
    ///     Render2DText: Muestra el texto en pantalla.
    ///
    ///     @param  int x: Coordenada x de pantalla donde se mostrará el texto.
    ///     @param  int y: Coordenada y de pantalla donde se mostrará el texto.
    ///     @param  char *text: Mensaje de texto a mostrar.
    ///     @param  unsigned int rgbColor: Color del texto a mostrar.
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void Font2D::Render2DText( int x, int y, char *text, unsigned int rgbColor )
    {
        int len;
        float xOffset, yOffset;
        static VertexFont2D vertexArray[4];

        IVideoDriver *pVideoDriver= IVideoDriver::GetVideoDriver();

        if ( pVideoDriver )
        {
            if ( text )
            {
                len= strlen(text);

                pVideoDriver->EnableBlending( true );
                pVideoDriver->SetBlending( /*fuente*/eBlendSrcAlpha,
                                          /*destino*/eBlendOneMinusSrcAlpha );

                for ( int i=0; ifloat)( ((unsigned char)text[i]-'' '')%m_CharsPerLine );
                    yOffset= (float)( ((unsigned char)text[i]-'' '')/m_CharsPerLine );

                    // Definimos un cuadrado con dos triángulos.
                    //
                    // v0   v2
                    //  *  /*
                    //  | / |
                    //  |/  |
                    //  *   *
                    // v1   v3
                    //

                    if ( pVideoDriver->GetAxisSystem() == eLeftHanded )
                    {
                        // Con sistema de ejes de mano izquierda, habría que recorrer 
                        // los vértices en el orden 1,0,2,3 en lugar de 0,1,2,3.
                        // Para evitar eso, lo que hacemos es que se rendericen las
                        // caras traseras, ya que lo que ocurre, al cambiar de ejes, 
                        // es que se cambia el sentido que define la cara frontal y trasera.
                        pVideoDriver->SetCullFaces( eCullFront );
                    }

                    // v0
                    vertexArray[0].color.rgba= rgbColor;

                    vertexArray[0].su= m_WidthChar*xOffset/m_WidthBitmap;
                    vertexArray[0].tv= 1.0f-m_HeightChar*yOffset/m_HeightBitmap;

                    vertexArray[0].x= x + m_WidthChar*i;
                    vertexArray[0].y= y + m_HeightChar;
                    vertexArray[0].z= 0.0f;

                    // v1
                    vertexArray[1].color.rgba= rgbColor;

                    vertexArray[1].su= m_WidthChar*xOffset/m_WidthBitmap;
                    vertexArray[1].tv= 1.0f-m_HeightChar*(yOffset+1)/m_HeightBitmap;

                    vertexArray[1].x= x + m_WidthChar*i;
                    vertexArray[1].y= y;
                    vertexArray[1].z= 0.0f;

                    // v2
                    vertexArray[2].color.rgba= rgbColor;

                    vertexArray[2].su= m_WidthChar*(xOffset+1)/m_WidthBitmap;
                    vertexArray[2].tv= 1.0f-m_HeightChar*yOffset/m_HeightBitmap;

                    vertexArray[2].x= x + m_WidthChar*(i+1);
                    vertexArray[2].y= y + m_HeightChar;
                    vertexArray[2].z= 0.0f;

                    // v3
                    vertexArray[3].color.rgba= rgbColor;

                    vertexArray[3].su= m_WidthChar*(xOffset+1)/m_WidthBitmap;
                    vertexArray[3].tv= 1.0f-m_HeightChar*(yOffset+1)/m_HeightBitmap;

                    vertexArray[3].x= x + m_WidthChar*(i+1);
                    vertexArray[3].y= y;
                    vertexArray[3].z= 0.0f;

                    pVideoDriver->RenderVertexArray( eTriangleStrip, (BYTE*)vertexArray,
                                                     sizeof(VertexFont2D), 0, 4,
                                                     eFVF_XYZ|eFVF_DIFFUSE|eFVF_TEX1 );
                }

                pVideoDriver->EnableBlending( false );
            }
        }
    }

En la aplicación principal, cargamos la textura del texto.


    ///////////////////////////////////////////////////////////////////////////////
    ///     OnCreateWindow: Función invocada al iniciarse el programa y DESPUÉS de crear la ventana.
    ///
    ///     @param  nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::OnCreateWindow( WindowProps windowProps )
    {
        ulColorRGBA colorKey;
        colorKey.rgba= COLOR_RGBA(0x00,0x00,0x00,0xff); // Negro

        if ( m_pVideoDriver )
        {
            m_pVideoDriver->Init( windowProps );

            // Revisad las rutas si no cargasen las texturas
    // ********************************* NEW **************************************
            m_2DFont.LoadTexture(
    #if defined (_MSC_VER)
                "../../textures/TABLA-ASCII-160x713x24.bmp",
    #else
                "../../../textures/TABLA-ASCII-160x713x24.bmp",
    #endif
                WIDTH_BITMAP_TEXT, HEIGHT_BITMAP_TEXT, 10, 230, colorKey );
    // ****************************************************************************
        }
    }

Fijaros como al definir la proyeción ortogonal (2D), hemos desplazado el origen de coordenadas a la esquina superior izquierda. Esto supone, que para pintar texto en pantalla, la coordenada x toma valores positivos (de izquierda a derecha) pero la coordenada vertical y, toma valores NEGATIVOS.


    ///////////////////////////////////////////////////////////////////////////////
    ///     OnRender: Esta función es invocada cuando el sistema está listo para renderizar.
    ///
    ///     @param  nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::OnRender()
    {
        Matrix mIdentity;
        fColorRGBA color = { 0.0f, 0.0f, 0.8f, 1.0f };  // Color de fondo.

        if ( m_pVideoDriver )
        {
            // Limpiamos la pantalla.
            m_pVideoDriver->ClearColor( color );
            m_pVideoDriver->ClearZBuffer();

            // Eje de coordenadas en la esquina superior izquierda
            m_pVideoDriver->SetOrthoProjection( 0.0f, m_WindowProps.width,      // left, right
                                                -m_WindowProps.height, 0.0f ,   // bottom, top
                                                -1.0f, 1.0f );
            m_pVideoDriver->BeginRender();

            if ( m_bWireframe )
            {
                m_pVideoDriver->SetRenderMode( eWireFrame );    // Renderizado wireframe
                m_pVideoDriver->SetCullFaces ( eCullNone  );    // Desactivamos la selección de caras a renderizar.
            }
            else
            {
                m_pVideoDriver->SetRenderMode( eSolid     );    // Renderizado sólido.
                m_pVideoDriver->SetCullFaces ( eCullBack  );    // No se renderizarán las caras traseras.
            }

            m_pVideoDriver->SetTransform( mIdentity );          // Resteamos las transformaciones previas.

            RenderObjects();

            m_pVideoDriver->EndRender();
        }
    }

Y en el método RenderObjects() dibujamos el texto que queramos.


    ///////////////////////////////////////////////////////////////////////////////
    ///     RenderObjects: Dibuja las geometrías.
    ///
    ///     @param  nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::RenderObjects()
    {
    // ********************************* NEW **************************************

        Matrix mTransform, mResize, mTranslate;

        m_pVideoDriver->EnableLighting( false );
        m_pVideoDriver->EnableTexture ( true  );

        m_2DFont.SetTexture();

        // Amarilla
        m_2DFont.Render2DText( 30, -100, WINDOW_TITLE, COLOR_RGBA(0xff,0xff,0x00,0xff) );

        // Roja
        mTransform   = mResize.Scale(Vector3(1,3,0));
        m_pVideoDriver->SetTransform( mTransform );

        m_2DFont.Render2DText( 30, -2*m_2DFont.GetHeigthChar(), WINDOW_TITLE, COLOR_RGBA(0xff,0x00,0x00,0xff) );

        // Verde
        mTransform   = mTranslate.TranslateY( -5*m_2DFont.GetHeigthChar() );
        mTransform  *= mResize.Scale(Vector3(1.5f,1.5f,0));
        m_pVideoDriver->SetTransform( mTransform );

        m_2DFont.Render2DText( 30, 0, WINDOW_TITLE, COLOR_RGBA(0x00,0xff,0x00,0xff) );

    // ****************************************************************************
    }

Otra cosa, que debéis fijaros, como mediante el uso de matrices, podemos desplazar la fuente y cambiar su tamaño. Muestro el mismo texto tres veces para que veáis cómo debe hacerse para cambiar su color, posición o tamaño.

Fijaros también, como se realiza una única llamada a SetTexture() para renderizar los tres textos ya que es la misma para todos y así ganamos en eficiencia.

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



Nota: Compartir en Facebook
Enviado el Lunes, 01 septiembre a las 10:10:12 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: 0
votos: 0
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 22 - Texto 2D" | 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