⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 multitex.cpp

📁 <B>DirectX9.0 3D游戏编程</B>
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/********************************************************************
 *         Advanced 3D Game Programming using DirectX 9.0			*
 ********************************************************************
 * copyright (c) 2003 by Peter A Walsh and Adrian Perez				*
 * See license.txt for modification and distribution information	*
 ********************************************************************/

#include "stdafx.h"

#include <string>
#include <vector>
using namespace std;

/**
 * This is the type of vertex we'll be using
 * location, normal, and 2 sets of uv coords.
 */
struct sMTVertex
{
	point3 loc;
	point3 norm;
	// 2 sets of u,v coordinates
	float tex[2][2];
};


class cMultiTexApp : public cApplication,
	public iKeyboardReceiver
{

public:

	float m_timeDelta;

	matrix4	m_earthMat;
	matrix4	m_cloudMat;

	vector< sMTVertex > m_earthVerts;
	vector< sMTVertex > m_cloudVerts;
	cTexture* m_pTextures[8];

	string m_helpText;

	bool m_bDrawHelp;

	/**
	 * Are we currently rendering a pass?
	 */
	bool m_bDoBasePass;
	bool m_bDoGlowPass;
	bool m_bDoGlossPass;
	bool m_bDoDetailPass;
	bool m_bDoEnvyPass;
	bool m_bDoCloudPass;

	/**
	 * Can we render a pass at all?
	 */
	bool m_bCanDoBasePass;
	bool m_bCanDoGlowPass;
	bool m_bCanDoGlossPass;
	bool m_bCanDoDetailPass;
	bool m_bCanDoEnvyPass;
	bool m_bCanDoCloudPass;

	//==========--------------------------  cApplication

	virtual void DoFrame( float timeDelta );
	virtual void SceneInit();

	bool CheckCaps();

	cMultiTexApp() :
		cApplication()
	{
		m_title = string( "MultiTex - 6 passes of multitexture madness" );
		m_glFlags &= ~GLF_ZBUFFER; // turn off Z

		for( int i=0; i<8; i++ )
		{
			m_pTextures[i] = NULL;
		}

		
	}

	virtual ~cMultiTexApp()
	{
		/**
		 * Delete all of the textures
		 */
		for( int i=0; i<8; i++ )
		{
			delete m_pTextures[i];
		}
	}

	virtual void KeyUp( int key );
	virtual void KeyDown( int key ){}

	void CreateSphereVertices( float radius, vector<sMTVertex>* pVec, float* scales );
	void InitLights();

	void LoadTextures();

	void DoBasePass();
	void DoGlowPass();
	void DoGlossPass();
	void DoDetailPass();
	void DoEnvyPass();
	void DoCloudPass();

	void DrawBackground();

};

cApplication* CreateApplication()
{
	return new cMultiTexApp();
}

void DestroyApplication( cApplication* pApp )
{
	delete pApp;
}

bool cMultiTexApp::CheckCaps()
{
	// certain base functionality is assumed, like MODULATE
	// and SELECTARGx

	m_bCanDoBasePass = true; // lord help us if the card can't do the base pass.
	m_bCanDoDetailPass = false;
	m_bCanDoGlowPass = false;
	m_bCanDoGlossPass = false;
	m_bCanDoEnvyPass = false;
	m_bCanDoCloudPass = false;

	D3DCAPS9 DevCaps;

	Graphics()->GetDevice()->GetDeviceCaps( &DevCaps );

	bool bCanDoMultitexture = (DevCaps.MaxSimultaneousTextures >= 2);
	bool bCanDoMod2x = (DevCaps.TextureOpCaps & D3DTEXOPCAPS_MODULATE2X)? true : false; 
	
	
	/**
	 * check detail mapping
	 */
	if( (DevCaps.SrcBlendCaps & D3DPBLENDCAPS_DESTCOLOR) &&
		(DevCaps.DestBlendCaps & D3DPBLENDCAPS_SRCCOLOR) )
	{
		m_bCanDoDetailPass = true;
	}

	/**
	 * check glow mapping
	 */
	if( bCanDoMultitexture &&
		(DevCaps.SrcBlendCaps & D3DPBLENDCAPS_ONE) &&
		(DevCaps.DestBlendCaps & D3DPBLENDCAPS_ONE) )
	{
		m_bCanDoGlowPass = true;
	}

	/**
	 * check envy mapping
	 */
	if( (DevCaps.VertexProcessingCaps & D3DVTXPCAPS_TEXGEN ) &&
		(DevCaps.SrcBlendCaps & D3DPBLENDCAPS_SRCCOLOR) &&
		(DevCaps.DestBlendCaps & D3DPBLENDCAPS_ONE) )
	{
		m_bCanDoEnvyPass = true;
	}

	/**
	 * check gloss mapping
	 */
	if( bCanDoMod2x &&
		(DevCaps.SrcBlendCaps & D3DPBLENDCAPS_ONE) &&
		(DevCaps.DestBlendCaps & D3DPBLENDCAPS_ONE) )
	{
		m_bCanDoGlossPass = true;
	}

	/**
	 * check cloud mapping
	 */
	if( (DevCaps.SrcBlendCaps & D3DPBLENDCAPS_SRCCOLOR) &&
		(DevCaps.DestBlendCaps & D3DPBLENDCAPS_INVSRCCOLOR) )
	{
		m_bCanDoCloudPass = true;
	}

	return true;
}


