mirror of
https://github.com/thug1src/thug.git
synced 2025-01-22 05:43:47 +00:00
1606 lines
49 KiB
C++
1606 lines
49 KiB
C++
|
#include <xtl.h>
|
||
|
#include <xgraphics.h>
|
||
|
|
||
|
#include <sys/timer.h>
|
||
|
#include <sys/file/filesys.h>
|
||
|
#include <core/macros.h>
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "nx_init.h"
|
||
|
#include "texture.h"
|
||
|
#include "scene.h"
|
||
|
#include "mesh.h"
|
||
|
#include "anim.h"
|
||
|
#include "render.h"
|
||
|
#include "billboard.h"
|
||
|
|
||
|
namespace NxXbox
|
||
|
{
|
||
|
|
||
|
bool s_meshScalingEnabled = false;
|
||
|
char* s_pWeightIndices = NULL;
|
||
|
float* s_pWeights = NULL;
|
||
|
Mth::Vector* s_pBonePositions = NULL;
|
||
|
Mth::Vector* s_pBoneScales = NULL;
|
||
|
int s_currentVertIndex = 0;
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void SetMeshScalingParameters( Nx::SMeshScalingParameters* pParams )
|
||
|
{
|
||
|
Dbg_Assert( pParams );
|
||
|
|
||
|
s_meshScalingEnabled = true;
|
||
|
s_pWeights = pParams->pWeights;
|
||
|
s_pWeightIndices = pParams->pWeightIndices;
|
||
|
s_pBoneScales = pParams->pBoneScales;
|
||
|
s_pBonePositions = pParams->pBonePositions;
|
||
|
s_currentVertIndex = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void DisableMeshScaling( void )
|
||
|
{
|
||
|
s_meshScalingEnabled = false;
|
||
|
s_pWeights = NULL;
|
||
|
s_pWeightIndices = NULL;
|
||
|
s_pBoneScales = NULL;
|
||
|
s_pBonePositions = NULL;
|
||
|
s_currentVertIndex = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
static inline Mth::Vector get_bone_scale( int bone_index )
|
||
|
{
|
||
|
Mth::Vector returnVec( 1.0f, 1.0f, 1.0f, 1.0f );
|
||
|
|
||
|
if( bone_index >= 29 && bone_index <= 33 )
|
||
|
{
|
||
|
// this only works with the thps5 skeleton, whose
|
||
|
// head bones are between 29 and 33...
|
||
|
// (eventually, we can remove the subtract 29
|
||
|
// once the exporter is massaging the data correctly)
|
||
|
returnVec = s_pBoneScales[ bone_index - 29 ];
|
||
|
|
||
|
// Y & Z are reversed... odd!
|
||
|
Mth::Vector tempVec = returnVec;
|
||
|
returnVec[Y] = tempVec[Z];
|
||
|
returnVec[Z] = tempVec[Y];
|
||
|
}
|
||
|
else if( bone_index == -1 )
|
||
|
{
|
||
|
// implies that it's not weighted to a bone
|
||
|
return returnVec;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// implies that it's weighted to the wrong bone
|
||
|
return returnVec;
|
||
|
}
|
||
|
return returnVec;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
static inline Mth::Vector get_bone_pos( int bone_index )
|
||
|
{
|
||
|
Mth::Vector returnVec( 0.0f, 0.0f, 0.0f, 1.0f );
|
||
|
|
||
|
if( bone_index >= 29 && bone_index <= 33 )
|
||
|
{
|
||
|
// this only works with the thps5 skeleton, whose
|
||
|
// head bones are between 29 and 33...
|
||
|
// (eventually, we can remove the subtract 29
|
||
|
// once the exporter is massaging the data correctly)
|
||
|
returnVec = s_pBonePositions[ bone_index - 29 ];
|
||
|
}
|
||
|
else if( bone_index == -1 )
|
||
|
{
|
||
|
// implies that it's not weighted to a bone
|
||
|
return returnVec;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// implies that it's weighted to the wrong bone
|
||
|
return returnVec;
|
||
|
}
|
||
|
returnVec[W] = 1.0f;
|
||
|
|
||
|
return returnVec;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void ApplyMeshScaling( float* p_vertices, int num_verts )
|
||
|
{
|
||
|
if( s_meshScalingEnabled )
|
||
|
{
|
||
|
for( int v = 0; v < num_verts; ++v, p_vertices += 3 )
|
||
|
{
|
||
|
float x = p_vertices[0];
|
||
|
float y = p_vertices[1];
|
||
|
float z = p_vertices[2];
|
||
|
|
||
|
Mth::Vector origPos( x, y, z, 1.0f );
|
||
|
|
||
|
Mth::Vector bonePos0 = get_bone_pos( s_pWeightIndices[v * 3] );
|
||
|
Mth::Vector bonePos1 = get_bone_pos( s_pWeightIndices[v * 3 + 1] );
|
||
|
Mth::Vector bonePos2 = get_bone_pos( s_pWeightIndices[v * 3 + 2] );
|
||
|
|
||
|
// Need to scale each vert relative to its parent bone.
|
||
|
Mth::Vector localPos0 = origPos - bonePos0;
|
||
|
Mth::Vector localPos1 = origPos - bonePos1;
|
||
|
Mth::Vector localPos2 = origPos - bonePos2;
|
||
|
|
||
|
localPos0.Scale( get_bone_scale( s_pWeightIndices[v * 3] ) );
|
||
|
localPos1.Scale( get_bone_scale( s_pWeightIndices[v * 3 + 1] ) );
|
||
|
localPos2.Scale( get_bone_scale( s_pWeightIndices[v * 3 + 2] ) );
|
||
|
|
||
|
localPos0 += bonePos0;
|
||
|
localPos1 += bonePos1;
|
||
|
localPos2 += bonePos2;
|
||
|
|
||
|
Mth::Vector scaledPos = ( localPos0 * s_pWeights[v * 3] ) +
|
||
|
( localPos1 * s_pWeights[v * 3 + 1] ) +
|
||
|
( localPos2 * s_pWeights[v * 3 + 2] );
|
||
|
|
||
|
p_vertices[0] = scaledPos[X];
|
||
|
p_vertices[1] = scaledPos[Y];
|
||
|
p_vertices[2] = scaledPos[Z];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
sMesh::sMesh( void )
|
||
|
{
|
||
|
m_flags = 0;
|
||
|
m_num_vertex_buffers = 1;
|
||
|
m_current_write_vertex_buffer = 0;
|
||
|
for( int vb = 0; vb < MAX_VERTEX_BUFFERS; ++vb )
|
||
|
{
|
||
|
mp_vertex_buffer[vb] = NULL;
|
||
|
}
|
||
|
for( int ib = 0; ib < MAX_INDEX_BUFFERS; ++ib )
|
||
|
{
|
||
|
mp_index_buffer[ib] = NULL;
|
||
|
m_num_indices[ib] = 0;
|
||
|
}
|
||
|
mp_vc_wibble_data = NULL;
|
||
|
mp_index_lod_data = NULL;
|
||
|
mp_billboard_data = NULL;
|
||
|
m_bone_index = -1;
|
||
|
mp_transform = NULL;
|
||
|
m_diffuse_offset = 0;
|
||
|
m_uv0_offset = 0;
|
||
|
m_normal_offset = 0;
|
||
|
m_vertex_stride = 0;
|
||
|
m_vertex_shader[0] = 0;
|
||
|
m_pixel_shader = 0;
|
||
|
|
||
|
SetActive( true );
|
||
|
SetVisibility( 0xFF );
|
||
|
|
||
|
// Set default primitive type.
|
||
|
m_primitive_type = D3DPT_TRIANGLESTRIP;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
sMesh::~sMesh( void )
|
||
|
{
|
||
|
// Remove this mesh from the billboard manager if appropriate.
|
||
|
if( m_flags & sMesh::MESH_FLAG_BILLBOARD )
|
||
|
{
|
||
|
BillboardManager.RemoveEntry( this );
|
||
|
}
|
||
|
|
||
|
EngineGlobals.p_Device->BlockUntilIdle();
|
||
|
|
||
|
if( mp_transform )
|
||
|
{
|
||
|
delete mp_transform;
|
||
|
}
|
||
|
|
||
|
if( !( m_flags & MESH_FLAG_IS_INSTANCE ))
|
||
|
{
|
||
|
for( int ib = 0; ib < MAX_INDEX_BUFFERS; ++ib )
|
||
|
{
|
||
|
delete [] mp_index_buffer[ib];
|
||
|
mp_index_buffer[ib] = NULL;
|
||
|
}
|
||
|
|
||
|
if( mp_vc_wibble_data )
|
||
|
{
|
||
|
delete mp_vc_wibble_data;
|
||
|
mp_vc_wibble_data = NULL;
|
||
|
}
|
||
|
|
||
|
if( mp_index_lod_data )
|
||
|
{
|
||
|
delete mp_index_lod_data;
|
||
|
mp_index_lod_data = NULL;
|
||
|
}
|
||
|
|
||
|
if( mp_billboard_data )
|
||
|
{
|
||
|
delete mp_billboard_data;
|
||
|
mp_billboard_data = NULL;
|
||
|
}
|
||
|
|
||
|
UINT stride;
|
||
|
IDirect3DVertexBuffer8 *p_vb;
|
||
|
D3DDevice_GetStreamSource( 0, &p_vb, &stride );
|
||
|
if( p_vb )
|
||
|
{
|
||
|
// GetStreamSource() increments the reference count, so call Release() here.
|
||
|
p_vb->Release();
|
||
|
}
|
||
|
|
||
|
for( uint32 i = 0; i < m_num_vertex_buffers; ++i )
|
||
|
{
|
||
|
if( mp_vertex_buffer[i] )
|
||
|
{
|
||
|
if( p_vb == mp_vertex_buffer[i] )
|
||
|
{
|
||
|
// We are deleting a vertex buffer that is set as the current stream source. This can result in
|
||
|
// problems with the internal D3D reference counter, so clear this up first.
|
||
|
D3DDevice_SetStreamSource( 0, NULL, 0 );
|
||
|
}
|
||
|
|
||
|
uint8 *p_del = (uint8*)mp_vertex_buffer[i];
|
||
|
delete p_del;
|
||
|
mp_vertex_buffer[i] = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::PushVertexShader( uint32 shader_id )
|
||
|
{
|
||
|
for( uint32 i = sMesh::VERTEX_SHADER_STACK_SIZE - 1; i > 0; --i )
|
||
|
{
|
||
|
m_vertex_shader[i] = m_vertex_shader[i - 1];
|
||
|
}
|
||
|
m_vertex_shader[0] = shader_id;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::PopVertexShader( void )
|
||
|
{
|
||
|
for( uint32 i = 0; i < sMesh::VERTEX_SHADER_STACK_SIZE - 1; ++i )
|
||
|
{
|
||
|
m_vertex_shader[i] = m_vertex_shader[i + 1];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::wibble_normals( void )
|
||
|
{
|
||
|
if( m_flags & 0 )
|
||
|
{
|
||
|
// Angle in the range [-PI/16, PI/16], period is 1 second.
|
||
|
float time = (float)Tmr::GetTime() * 0.0005f;
|
||
|
|
||
|
BYTE *p_byte;
|
||
|
float *p_normal;
|
||
|
float *p_pos;
|
||
|
mp_vertex_buffer[m_current_write_vertex_buffer]->Lock( 0, 0, &p_byte, 0 );
|
||
|
p_pos = (float*)( p_byte + 0 );
|
||
|
p_normal = (float*)( p_byte + m_normal_offset );
|
||
|
|
||
|
for( uint32 i = 0; i < m_num_vertices; ++i )
|
||
|
{
|
||
|
float x = p_pos[0] - m_sphere_center.x;
|
||
|
float z = p_pos[2] - m_sphere_center.z;
|
||
|
|
||
|
float time_offset_x = time + (( x / m_sphere_radius ) * 0.5f );
|
||
|
float time_offset_z = time + (( z / m_sphere_radius ) * 0.5f );
|
||
|
|
||
|
float angle_x = ( Mth::PI * ( 1.0f / 64.0f ) * (float)fabs( sinf( time_offset_x * Mth::PI ))) - ( Mth::PI * ( 1.0f / 128.0f ));
|
||
|
float angle_z = ( Mth::PI * ( 1.0f / 64.0f ) * (float)fabs( sinf( time_offset_z * Mth::PI ))) - ( Mth::PI * ( 1.0f / 129.0f ));
|
||
|
|
||
|
Mth::Vector n( sinf( angle_x ), cosf(( angle_x + angle_z ) * 0.5f ), sinf( angle_z ));
|
||
|
n.Normalize();
|
||
|
|
||
|
p_normal[0] = n[X];
|
||
|
p_normal[1] = n[Y];
|
||
|
p_normal[2] = n[Z];
|
||
|
|
||
|
p_pos = (float*)((BYTE*)p_pos + m_vertex_stride );
|
||
|
p_normal = (float*)((BYTE*)p_normal + m_vertex_stride );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::wibble_vc( void )
|
||
|
{
|
||
|
if( mp_vc_wibble_data )
|
||
|
{
|
||
|
// Grab byte pointer to current 'write' vertex buffer.
|
||
|
BYTE *p_byte;
|
||
|
D3DCOLOR *p_color;
|
||
|
mp_vertex_buffer[m_current_write_vertex_buffer]->Lock( 0, 0, &p_byte, 0 );
|
||
|
p_color = (D3DCOLOR*)( p_byte + m_diffuse_offset );
|
||
|
|
||
|
D3DCOLOR *p_color_array = mp_material->mp_wibble_vc_colors;
|
||
|
|
||
|
// Scan through each vertex, setting the new color.
|
||
|
for( uint32 i = 0; i < m_num_vertices; ++i )
|
||
|
{
|
||
|
// An index of zero means no update for this vert.
|
||
|
uint32 index = mp_vc_wibble_data[i];
|
||
|
if( index > 0 )
|
||
|
{
|
||
|
*p_color = p_color_array[index - 1];
|
||
|
}
|
||
|
p_color = (D3DCOLOR*)((BYTE*)p_color + m_vertex_stride );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::CreateDuplicateVertexBuffers( int n )
|
||
|
{
|
||
|
// Ensure this hasn't already been called.
|
||
|
Dbg_Assert( mp_vertex_buffer[0] != NULL );
|
||
|
Dbg_Assert( mp_vertex_buffer[1] == NULL );
|
||
|
Dbg_Assert(( n > 0 ) && ( n < MAX_VERTEX_BUFFERS ));
|
||
|
|
||
|
// Lock the source buffer.
|
||
|
BYTE *p_byte;
|
||
|
if( D3D_OK != mp_vertex_buffer[0]->Lock( 0, 0, &p_byte, D3DLOCK_READONLY ))
|
||
|
{
|
||
|
exit( 0 );
|
||
|
}
|
||
|
|
||
|
for( int i = 0; i < n; ++i )
|
||
|
{
|
||
|
mp_vertex_buffer[i + 1] = AllocateVertexBuffer( m_vertex_stride * m_num_vertices );
|
||
|
|
||
|
// Lock the destination buffer and copy the contents of the original buffer into the new buffer.
|
||
|
BYTE *p_byte2;
|
||
|
if( D3D_OK != mp_vertex_buffer[i + 1]->Lock( 0, 0, &p_byte2, 0 ))
|
||
|
{
|
||
|
exit( 0 );
|
||
|
}
|
||
|
CopyMemory( p_byte2, p_byte, m_vertex_stride * m_num_vertices );
|
||
|
}
|
||
|
|
||
|
m_num_vertex_buffers = 1 + n;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::SetPosition( Mth::Vector &pos )
|
||
|
{
|
||
|
// Create a transform if one doesn't exist yet.
|
||
|
if( mp_transform == NULL )
|
||
|
{
|
||
|
mp_transform = new Mth::Matrix();
|
||
|
mp_transform->Ident();
|
||
|
}
|
||
|
|
||
|
// Figure what we need to add to each vertex, based on current position.
|
||
|
Mth::Vector offset( pos[X] - mp_transform->GetPos()[X],
|
||
|
pos[Y] - mp_transform->GetPos()[Y],
|
||
|
pos[Z] - mp_transform->GetPos()[Z] );
|
||
|
|
||
|
mp_transform->SetPos( pos );
|
||
|
|
||
|
for( uint32 vb = 0; vb < m_num_vertex_buffers; ++vb )
|
||
|
{
|
||
|
BYTE *p_byte;
|
||
|
mp_vertex_buffer[vb]->Lock( 0, 0, &p_byte, 0 );
|
||
|
|
||
|
for( uint32 v = 0; v < m_num_vertices; ++v )
|
||
|
{
|
||
|
((D3DVECTOR*)p_byte )->x += offset[X];
|
||
|
((D3DVECTOR*)p_byte )->y += offset[Y];
|
||
|
((D3DVECTOR*)p_byte )->z += offset[Z];
|
||
|
p_byte += m_vertex_stride;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We also need to adjust the bounding box and sphere information for this mesh.
|
||
|
m_sphere_center.x += offset[X];
|
||
|
m_sphere_center.y += offset[Y];
|
||
|
m_sphere_center.z += offset[Z];
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::GetPosition( Mth::Vector *p_pos )
|
||
|
{
|
||
|
if( mp_transform == NULL )
|
||
|
{
|
||
|
p_pos->Set( 0.0f, 0.0f, 0.0f );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*p_pos = mp_transform->GetPos();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::SetYRotation( Mth::ERot90 rot )
|
||
|
{
|
||
|
if( rot > Mth::ROT_0 )
|
||
|
{
|
||
|
// Create a transform if one doesn't exist yet.
|
||
|
if( mp_transform == NULL )
|
||
|
{
|
||
|
mp_transform = new Mth::Matrix();
|
||
|
mp_transform->Ident();
|
||
|
}
|
||
|
|
||
|
for( uint32 vb = 0; vb < m_num_vertex_buffers; ++vb )
|
||
|
{
|
||
|
BYTE *p_byte;
|
||
|
mp_vertex_buffer[vb]->Lock( 0, 0, &p_byte, 0 );
|
||
|
|
||
|
switch( rot )
|
||
|
{
|
||
|
case Mth::ROT_90:
|
||
|
{
|
||
|
for( uint32 v = 0; v < m_num_vertices; ++v )
|
||
|
{
|
||
|
float x = ((D3DVECTOR*)p_byte )->x - mp_transform->GetPos()[X];
|
||
|
float z = ((D3DVECTOR*)p_byte )->z - mp_transform->GetPos()[Z];
|
||
|
((D3DVECTOR*)p_byte )->x = z + mp_transform->GetPos()[X];
|
||
|
((D3DVECTOR*)p_byte )->z = -x + mp_transform->GetPos()[Z];
|
||
|
p_byte += m_vertex_stride;
|
||
|
}
|
||
|
|
||
|
// Adjust the bounding sphere information for this mesh.
|
||
|
m_sphere_center.x -= mp_transform->GetPos()[X];
|
||
|
m_sphere_center.z -= mp_transform->GetPos()[Z];
|
||
|
float t = m_sphere_center.x;
|
||
|
m_sphere_center.x = m_sphere_center.z + mp_transform->GetPos()[X];
|
||
|
m_sphere_center.z = -t + mp_transform->GetPos()[Z];
|
||
|
break;
|
||
|
}
|
||
|
case Mth::ROT_180:
|
||
|
{
|
||
|
for( uint32 v = 0; v < m_num_vertices; ++v )
|
||
|
{
|
||
|
float x = ((D3DVECTOR*)p_byte )->x - mp_transform->GetPos()[X];
|
||
|
float z = ((D3DVECTOR*)p_byte )->z - mp_transform->GetPos()[Z];
|
||
|
((D3DVECTOR*)p_byte )->x = -x + mp_transform->GetPos()[X];
|
||
|
((D3DVECTOR*)p_byte )->z = -z + mp_transform->GetPos()[Z];
|
||
|
p_byte += m_vertex_stride;
|
||
|
}
|
||
|
|
||
|
// Adjust the bounding sphere information for this mesh.
|
||
|
m_sphere_center.x -= mp_transform->GetPos()[X];
|
||
|
m_sphere_center.z -= mp_transform->GetPos()[Z];
|
||
|
m_sphere_center.x = -m_sphere_center.x + mp_transform->GetPos()[X];
|
||
|
m_sphere_center.z = -m_sphere_center.z + mp_transform->GetPos()[Z];
|
||
|
break;
|
||
|
}
|
||
|
case Mth::ROT_270:
|
||
|
{
|
||
|
for( uint32 v = 0; v < m_num_vertices; ++v )
|
||
|
{
|
||
|
float x = ((D3DVECTOR*)p_byte )->x - mp_transform->GetPos()[X];
|
||
|
float z = ((D3DVECTOR*)p_byte )->z - mp_transform->GetPos()[Z];
|
||
|
((D3DVECTOR*)p_byte )->x = -z + mp_transform->GetPos()[X];
|
||
|
((D3DVECTOR*)p_byte )->z = x + mp_transform->GetPos()[Z];
|
||
|
p_byte += m_vertex_stride;
|
||
|
}
|
||
|
|
||
|
// Adjust the bounding sphere information for this mesh.
|
||
|
m_sphere_center.x -= mp_transform->GetPos()[X];
|
||
|
m_sphere_center.z -= mp_transform->GetPos()[Z];
|
||
|
float t = m_sphere_center.x;
|
||
|
m_sphere_center.x = -m_sphere_center.z + mp_transform->GetPos()[X];
|
||
|
m_sphere_center.z = t + mp_transform->GetPos()[Z];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::SwapVertexBuffers( void )
|
||
|
{
|
||
|
if( m_num_vertex_buffers > 1 )
|
||
|
{
|
||
|
m_current_write_vertex_buffer = ( m_current_write_vertex_buffer + 1 ) % m_num_vertex_buffers;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::HandleColorOverride( void )
|
||
|
{
|
||
|
static float constants[16];
|
||
|
|
||
|
Dbg_Assert( m_flags & sMesh::MESH_FLAG_MATERIAL_COLOR_OVERRIDE );
|
||
|
|
||
|
// Re-jig the pixel shader constants for the material color override.
|
||
|
CopyMemory( constants, EngineGlobals.pixel_shader_constants, sizeof( float ) * 16 );
|
||
|
|
||
|
for( uint32 p = 0; p < mp_material->m_passes; ++p )
|
||
|
{
|
||
|
if( !( mp_material->m_flags[p] & MATFLAG_PASS_COLOR_LOCKED ))
|
||
|
{
|
||
|
// EngineGlobals.pixel_shader_constants[( p * 4 ) + 0] *= m_material_color_override[0];
|
||
|
// EngineGlobals.pixel_shader_constants[( p * 4 ) + 1] *= m_material_color_override[1];
|
||
|
// EngineGlobals.pixel_shader_constants[( p * 4 ) + 2] *= m_material_color_override[2];
|
||
|
EngineGlobals.pixel_shader_constants[( p * 4 ) + 0] = m_material_color_override[0];
|
||
|
EngineGlobals.pixel_shader_constants[( p * 4 ) + 1] = m_material_color_override[1];
|
||
|
EngineGlobals.pixel_shader_constants[( p * 4 ) + 2] = m_material_color_override[2];
|
||
|
}
|
||
|
}
|
||
|
EngineGlobals.upload_pixel_shader_constants = true;
|
||
|
|
||
|
// Set the pixel shader (this will upload the new constants).
|
||
|
set_pixel_shader( m_pixel_shader, mp_material->m_passes );
|
||
|
|
||
|
// Restore the pixel shader constants and flag as needing a reload.
|
||
|
CopyMemory( EngineGlobals.pixel_shader_constants, constants, sizeof( float ) * 16 );
|
||
|
EngineGlobals.upload_pixel_shader_constants = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::Submit( void )
|
||
|
{
|
||
|
DWORD stage_zero_minfilter;
|
||
|
DWORD zwrite;
|
||
|
|
||
|
// Pointless submitting a mesh with zero indices.
|
||
|
if( m_num_indices == 0 )
|
||
|
return;
|
||
|
|
||
|
// Deal with vertex color wibbling.
|
||
|
wibble_vc();
|
||
|
|
||
|
// Set vertex shader.
|
||
|
set_vertex_shader( m_vertex_shader[0] );
|
||
|
|
||
|
if( m_flags & sMesh::MESH_FLAG_MATERIAL_COLOR_OVERRIDE )
|
||
|
{
|
||
|
HandleColorOverride();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Just set the pixel shader.
|
||
|
set_pixel_shader( m_pixel_shader, mp_material->m_passes );
|
||
|
}
|
||
|
|
||
|
// Deal with meshes that set no anisotropic filtering.
|
||
|
if( m_flags & MESH_FLAG_NO_ANISOTROPIC )
|
||
|
{
|
||
|
D3DDevice_GetTextureStageState( 0, D3DTSS_MINFILTER, &stage_zero_minfilter );
|
||
|
if( stage_zero_minfilter != D3DTEXF_LINEAR )
|
||
|
{
|
||
|
D3DDevice_SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Deal with meshes that set no z-write.
|
||
|
if( m_flags & MESH_FLAG_NO_ZWRITE )
|
||
|
{
|
||
|
D3DDevice_GetRenderState( D3DRS_ZWRITEENABLE, &zwrite );
|
||
|
if( zwrite == TRUE )
|
||
|
{
|
||
|
D3DDevice_SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Get the vertex buffer to submit (which is the one we have potentially just been writing to).
|
||
|
IDirect3DVertexBuffer8* p_submit_buffer = mp_vertex_buffer[m_current_write_vertex_buffer];
|
||
|
|
||
|
// Swap multiple vertex buffers if present.
|
||
|
SwapVertexBuffers();
|
||
|
|
||
|
// Set the stream source.
|
||
|
D3DDevice_SetStreamSource( 0, p_submit_buffer, m_vertex_stride );
|
||
|
|
||
|
// See if we have index LOD data, in which case we need to figure distance and select the correct LOD.
|
||
|
if( mp_index_lod_data )
|
||
|
{
|
||
|
// Figure distance from this mesh to the camera. This is *not* an efficient way to do it.
|
||
|
frustum_check_sphere( &m_sphere_center, m_sphere_radius );
|
||
|
float dist = get_bounding_sphere_nearest_z();
|
||
|
for( int idx = 0; idx < MAX_INDEX_BUFFERS; ++idx )
|
||
|
{
|
||
|
if( mp_index_buffer[idx] == NULL )
|
||
|
{
|
||
|
// We have got to the end of the set without drawing anything. Just use the last valid index set.
|
||
|
if( idx > 0 )
|
||
|
{
|
||
|
--idx;
|
||
|
D3DDevice_DrawIndexedVertices( m_primitive_type, m_num_indices[idx], mp_index_buffer[idx] );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Dbg_Assert( 0 );
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if( dist < mp_index_lod_data[idx] )
|
||
|
{
|
||
|
// This is the index set we want.
|
||
|
D3DDevice_DrawIndexedVertices( m_primitive_type, m_num_indices[idx], mp_index_buffer[idx] );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Submit.
|
||
|
D3DDevice_DrawIndexedVertices( m_primitive_type, m_num_indices[0], mp_index_buffer[0] );
|
||
|
}
|
||
|
|
||
|
// Deal with meshes that set no anisotropic filtering.
|
||
|
if( m_flags & MESH_FLAG_NO_ANISOTROPIC )
|
||
|
{
|
||
|
if( stage_zero_minfilter != D3DTEXF_LINEAR )
|
||
|
{
|
||
|
D3DDevice_SetTextureStageState( 0, D3DTSS_MINFILTER, stage_zero_minfilter );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Deal with meshes that set no z-write.
|
||
|
if( m_flags & MESH_FLAG_NO_ZWRITE )
|
||
|
{
|
||
|
if( zwrite == TRUE )
|
||
|
{
|
||
|
D3DDevice_SetRenderState( D3DRS_ZWRITEENABLE, zwrite );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
sMesh *sMesh::Clone( bool instance )
|
||
|
{
|
||
|
sMesh *p_clone = new sMesh();
|
||
|
|
||
|
// Copy over basic details.
|
||
|
CopyMemory( p_clone, this, sizeof( sMesh ));
|
||
|
|
||
|
if( instance )
|
||
|
{
|
||
|
p_clone->m_flags |= MESH_FLAG_IS_INSTANCE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Build new vertex and index lists.
|
||
|
p_clone->mp_vertex_buffer[0] = AllocateVertexBuffer( p_clone->m_vertex_stride * p_clone->m_num_vertices );
|
||
|
|
||
|
BYTE *p_byte_src, *p_byte_dest;
|
||
|
if( D3D_OK != mp_vertex_buffer[0]->Lock( 0, 0, &p_byte_src, D3DLOCK_READONLY ))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
if( D3D_OK != p_clone->mp_vertex_buffer[0]->Lock( 0, 0, &p_byte_dest, 0 ))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Copy over vertex information.
|
||
|
CopyMemory( p_byte_dest, p_byte_src, p_clone->m_vertex_stride * p_clone->m_num_vertices );
|
||
|
|
||
|
// Create index buffer(s) and copy over index information.
|
||
|
for( int ib = 0; ib < MAX_INDEX_BUFFERS; ++ib )
|
||
|
{
|
||
|
if( p_clone->m_num_indices[ib] > 0 )
|
||
|
{
|
||
|
p_clone->mp_index_buffer[ib] = new uint16[p_clone->m_num_indices[ib]];
|
||
|
CopyMemory( p_clone->mp_index_buffer[ib], mp_index_buffer[ib], sizeof( uint16 ) * p_clone->m_num_indices[ib] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Handle duplicate vertex buffers if they exist.
|
||
|
if( m_num_vertex_buffers > 1 )
|
||
|
{
|
||
|
p_clone->mp_vertex_buffer[1] = NULL;
|
||
|
p_clone->CreateDuplicateVertexBuffers( m_num_vertex_buffers - 1 );
|
||
|
}
|
||
|
}
|
||
|
return p_clone;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
IDirect3DVertexBuffer8 *sMesh::AllocateVertexBuffer( uint32 size )
|
||
|
{
|
||
|
uint8 *p_vb = new uint8[sizeof( IDirect3DVertexBuffer8 ) + size];
|
||
|
IDirect3DVertexBuffer8 *p_vb_ret = (IDirect3DVertexBuffer8*)p_vb;
|
||
|
|
||
|
XGSetVertexBufferHeader( 0, 0, 0, 0, p_vb_ret, 0 );
|
||
|
p_vb_ret->Register( p_vb + sizeof( IDirect3DVertexBuffer8 ));
|
||
|
|
||
|
return p_vb_ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::Crunch( void )
|
||
|
{
|
||
|
uint16 *p_indices = mp_index_buffer[0];
|
||
|
|
||
|
uint32 i0 = p_indices[0];
|
||
|
uint32 i1 = p_indices[1];
|
||
|
|
||
|
uint32 invalid = 0;
|
||
|
uint32 total_invalid = 0;
|
||
|
bool crunch = false;
|
||
|
|
||
|
for( uint32 i = 2; i < m_num_indices[0]; ++i )
|
||
|
{
|
||
|
uint32 i2 = p_indices[i];
|
||
|
|
||
|
if(( i0 == i1 ) || ( i0 == i2 ) || ( i1 == i2 ))
|
||
|
{
|
||
|
++invalid;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( invalid > 5 )
|
||
|
{
|
||
|
if(( invalid & 1 ) == 0 )
|
||
|
{
|
||
|
// printf( "Crunching %d indices (even)\n", invalid - 4 );
|
||
|
|
||
|
// Ensure the leading and trailing degenerate indices are correct.
|
||
|
p_indices[i - 3] = p_indices[i - 2];
|
||
|
p_indices[i - invalid] = p_indices[i - invalid - 1];
|
||
|
|
||
|
// With an even number of invalid entries, the wind order won't change during crunch.
|
||
|
MoveMemory( p_indices + i - invalid + 1, p_indices + i - 3, sizeof( uint16 ) * ( m_num_indices[0] - i + 3 ));
|
||
|
|
||
|
m_num_indices[0] -= (uint16)( invalid - 4 );
|
||
|
i -= invalid - 4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// printf( "Crunching %d indices (odd)\n", invalid - 5 );
|
||
|
|
||
|
// Ensure the leading and trailing degenerate indices are correct.
|
||
|
p_indices[i - 3] = p_indices[i - 2];
|
||
|
p_indices[i - invalid] = p_indices[i - invalid - 1];
|
||
|
p_indices[i - invalid + 1] = p_indices[i - invalid];
|
||
|
|
||
|
// With an odd number of invalid entries, the wind order will change during crunch, so use one extra index.
|
||
|
MoveMemory( p_indices + i - invalid + 2, p_indices + i - 3, sizeof( uint16 ) * ( m_num_indices[0] - i + 3 ));
|
||
|
m_num_indices[0] -= (uint16)( invalid - 5 );
|
||
|
i -= invalid - 5;
|
||
|
}
|
||
|
}
|
||
|
invalid = 0;
|
||
|
}
|
||
|
|
||
|
i0 = i1;
|
||
|
i1 = i2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::SetBillboardData( uint32 type, Mth::Vector & pivot_pos, Mth::Vector & pivot_axis )
|
||
|
{
|
||
|
Dbg_Assert( mp_billboard_data == NULL );
|
||
|
|
||
|
// Create the billboard data.
|
||
|
mp_billboard_data = new sBillboardData;
|
||
|
|
||
|
// Determine the billboard type.
|
||
|
if( type == 1 )
|
||
|
{
|
||
|
mp_billboard_data->m_type = sBillboardData::vBILLBOARD_TYPE_SCREEN_ALIGNED;
|
||
|
}
|
||
|
else if( type == 2 )
|
||
|
{
|
||
|
// Axial aligned. See if this is y axis.
|
||
|
if( fabsf( Mth::DotProduct( pivot_axis, Mth::Vector( 0.0f, 1.0f, 0.0f ))) > 0.99f )
|
||
|
{
|
||
|
mp_billboard_data->m_type = sBillboardData::vBILLBOARD_TYPE_Y_AXIS_ALIGNED;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
mp_billboard_data->m_type = sBillboardData::vBILLBOARD_TYPE_ARBITRARY_AXIS_ALIGNED;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Dbg_Assert( 0 );
|
||
|
}
|
||
|
|
||
|
mp_billboard_data->m_pivot_pos = pivot_pos;
|
||
|
if( mp_billboard_data->m_type == sBillboardData::vBILLBOARD_TYPE_ARBITRARY_AXIS_ALIGNED )
|
||
|
{
|
||
|
mp_billboard_data->m_pivot_axis = pivot_axis;
|
||
|
}
|
||
|
|
||
|
// We need to go through at a low level and rebuild the vertex buffer. In all cases the
|
||
|
// mesh won't have been exported with normals, which we use for billboards to store the
|
||
|
// pivot-relative position, so we need to recalculate the vertex stride.
|
||
|
Dbg_Assert( m_normal_offset == 0 );
|
||
|
Dbg_Assert( m_diffuse_offset > 0 );
|
||
|
Dbg_Assert( m_uv0_offset > 0 );
|
||
|
Dbg_Assert( m_num_vertices == 4 );
|
||
|
Dbg_Assert( m_num_indices[0] == 4 );
|
||
|
|
||
|
// Add size of normal to vertex size.
|
||
|
int old_vertex_stride = m_vertex_stride;
|
||
|
int new_vertex_stride = old_vertex_stride + ( sizeof( float ) * 3 );
|
||
|
|
||
|
IDirect3DVertexBuffer8* p_old_buffer = mp_vertex_buffer[0];
|
||
|
IDirect3DVertexBuffer8* p_new_buffer = AllocateVertexBuffer( new_vertex_stride * 4 );
|
||
|
|
||
|
// Lock old buffer (read) and new buffer (write).
|
||
|
BYTE *p_old_vb_data;
|
||
|
BYTE *p_new_vb_data;
|
||
|
p_old_buffer->Lock( 0, 0, &p_old_vb_data, D3DLOCK_READONLY | D3DLOCK_NOFLUSH );
|
||
|
p_new_buffer->Lock( 0, 0, &p_new_vb_data, 0 );
|
||
|
|
||
|
// Calculate the normal of the billboard, using the first tri.
|
||
|
float *p_vert;
|
||
|
uint16 indices[4];
|
||
|
indices[0] = mp_index_buffer[0][0];
|
||
|
indices[1] = mp_index_buffer[0][1];
|
||
|
indices[2] = mp_index_buffer[0][2];
|
||
|
indices[3] = mp_index_buffer[0][3];
|
||
|
|
||
|
p_vert = (float*)( p_old_vb_data + ( indices[0] * old_vertex_stride ));
|
||
|
Mth::Vector v0( p_vert[0], p_vert[1], p_vert[2] );
|
||
|
p_vert = (float*)( p_old_vb_data + ( indices[1] * old_vertex_stride ));
|
||
|
Mth::Vector v1( p_vert[0], p_vert[1], p_vert[2] );
|
||
|
p_vert = (float*)( p_old_vb_data + ( indices[2] * old_vertex_stride ));
|
||
|
Mth::Vector v2( p_vert[0], p_vert[1], p_vert[2] );
|
||
|
Mth::Vector normal = Mth::CrossProduct(( v1 - v0 ), ( v2 - v0 )).Normalize();
|
||
|
|
||
|
// Given the normal, calculate the local right and up (u and v) vectors, based on the billboard type.
|
||
|
Mth::Vector u, v;
|
||
|
|
||
|
switch( mp_billboard_data->m_type )
|
||
|
{
|
||
|
case sBillboardData::vBILLBOARD_TYPE_SCREEN_ALIGNED:
|
||
|
case sBillboardData::vBILLBOARD_TYPE_Y_AXIS_ALIGNED:
|
||
|
case sBillboardData::vBILLBOARD_TYPE_WORLD_ORIENTED:
|
||
|
{
|
||
|
// Use the world 'up' vector to generate the 'u' vector.
|
||
|
u = Mth::CrossProduct( normal, Mth::Vector( 0.0f, 1.0f, 0.0f )).Normalize();
|
||
|
|
||
|
// Use the 'u' vector and the normal vector to generate the 'v' vector.
|
||
|
v = Mth::CrossProduct( u, normal ).Normalize();
|
||
|
break;
|
||
|
}
|
||
|
case sBillboardData::vBILLBOARD_TYPE_ARBITRARY_AXIS_ALIGNED:
|
||
|
{
|
||
|
// Use the pivot axis and the normal vector to generate the 'u' vector.
|
||
|
u = Mth::CrossProduct( normal, pivot_axis ).Normalize();
|
||
|
|
||
|
// Use the 'u' vector and the normal vector to generate the 'v' vector.
|
||
|
v = Mth::CrossProduct( u, normal ).Normalize();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for( int i = 0; i < 4; ++i )
|
||
|
{
|
||
|
// The new position is actually the position of the pivot point for the billboard.
|
||
|
float *p_pos_old = (float*)( p_old_vb_data + ( i * old_vertex_stride ));
|
||
|
float *p_pos_new = (float*)( p_new_vb_data + ( i * new_vertex_stride ));
|
||
|
p_pos_new[0] = pivot_pos[X];
|
||
|
p_pos_new[1] = pivot_pos[Y];
|
||
|
p_pos_new[2] = pivot_pos[Z];
|
||
|
|
||
|
// Introduce normal (which is actually the position of the vertex relative to the pivot).
|
||
|
Mth::Vector pos_relative_to_pivot( p_pos_old[0] - pivot_pos[X], p_pos_old[1] - pivot_pos[Y], p_pos_old[2] - pivot_pos[Z] );
|
||
|
|
||
|
p_pos_new[3] = Mth::DotProduct( pos_relative_to_pivot, u );
|
||
|
p_pos_new[4] = Mth::DotProduct( pos_relative_to_pivot, v );
|
||
|
p_pos_new[5] = Mth::DotProduct( pos_relative_to_pivot, normal );
|
||
|
|
||
|
// Copy color.
|
||
|
D3DCOLOR *p_col_old = (D3DCOLOR*)( p_old_vb_data + ( i * old_vertex_stride ) + m_diffuse_offset );
|
||
|
D3DCOLOR *p_col_new = (D3DCOLOR*)( p_new_vb_data + ( i * new_vertex_stride ) + m_diffuse_offset + ( sizeof( float ) * 3 ));
|
||
|
p_col_new[0] = p_col_old[0];
|
||
|
|
||
|
// Copy uv0...
|
||
|
float *p_uv0_old = (float*)( p_old_vb_data + ( i * old_vertex_stride ) + m_uv0_offset );
|
||
|
float *p_uv0_new = (float*)( p_new_vb_data + ( i * new_vertex_stride ) + m_uv0_offset + ( sizeof( float ) * 3 ));
|
||
|
p_uv0_new[0] = p_uv0_old[0];
|
||
|
p_uv0_new[1] = p_uv0_old[1];
|
||
|
|
||
|
// ...and additional uv's if present.
|
||
|
if(( m_vertex_shader[0] & D3DFVF_TEXCOUNT_MASK ) > D3DFVF_TEX1 )
|
||
|
{
|
||
|
p_uv0_new[2] = p_uv0_old[2];
|
||
|
p_uv0_new[3] = p_uv0_old[3];
|
||
|
}
|
||
|
if(( m_vertex_shader[0] & D3DFVF_TEXCOUNT_MASK ) > D3DFVF_TEX2 )
|
||
|
{
|
||
|
p_uv0_new[4] = p_uv0_old[4];
|
||
|
p_uv0_new[5] = p_uv0_old[5];
|
||
|
}
|
||
|
if(( m_vertex_shader[0] & D3DFVF_TEXCOUNT_MASK ) > D3DFVF_TEX3 )
|
||
|
{
|
||
|
p_uv0_new[6] = p_uv0_old[6];
|
||
|
p_uv0_new[7] = p_uv0_old[7];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Now fix up the mesh. Flag the mesh as being a billboard (stop the mesh being rendered by the regular pathway).
|
||
|
m_flags |= sMesh::MESH_FLAG_BILLBOARD;
|
||
|
|
||
|
// Switch vertex buffers, deleting the old one.
|
||
|
mp_vertex_buffer[0] = p_new_buffer;
|
||
|
delete p_old_buffer;
|
||
|
|
||
|
// Set the new vertex stride, diffuse and uv0 offset (and normal offset, just to be complete).
|
||
|
m_vertex_stride = new_vertex_stride;
|
||
|
m_diffuse_offset += sizeof( float ) * 3;
|
||
|
m_uv0_offset += sizeof( float ) * 3;
|
||
|
m_normal_offset = sizeof( float ) * 3;
|
||
|
|
||
|
// Copy the new vertex buffer into existing buffered buffers if m_num_vertex_buffers > 1.
|
||
|
if( m_num_vertex_buffers > 1 )
|
||
|
{
|
||
|
BYTE *p_buffer0;
|
||
|
BYTE *p_bufferN;
|
||
|
mp_vertex_buffer[0]->Lock( 0, 0, &p_buffer0, D3DLOCK_READONLY | D3DLOCK_NOFLUSH );
|
||
|
for( int vb = 1; vb < m_num_vertex_buffers; ++vb )
|
||
|
{
|
||
|
delete mp_vertex_buffer[vb];
|
||
|
mp_vertex_buffer[vb] = AllocateVertexBuffer( new_vertex_stride * 4 );
|
||
|
mp_vertex_buffer[vb]->Lock( 0, 0, &p_bufferN, 0 );
|
||
|
CopyMemory( p_bufferN, p_buffer0, new_vertex_stride * 4 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set the new vertex shader.
|
||
|
m_vertex_shader[0] = 999;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::SetBoundingData( Mth::Vector & sphere_center, float radius, Mth::Vector & bb_min, Mth::Vector & bb_max )
|
||
|
{
|
||
|
// m_bbox.Set( bb_min, bb_max );
|
||
|
|
||
|
m_sphere_center = D3DXVECTOR3( sphere_center[X], sphere_center[Y], sphere_center[Z] );
|
||
|
m_sphere_radius = radius;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::Initialize( int num_vertices,
|
||
|
float *p_positions,
|
||
|
float *p_normals,
|
||
|
float *p_tex_coords,
|
||
|
int num_tc_sets,
|
||
|
DWORD *p_colors,
|
||
|
int num_index_sets, // How many sets of indices there are (usually 1 set)
|
||
|
int *p_num_indices, // Pointer to an array of ints containing number of indices per set
|
||
|
uint16 **pp_indices, // Pointer to an array of pointers to the actual indices
|
||
|
unsigned long material_checksum,
|
||
|
void *p_scene,
|
||
|
uint16 *p_matrix_indices,
|
||
|
uint32 *p_weights,
|
||
|
char *p_vc_wibble_anims )
|
||
|
{
|
||
|
// First thing to do is grab the material pointer for this mesh.
|
||
|
mp_material = ((sScene*)p_scene )->GetMaterial( material_checksum );
|
||
|
if( mp_material == NULL )
|
||
|
{
|
||
|
Dbg_Assert( 0 );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(( num_index_sets == 0 ) || ( p_num_indices[0] == 0 ))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
uint16 min_index = ( pp_indices[0] )[0];
|
||
|
uint16 max_index = ( pp_indices[0] )[0];
|
||
|
for( int i = 0; i < p_num_indices[0]; ++i )
|
||
|
{
|
||
|
if(( pp_indices[0] )[i] > max_index )
|
||
|
{
|
||
|
max_index = ( pp_indices[0] )[i];
|
||
|
}
|
||
|
else if(( pp_indices[0] )[i] < min_index )
|
||
|
{
|
||
|
min_index = ( pp_indices[0] )[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( max_index >= num_vertices )
|
||
|
{
|
||
|
// Error!
|
||
|
Dbg_Assert( 0 );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Grab top-down heap memory for the mesh workspace buffer. This will need to be as big as the maximum vertex indexed.
|
||
|
int16 *p_mesh_workspace_array = new (Mem::Manager::sHandle().TopDownHeap()) int16[max_index + 1];
|
||
|
|
||
|
// Setup workspace buffer.
|
||
|
memset( p_mesh_workspace_array, 1, sizeof( int16 ) * ( max_index + 1 ));
|
||
|
for( int i = 0; i < p_num_indices[0]; ++i )
|
||
|
{
|
||
|
p_mesh_workspace_array[( pp_indices[0] )[i]] = 0;
|
||
|
}
|
||
|
|
||
|
// Now figure the wasted space.
|
||
|
int wasted_verts = 0;
|
||
|
for( int i = min_index; i <= max_index; ++i )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[i] != 0 )
|
||
|
++wasted_verts;
|
||
|
}
|
||
|
|
||
|
// Now figure the total number of vertices required for this mesh, to span the min->max indices.
|
||
|
uint16 vertices_for_this_mesh = ( max_index - min_index + 1 ) - wasted_verts;
|
||
|
m_num_vertices = vertices_for_this_mesh;
|
||
|
|
||
|
// Create the index buffer(s). (Should be 16byte aligned for best performance).
|
||
|
for( int ib = 0; ib < num_index_sets; ++ib )
|
||
|
{
|
||
|
mp_index_buffer[ib] = new uint16[p_num_indices[ib]];
|
||
|
m_num_indices[ib] = p_num_indices[ib];
|
||
|
}
|
||
|
|
||
|
// Use the material flags to figure the vertex format.
|
||
|
int vertex_size = 3 * sizeof( float );
|
||
|
|
||
|
// Include weights (for weighted animation) if present.
|
||
|
uint32 biggest_index_used = 0;
|
||
|
if( p_weights )
|
||
|
{
|
||
|
Dbg_Assert( p_matrix_indices );
|
||
|
|
||
|
// Calculate the biggest weight used.
|
||
|
uint32* p_weight_read = p_weights + min_index;
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
// This vertex is used.
|
||
|
uint32 w2 = (( p_weight_read[0] >> 22 ) & 0x3FF );
|
||
|
if( w2 > 0 )
|
||
|
{
|
||
|
biggest_index_used = 2;
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint32 w1 = (( p_weight_read[0] >> 11 ) & 0x7FF );
|
||
|
if( w1 > 0 )
|
||
|
{
|
||
|
biggest_index_used = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
++p_weight_read;
|
||
|
}
|
||
|
vertex_size += sizeof( uint32 );
|
||
|
}
|
||
|
|
||
|
// Include indices (for weighted animation) if present.
|
||
|
if( p_matrix_indices )
|
||
|
{
|
||
|
Dbg_Assert( p_weights );
|
||
|
vertex_size += sizeof( uint16 ) * 4;
|
||
|
}
|
||
|
|
||
|
// Texture coordinates.
|
||
|
uint32 tex_coord_pass = 0;
|
||
|
bool env_mapped = false;
|
||
|
if( p_tex_coords )
|
||
|
{
|
||
|
for( uint32 pass = 0; pass < mp_material->m_passes; ++pass )
|
||
|
{
|
||
|
if( mp_material->m_flags[pass] & MATFLAG_ENVIRONMENT )
|
||
|
{
|
||
|
env_mapped = true;
|
||
|
}
|
||
|
|
||
|
// Only need UV's for this stage if it is *not* environment mapped.
|
||
|
if(( mp_material->mp_tex[pass] ) && ( !( mp_material->m_flags[pass] & MATFLAG_ENVIRONMENT )))
|
||
|
{
|
||
|
// Will need uv for this pass and all before it.
|
||
|
tex_coord_pass = pass + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for( uint32 pass = 0; pass < mp_material->m_passes; ++pass )
|
||
|
{
|
||
|
if( mp_material->m_flags[pass] & MATFLAG_ENVIRONMENT )
|
||
|
{
|
||
|
env_mapped = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( tex_coord_pass > 0 )
|
||
|
{
|
||
|
vertex_size += 2 * sizeof( float ) * tex_coord_pass;
|
||
|
}
|
||
|
|
||
|
// Assume no normals for now, unless weight information indicates an animating mesh.
|
||
|
bool use_normals = false;
|
||
|
bool use_packed_normals = false;
|
||
|
|
||
|
if( p_normals || p_weights || env_mapped )
|
||
|
{
|
||
|
// Need to include normals. They will be packed differently for weighted meshes.
|
||
|
use_normals = true;
|
||
|
if( p_weights )
|
||
|
{
|
||
|
use_packed_normals = true;
|
||
|
vertex_size += sizeof( uint32 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vertex_size += sizeof( float ) * 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool use_colors = false;
|
||
|
if( p_colors )
|
||
|
{
|
||
|
// The raw vertex data does contain vertex colors.
|
||
|
vertex_size += sizeof( D3DCOLOR );
|
||
|
use_colors = true;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Create the vertex buffer.
|
||
|
m_vertex_stride = vertex_size;
|
||
|
|
||
|
// One allocation for the header and the data buffer.
|
||
|
mp_vertex_buffer[0] = AllocateVertexBuffer( vertex_size * vertices_for_this_mesh );
|
||
|
|
||
|
// Lock the vertex buffer.
|
||
|
BYTE* p_byte;
|
||
|
if( D3D_OK != mp_vertex_buffer[0]->Lock( 0, // Offset to lock.
|
||
|
0, // Size to lock ( 0 means all).
|
||
|
&p_byte, // Pointer to data.
|
||
|
D3DLOCK_NOFLUSH )) // Flags.
|
||
|
{
|
||
|
Dbg_Assert( 0 );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Copy in vertex position data (for vertices that are used).
|
||
|
uint32 byte_write_offset = 0;
|
||
|
float* p_read = p_positions + ( min_index * 3 );
|
||
|
float* p_write = (float*)p_byte;
|
||
|
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
// This vertex is used.
|
||
|
p_write[0] = p_read[0];
|
||
|
p_write[1] = p_read[1];
|
||
|
p_write[2] = p_read[2];
|
||
|
p_write = (float*)((char*)p_write + vertex_size );
|
||
|
}
|
||
|
p_read += 3;
|
||
|
}
|
||
|
|
||
|
byte_write_offset += sizeof( float ) * 3;
|
||
|
m_vertex_shader[0] |= D3DFVF_XYZ;
|
||
|
|
||
|
// Copy in vertex weight data.
|
||
|
if( p_weights )
|
||
|
{
|
||
|
uint32* p_weight_read = p_weights + min_index;
|
||
|
uint32* p_weight_write = (uint32*)((char*)p_byte + byte_write_offset );
|
||
|
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
// This vertex is used.
|
||
|
p_weight_write[0] = p_weight_read[0];
|
||
|
p_weight_write = (uint32*)((char*)p_weight_write + vertex_size );
|
||
|
}
|
||
|
++p_weight_read;
|
||
|
}
|
||
|
byte_write_offset += sizeof( uint32 );
|
||
|
|
||
|
// No fvf flag setting, since it will be determined at the end.
|
||
|
}
|
||
|
|
||
|
// Copy in vertex matrix index data.
|
||
|
if( p_matrix_indices )
|
||
|
{
|
||
|
uint16* p_index_read = p_matrix_indices + ( min_index * 4 );
|
||
|
uint16* p_index_write = (uint16*)((char*)p_byte + byte_write_offset );
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
// Have to multiply the indices by three to get the correct register offset, since there are 3 registers
|
||
|
// per matrix.
|
||
|
p_index_write[0] = p_index_read[0] * 3;
|
||
|
p_index_write[1] = p_index_read[1] * 3;
|
||
|
p_index_write[2] = p_index_read[2] * 3;
|
||
|
p_index_write[3] = p_index_read[3] * 3;
|
||
|
p_index_write = (uint16*)((char*)p_index_write + vertex_size );
|
||
|
}
|
||
|
p_index_read += 4;
|
||
|
}
|
||
|
byte_write_offset += sizeof( uint16 ) * 4;
|
||
|
|
||
|
// No fvf flag setting, since it will be determined at the end.
|
||
|
}
|
||
|
|
||
|
// Copy in normals data.
|
||
|
if( use_normals )
|
||
|
{
|
||
|
m_normal_offset = (uint8)byte_write_offset;
|
||
|
if( use_packed_normals )
|
||
|
{
|
||
|
float *p_read = p_normals + ( min_index * 3 );
|
||
|
uint32 *p_write = (uint32*)((char*)p_byte + byte_write_offset );
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
// The packed normal format is as follows:
|
||
|
// 31 0
|
||
|
// |----- 10 -----|----- 11 ------|----- 11 ------|
|
||
|
// | z | y | x |
|
||
|
uint32 snx = Ftoi_ASM( p_read[0] * 1023.0f );
|
||
|
uint32 sny = Ftoi_ASM( p_read[1] * 1023.0f );
|
||
|
uint32 snz = Ftoi_ASM( p_read[2] * 511.0f );
|
||
|
p_write[0] = ( snx & 0x7FF ) | (( sny & 0x7FF ) << 11 ) | (( snz & 0x3FF ) << 22 );
|
||
|
p_write = (uint32*)((char*)p_write + vertex_size );
|
||
|
}
|
||
|
p_read += 3;
|
||
|
}
|
||
|
byte_write_offset += sizeof( uint32 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
float* p_read = p_normals + ( min_index * 3 );
|
||
|
float* p_write = (float*)((char*)p_byte + byte_write_offset );
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
p_write[0] = p_read[0];
|
||
|
p_write[1] = p_read[1];
|
||
|
p_write[2] = p_read[2];
|
||
|
p_write = (float*)((char*)p_write + vertex_size );
|
||
|
}
|
||
|
p_read += 3;
|
||
|
}
|
||
|
byte_write_offset += sizeof( float ) * 3;
|
||
|
}
|
||
|
m_vertex_shader[0] |= D3DFVF_NORMAL;
|
||
|
}
|
||
|
|
||
|
// Copy in vertex color data.
|
||
|
if( use_colors )
|
||
|
{
|
||
|
m_diffuse_offset = (uint8)byte_write_offset;
|
||
|
DWORD* p_col_read = p_colors + min_index;
|
||
|
DWORD* p_col_write = (DWORD*)((char*)p_byte + byte_write_offset );
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
p_col_write[0] = p_col_read[0];
|
||
|
p_col_write = (DWORD*)((char*)p_col_write + vertex_size );
|
||
|
}
|
||
|
p_col_read++;
|
||
|
}
|
||
|
byte_write_offset += sizeof( DWORD );
|
||
|
m_vertex_shader[0] |= D3DFVF_DIFFUSE;
|
||
|
}
|
||
|
|
||
|
// Copy in vertex texture coordinate data.
|
||
|
if(( tex_coord_pass > 0 ) && ( p_tex_coords != NULL ))
|
||
|
{
|
||
|
m_uv0_offset = (uint8)byte_write_offset;
|
||
|
p_read = p_tex_coords + ( min_index * 2 * num_tc_sets );
|
||
|
p_write = (float*)((char*)p_byte + byte_write_offset );
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
for( uint32 pass = 0; pass < tex_coord_pass; ++pass )
|
||
|
{
|
||
|
p_write[( pass * 2 ) + 0] = p_read[( pass * 2 ) + 0];
|
||
|
p_write[( pass * 2 ) + 1] = p_read[( pass * 2 ) + 1];
|
||
|
}
|
||
|
p_write = (float*)((char*)p_write + vertex_size );
|
||
|
}
|
||
|
p_read = p_read + ( num_tc_sets * 2 );
|
||
|
}
|
||
|
byte_write_offset += sizeof( float ) * 2 * tex_coord_pass;
|
||
|
|
||
|
switch( tex_coord_pass )
|
||
|
{
|
||
|
case 1:
|
||
|
{
|
||
|
m_vertex_shader[0] |= D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2( 0 );
|
||
|
break;
|
||
|
}
|
||
|
case 2:
|
||
|
{
|
||
|
m_vertex_shader[0] |= D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2( 0 ) | D3DFVF_TEXCOORDSIZE2( 1 );
|
||
|
break;
|
||
|
}
|
||
|
case 3:
|
||
|
{
|
||
|
m_vertex_shader[0] |= D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE2( 0 ) | D3DFVF_TEXCOORDSIZE2( 1 ) | D3DFVF_TEXCOORDSIZE2( 2 );
|
||
|
break;
|
||
|
}
|
||
|
case 4:
|
||
|
{
|
||
|
m_vertex_shader[0] |= D3DFVF_TEX4 | D3DFVF_TEXCOORDSIZE2( 0 ) | D3DFVF_TEXCOORDSIZE2( 1 ) | D3DFVF_TEXCOORDSIZE2( 2 ) | D3DFVF_TEXCOORDSIZE2( 3 );
|
||
|
break;
|
||
|
}
|
||
|
default:
|
||
|
{
|
||
|
Dbg_MsgAssert( 0, ( "Bad number of passes" ));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create the vertex color wibble array if data is present.
|
||
|
if( p_vc_wibble_anims )
|
||
|
{
|
||
|
mp_vc_wibble_data = new char[m_num_vertices];
|
||
|
int vc_wibble_data_offset = 0;
|
||
|
|
||
|
for( int v = min_index; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
mp_vc_wibble_data[vc_wibble_data_offset++] = p_vc_wibble_anims[v];
|
||
|
}
|
||
|
}
|
||
|
// Double buffer the vertex buffer.
|
||
|
CreateDuplicateVertexBuffers( 1 );
|
||
|
}
|
||
|
|
||
|
// Process the workspace array.
|
||
|
int offset = 0;
|
||
|
for( int v = 0; v <= max_index; ++v )
|
||
|
{
|
||
|
if( p_mesh_workspace_array[v] == 0 )
|
||
|
{
|
||
|
// This vertex is used.
|
||
|
p_mesh_workspace_array[v] = offset;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This vertex is not used. Update the offset for the next used vertex.
|
||
|
--offset;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy in index data, normalising the indices for this vertex buffer (i.e. so the lowest index will reference
|
||
|
// vertex 0 in the buffer built specifically for this mesh).
|
||
|
for( int ib = 0; ib < num_index_sets; ++ib )
|
||
|
{
|
||
|
for( int i = 0; i < p_num_indices[ib]; ++i )
|
||
|
{
|
||
|
uint16 idx = ( pp_indices[ib] )[i];
|
||
|
mp_index_buffer[ib][i] = idx + p_mesh_workspace_array[idx];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Can now remove the mesh workspace array.
|
||
|
delete [] p_mesh_workspace_array;
|
||
|
|
||
|
// Set the correct vertex shader if a weighted mesh.
|
||
|
// The number of indices used will be one more than the biggest index used (given 0 base).
|
||
|
if( p_weights )
|
||
|
{
|
||
|
m_vertex_shader[0] = GetVertexShader( use_colors, ( mp_material->m_flags[0] & MATFLAG_SPECULAR ) ? true : false, biggest_index_used + 1 );
|
||
|
}
|
||
|
|
||
|
// Set the pixel shader regardless.
|
||
|
GetPixelShader( mp_material, &m_pixel_shader );
|
||
|
|
||
|
if( num_index_sets > 1 )
|
||
|
{
|
||
|
mp_index_lod_data = new float[num_index_sets];
|
||
|
for( int d = 0; d < num_index_sets; ++d )
|
||
|
{
|
||
|
float dist = ( 15.0f + ( d * 10.0f )) * 12.0f;
|
||
|
mp_index_lod_data[d] = dist;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/******************************************************************/
|
||
|
/* */
|
||
|
/* */
|
||
|
/******************************************************************/
|
||
|
void sMesh::DrawBoundingSphere( void )
|
||
|
{
|
||
|
# ifdef __NOPT_ASSERT__
|
||
|
const uint32 NUM_SPHERE_POINTS = 64;
|
||
|
|
||
|
static uint32 sphere_buffer[NUM_SPHERE_POINTS * 4];
|
||
|
|
||
|
D3DXMATRIX *p_matrix = (D3DXMATRIX*)&NxXbox::EngineGlobals.view_matrix;
|
||
|
Mth::Vector up( 0.0f, 1.0f, 0.0f );
|
||
|
|
||
|
// Get the 'right' vector as the cross product of camera 'at and world 'up'.
|
||
|
Mth::Vector at( p_matrix->m[0][2], p_matrix->m[1][2], p_matrix->m[2][2] );
|
||
|
Mth::Vector screen_right = Mth::CrossProduct( at, up );
|
||
|
Mth::Vector screen_up = Mth::CrossProduct( screen_right, at );
|
||
|
|
||
|
screen_right.Normalize();
|
||
|
screen_up.Normalize();
|
||
|
|
||
|
set_vertex_shader( D3DFVF_XYZ | D3DFVF_DIFFUSE );
|
||
|
set_pixel_shader( PixelShader5 );
|
||
|
|
||
|
int index = 0;
|
||
|
float angle = 0.0f;
|
||
|
float angle_step = ( Mth::PI * 2.0f ) / (float)NUM_SPHERE_POINTS;
|
||
|
|
||
|
// Draw the screen aligned sphere.
|
||
|
for( uint32 i = 0; i < NUM_SPHERE_POINTS; ++i, angle += angle_step )
|
||
|
{
|
||
|
float x = m_sphere_center.x + ( m_sphere_radius * cosf( angle ) * screen_right[X] ) + ( m_sphere_radius * sinf( angle ) * screen_up[X] );
|
||
|
float y = m_sphere_center.y + ( m_sphere_radius * cosf( angle ) * screen_right[Y] ) + ( m_sphere_radius * sinf( angle ) * screen_up[Y] );
|
||
|
float z = m_sphere_center.z + ( m_sphere_radius * cosf( angle ) * screen_right[Z] ) + ( m_sphere_radius * sinf( angle ) * screen_up[Z] );
|
||
|
|
||
|
sphere_buffer[index++] = *((uint32*)&x );
|
||
|
sphere_buffer[index++] = *((uint32*)&y );
|
||
|
sphere_buffer[index++] = *((uint32*)&z );
|
||
|
sphere_buffer[index++] = 0x80800000;
|
||
|
}
|
||
|
D3DDevice_DrawVerticesUP( D3DPT_LINELOOP, NUM_SPHERE_POINTS, sphere_buffer, sizeof( uint32 ) * 4 );
|
||
|
|
||
|
// Draw the xz plane sphere.
|
||
|
index = 0;
|
||
|
angle = 0.0f;
|
||
|
for( uint32 i = 0; i < NUM_SPHERE_POINTS; ++i, angle += angle_step )
|
||
|
{
|
||
|
float x = m_sphere_center.x + ( m_sphere_radius * cosf( angle ));
|
||
|
float y = m_sphere_center.y;
|
||
|
float z = m_sphere_center.z + ( m_sphere_radius * sinf( angle ));
|
||
|
|
||
|
sphere_buffer[index++] = *((uint32*)&x );
|
||
|
sphere_buffer[index++] = *((uint32*)&y );
|
||
|
sphere_buffer[index++] = *((uint32*)&z );
|
||
|
sphere_buffer[index++] = 0x80800000;
|
||
|
}
|
||
|
D3DDevice_DrawVerticesUP( D3DPT_LINELOOP, NUM_SPHERE_POINTS, sphere_buffer, sizeof( uint32 ) * 4 );
|
||
|
# endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
} // namespace NxXbox
|
||
|
|
||
|
|