Tu segundo programa
<<< BAJATE EL CODIGO FUENTE AQUI >>>
Y despues del primero.... el segundo!! :)
El segundo programa que vamos a ver esta basado en el primero, pero vamos a añadirle una textura de fondo y vamos a mostrar texto en la ventana con informacion sobre los FPS y la tarjeta de video que se usa.
- Cargar texturas
- Cargar fuentes
Solo voy a comentar las partes que han cambiado respecto al programa anterior, porque sino se hace esto muy largo, ok?
>ala que si, empieza ya pesado!!!!
Descripcion del vertice
Como ya no vamos a mostrar cada vertice de un color, sino que
vamos a poner una textura, ya no necesitamos mas el componente color de nuestra
estructura.
Ademas hemos de añadir las coordenadas de la textura que cada vertice
situara:
struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw; // The transformed position for the vertex
FLOAT tu, tv; // texture coordinates
};
y tambien nuestro #define...
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_TEX1)
Cargar Fuentes
Para cargar las fuentes vamos a usar la funcion CD3DFont. Las fuentes las creamos en el constructor de nuestra clase principal, asi se crean lo primero de todo.
CMyD3DApplication::CMyD3DApplication() { m_strWindowTitle = _T("Basic"); m_bUseDepthBuffer = FALSE; m_pVB = NULL; m_pFont = new CD3DFont( _T("Arial"), 12, D3DFONT_BOLD ); }
Una vez que la tenemos creada, hemos de cargarla usando metodos GDI. Esto lo hacemos en InitDeviceObjects()...
HRESULT CMyD3DApplication::InitDeviceObjects() { m_pFont->InitDeviceObjects( m_pd3dDevice );
// Load the texture for the background image if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, _T("Lake.bmp"), &m_pBackgroundTexture) ) ) return D3DAPPERR_MEDIANOTFOUND;
return S_OK; }
La primera linea sirve para cargar la fuente que habiamos creado
anteriormente.
El resto de lineas sirven para crear la textura que mostraremos como fondo de
nuestra ventana... vamos a ver en que consiste esto de crear la textura.
Cargar Texturas
D3DUtil_CreateTexture() utiliza internamente la funcion D3DXCreateTextureFromFileEx() ....
HRESULT D3DUtil_CreateTexture( LPDIRECT3DDEVICE8
pd3dDevice, TCHAR* strTexture, LPDIRECT3DTEXTURE8* ppTexture, D3DFORMAT d3dFormat
)
{
// Get the path to the texture
TCHAR strPath[MAX_PATH];
DXUtil_FindMediaFile( strPath, strTexture );
// Create the texture using D3DX
return D3DXCreateTextureFromFileEx( pd3dDevice, strPath,
D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, d3dFormat,
D3DPOOL_MANAGED, D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR,
D3DX_FILTER_TRIANGLE|D3DX_FILTER_MIRROR, 0, NULL, NULL, ppTexture );
}
Y ahora veamos un poco que es D3DXCreateTextureFromFileEx()
y que podemos hacer con ella...
HRESULT WINAPI D3DXCreateTextureFromFileEx()
LPDIRECT3DDEVICE8 pDevice,
LPCSTR pSrcFile,
UINT Width,
UINT Height,
UINT MipLevels,
DOWRD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
DWORD Filter,
DOWRD MipFilter,
D3DCOLOR ColorKey,
D3DXIMAGE_INFO* pSrcInfo,
PALETTEENTRY* pPalette,
LPDIRECT3DTEXTURE8* ppTexture);
esta es la definicion de la funcion, vemos que tiene un monton de parametros. Esta funcion nos es mas util que D3DUtil_Createtexture porque asi podemos hacer mas cosas:
- pDevice especifica que dispositivo usamos
- pSrcFile es una cadena que contiene el nombre del fichero
- Width and Height es el ancho y alto de la textura. Si pones 0 o D3DX_DEFAULT
las dimensiones se leen desde el fichero de origen
- MipLevels es una de las mas importantes, ya que nos permite hacer mipmapping
con la texura. Mipmapping consiste en tener diferentes resoluciones de la misma
textura, para cuando tengamos por ejemplo un arbol situado muy lejos de la camara
usemos una version con resolucion muy baja de la textura, en vez de la maxima
resolucion que nos haria perder recursos. Poniendo aqui 0 o D3DX_DEFAULT el
solo creara automaticamente las diferentes texturas.
- Usage sirve si queremos usar la textura para renderizar sobre ella o no, por
ejemplo cuando visualizas un video sobre la cara de un cubo estas renderizando
sobre una textura. Los valores son 0 o D3DUSAGE_RENDER-TARGET. Si quieres usar
la textura para tal fin debes comprobar primero si tu tarjeta lo permite con
CheckDeviceFormat(), poner el Pool por defecto con D3DPOOL_DEFAULT (esto es
el manejo de recursos), y despues utilizar el SetRenderTarget().
- Format define el formato de la superficie. Si no especificamos nada el formato
de la textura devuelto es el mismo que el del fichero de origen.
- Filter controla como es filtrada la imagen (esto es la calidad). Si por ejemplo
la textura va a ser la mitad de tamaño que el fichero de origen, puedes
usar D3DX_FILTER_BOX como parametro. Si va a ser un cuarto, usa D3DX_FILTER_LINEAR.
Este es tambien un parametro muy importante. Si la textura va a tener el mismo
tamaño puedes usar D3DX_FILTER_TRIANGLE | D3DX_FILTER_MIRROR.
- MipFilter es lo mismo que Filter pero para el mipmapping.
- ColorKey sirve para especificar cual es el color transparente de la textura.
- pSrcInfo devuelve un puntero a D3DXIMAGE_INFO que es una estructura que contiene
el ancho, alto, numero de miplevels que tiene la textura, y el formato de la
textura. D3DUtil_CreateTexture() no devuelve esta informacion.
- pPalette devuelve la paleta de colores. (Solo si usas texturas paletizadas,
esto es 256 colores).
-ppTexture por fin devuelve la textura creada.
RestoreDeviceObjects()
Esta es otra parte que ha cambiado de nuestro programa...
tan solo es que ahora tenemos tambien que restablecer las fuentes con:
m_pFont->RestoreDeviceObjects();
y que los vertices tienen nuevas componentes y hemos de quitar el color porque ya no tienen
CUSTOMVERTEX cvVertices[] =
{
{ 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f, }, // x, y, z, rhw, tu, tv
{ (float)vp.Width, 0.0f, 0.5f, 1.0f, 1.0f, 0.0f, },
{ (float)vp.Width, (float)vp.Height, 0.5f, 1.0f, 1.0f, 1.0f, },
{ 0.0f, (float)vp.Height, 0.5f, 1.0f, 0.0f, 1.0f},
};
Render()
Aqui viene un poco mas la chicha. este es el codigo completo de la funcion:
HRESULT CMyD3DApplication::Render()
{
// Begin the scene
if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
{
m_pd3dDevice->SetTexture( 0, m_pBackgroundTexture );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1 );
m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(CUSTOMVERTEX) ); m_pd3dDevice->SetVertexShader( D3DFVF_CUSTOMVERTEX ); m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, 0, 2 );
// Output statistics m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0), m_strFrameStats ); m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats );
// End the scene. m_pd3dDevice->EndScene(); }
return S_OK; }
Lo primero es llamar a SetTexture() para cargar la textura, con esto le decimos a Direct3D que vamos a trabajar con ella. Direct3D mantiene una lista de hasta 8 texturas a la vez, lo que significa que puede mezclar hasta 8 texturas en una primitiva por hardware. La mayoria de tarjetas de video actuales no permiten mas de 2 al mismo tiempo (multitexturing), en cambio si que pueden mezclar mas de 2 pero una detras de otra (multipass texturing) aunque claro es mas lento.
Tras SetTexture(), todas las primitivas que renderizemos se haran con la textura que hemos seleccionado. Antes de dibujar la primitiva debemos configurar esa textura un poco...
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1,
D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1
);
...
HRESULT SettextureStageState(
DOWORD Stage,
D3DTEXTURESTAGESTATETYPE Type,
DWORD Value
};
Que es SetTextureStageState() ??? Pues es como una navaja suiza, vale para todo lo que quieras hacer con las texturas, te explico:
- El primer parametro es Stage, indica el "pass number", esto es el numero de stage en el que estas. Cuando solo tienes una textura, se hace todo de un tiron (digamoslo asi), lo que quiere decir que solo tienes un stage (de valor 0). Cuando tienes dos texturas a dibujar sobre un mismo triangulo tienes dos stages (de valor 0 y 1). Este parametro sirve para indicar en que stage (o llamalo estadio) estamos configurando nuestra textura.
- El segundo parametro indica el tipo de estado en el render que quieres usar. Hay un monton de tipos pero los mas comunes son D3DTSS_COLORx que controlan el flujo de un vector RGB y D3DTSS_ALPHAX que controla el flujo del escalar alfa a traves de segmentos paralelos en el pipeline de Direct3D. Pero estas cosas ya las veremos mas adelante, por el momento simplemente usa estos valores. En el segundo SetTextureStageState usamos una operacion de color con el parametro D3DTSS_COLOROP, que en este caso es D3DTOP_SELECTARG1 e indica que use el primer argumento como salida. El primer SetTextureStageState() indica que este primer argumento es el color de textura (que ya la habiamos cargado con SetTexture() )
Continuamos con nuestro render, las tres lineas que vienen a continuacion son igual que en el primer pograma... me refiero SetStreamSource(), SetVertexShader(), y DrawPrimitive()
Lo que hemos añadido es DrawText()...
m_pFont->DrawText( 2, 0, D3DCOLOR_ARGB(255,255,255,0),
m_strFrameStats );
m_pFont->DrawText( 2, 20, D3DCOLOR_ARGB(255,255,255,0), m_strDeviceStats
);
Los dos primeros parametros son la X, Y del texto, empezando a contar desde
arriba a la izquierda como de costumbre. Despues el color del texto. Y por ultimo
el texto que queremos mostrar, estas dos variables que hemos usado estan ya
predefinidas en d3dapp.cpp y contienen los informacion sobre el estado del programa:
frames por segundo, ancho y alto de la ventana, formato, tarjeta de video que
usamos, sus caracteristicas, etc...
InvalidateDeviceObjects()
HRESULT CMyD3DApplication::InvalidateDeviceObjects() { m_pFont->InvalidateDeviceObjects(); SAFE_RELEASE( m_pVB ); return S_OK; }
m_pFont->InvalidateDeviceObjects(); destruye todo lo que la fuente ha creado, pero no la fuente!!. Esto ocurre cada vez que redimensionamos la ventana
DeleteDeviceObjects()
HRESULT CMyD3DApplication::DeleteDeviceObjects() { m_pFont->DeleteDeviceObjects(); SAFE_RELEASE( m_pBackgroundTexture ); return S_OK; }
aqui destruimos todo lo que hemos creado anteriormente: la textura y la fuente
Y Fin, ya tienes tu segundo programa terminado y funcionando!!