void cMultiTexApp::SceneInit()
{
	/**
	 * We're making the FOV less than 90 degrees.
	 * this is so the object doesn't warp as much
	 * when we're close to it.
	 */
	CheckCaps();

	Graphics()->SetProjectionData( PI/4.f, 1.f, 150.f );
	Graphics()->MakeProjectionMatrix();

	/**
	 * Request keyboard updates
	 */
	Input()->GetKeyboard()->SetReceiver( this );

	/**
	 * initialize our scene
	 */
	LPDIRECT3DDEVICE9 pDevice = Graphics()->GetDevice();

	pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
	pDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
	pDevice->SetRenderState(D3DRS_DITHERENABLE, TRUE);
	pDevice->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
	pDevice->SetRenderState(D3DRS_AMBIENT, 0xFFFFFF );

	/**
	 * Turn on bilinear filtering
	 */

	pDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
	pDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
	pDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_POINT );

	pDevice->SetSamplerState( 1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );
	pDevice->SetSamplerState( 1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );
	pDevice->SetSamplerState( 1, D3DSAMP_MIPFILTER, D3DTEXF_POINT );
	

	/**
	 * initialize the camera
	 * the 'up' vector is tilted to make the earth appear off-axis
	 */
	Graphics()->SetViewMatrix( 
		matrix4::CameraLookAt(
			point3(4, 10, -25 ), 
			point3(0,0,0) )
	);

	m_timeDelta = 0.03f; // a 30th of a second is a good first value

	/**
	 * We're wasting a bit of space, since the cloud vertices
	 * only use one set of texture coordinates.  Fixing that
	 * would introduce code complexity, which I'd rather avoid
	 */
	float scales[2] = {1.0f, 11.0f};
	CreateSphereVertices( 10.f, &m_earthVerts, &scales[0] );
	CreateSphereVertices( 10.2f, &m_cloudVerts, &scales[0] );

	InitLights();
	LoadTextures();

	m_helpText = "Multitexture Sample Application\n" +
	m_helpText += "Advanced 3D Game Programming using DirectX 8.0\n";
	m_helpText += "  available keys: (availability depends on device features)\n";

	m_helpText += (( m_bCanDoBasePass ) ? 
			"   [1]: Toggle base pass\n" : 
			"   [1]: (Not available)\n");

	m_helpText += (( m_bCanDoDetailPass ) ? 
			"   [2]: Toggle detail pass\n" : 
			"   [2]: (Not available)\n");

	m_helpText += (( m_bCanDoGlowPass ) ? 
			"   [3]: Toggle glow pass\n" : 
			"   [3]: (Not available)\n");

	m_helpText += (( m_bCanDoEnvyPass ) ? 
			"   [4]: Toggle envy pass\n" : 
			"   [4]: (Not available)\n");

	m_helpText += (( m_bCanDoGlossPass ) ? 
			"   [5]: Toggle gloss pass\n" : 
			"   [5]: (Not available)\n");

	m_helpText += (( m_bCanDoCloudPass ) ? 
			"   [6]: Toggle cloud pass\n" : 
			"   [6]: (Not available)\n");

	/**
	 * Initially, don't draw help
	 */
	m_bDrawHelp = false;

	/**
	 * Initially, just display the base map.
	 */
	m_bDoBasePass = true;
	m_bDoGlowPass = false;
	m_bDoGlossPass = false;
	m_bDoDetailPass = false;
	m_bDoEnvyPass = false;
	m_bDoCloudPass = false;

}

void cMultiTexApp::DoFrame( float timeDelta )
{
	/**
	 * update the time
	 */
	m_timeDelta = timeDelta;
	
	static float rotAmt = 3*PI/4;
	rotAmt += 0.75f * m_timeDelta;

	/**
	 * then, draw the frame.
	 */
	LPDIRECT3DDEVICE9 pDevice = Graphics()->GetDevice();
	if( pDevice )
	{
		pDevice->SetFVF( 
			D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX2 );

		Graphics()->Clear( true, true, 0, 1.f );

		Graphics()->BeginScene();

		Graphics()->SetWorldMatrix( matrix4::Identity );
		DrawBackground();

		point3 from( 0, 1, 0 );

		m_earthMat = 
			matrix4::AxisAngle( point3::j, rotAmt );

		/**
		 * The cloud matrix rotates a tiny bit faster
		 * than the earth matrix
		 */
		m_cloudMat = 
			matrix4::AxisAngle( point3::j, rotAmt * 0.7f );

		Graphics()->SetWorldMatrix( m_earthMat );

		if( m_bCanDoBasePass && m_bDoBasePass )
		{
			DoBasePass();
		}

		if( m_bCanDoDetailPass && m_bDoDetailPass )
		{
			DoDetailPass();
		}

		if( m_bCanDoGlowPass && m_bDoGlowPass )
		{
			DoGlowPass();
		}

		if( m_bCanDoEnvyPass && m_bDoEnvyPass )
		{
			DoEnvyPass();
		}

		if( m_bCanDoGlossPass && m_bDoGlossPass )
		{
			DoGlossPass();
		}

		if( m_bCanDoCloudPass && m_bDoCloudPass )
		{
			Graphics()->SetWorldMatrix( m_cloudMat );
			DoCloudPass();
		}

		

		if( m_bDrawHelp )
		{
			Graphics()->DrawTextString( 2, 2, D3DCOLOR_XRGB( 0, 255, 0 ), 
				(char*)m_helpText.c_str() );
		}
		else
		{
			Graphics()->DrawTextString( 2, 2, D3DCOLOR_XRGB( 0, 0, 255 ), 
				"Press [H] for help" );
		}

		Graphics()->EndScene();

		/**
		 * flip the buffer.
		 */
		Graphics()->Flip();
	
	}

}

void cMultiTexApp::KeyUp( int key )
{
	if( key == DIK_1 )
	{
		m_bDoBasePass = !m_bDoBasePass;
	}
	if( key == DIK_2 )
	{
		m_bDoDetailPass = !m_bDoDetailPass;
	}
	if( key == DIK_3 )
	{
		m_bDoGlowPass = !m_bDoGlowPass;
	}
	if( key == DIK_4 )
	{
		m_bDoEnvyPass = !m_bDoEnvyPass;
	}
	if( key == DIK_5 )
	{
		m_bDoGlossPass = !m_bDoGlossPass;
	}
	if( key == DIK_6 )
	{
		m_bDoCloudPass = !m_bDoCloudPass;
	}
	if( key == DIK_H )
	{
		m_bDrawHelp = !m_bDrawHelp;
	}
}


void cMultiTexApp::InitLights()
{
	LPDIRECT3DDEVICE9 lpDevice = Graphics()->GetDevice();
    
    sLight light;

	// Light 0
	light = sLight::Directional( 
		point3(8,-3,5).Normalized(),
		0.9f * color3::White + 0.1f * color3::Yellow,
		0.9f * color3::White + 0.1f * color3::Yellow );

    // Set the light
    lpDevice->SetLight( 0, &light );
	lpDevice->LightEnable(0, TRUE);

	// Light 1
	light = sLight::Directional( 
		point3(8,-3,5).Normalized(),
		color3::White );

    // Set the light
    lpDevice->SetLight( 1, &light );
}


/**
 * Based off of InitSphereVertices from the
 * BumpEarth D3D SDK application
 */
void cMultiTexApp::CreateSphereVertices( float radius, vector<sMTVertex>* pVec, float* scales )
{
    int numSphereRings    = 30;
    int numSphereSegments = 30;

	sMTVertex curr;
	int i;

    // Establish constants used in sphere generation
    float fDeltaRingAngle = ( PI / numSphereRings );
    float fDeltaSegAngle  = ( 2.0f * PI / numSphereSegments );

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -