www.pudn.com > tomohide_fur.03.13.02.zip > FurMesh.cpp


//----------------------------------------------------------------------------- 
// File: FurMesh.cpp 
// 
// Copyright (C) 2001-2002 Tomohide Kano. All rights reserved. 
//----------------------------------------------------------------------------- 
 
#include  
#include  
#include "extensions.h" 
#include "FurMesh.h" 
 
struct FURVERTEX 
{ 
	D3DXVECTOR3 pos; 
	D3DXVECTOR2 tex1; 
	D3DXVECTOR2 tex2; 
	D3DXVECTOR2 scale; 
	D3DXVECTOR2 radius; 
	D3DXVECTOR3 ds; 
	D3DXVECTOR3 dt; 
	D3DXVECTOR3 normal; 
}; 
 
const GLuint OFFSET_POS    =  0 * sizeof(float); 
const GLuint OFFSET_TEX1   =  3 * sizeof(float); 
const GLuint OFFSET_TEX2   =  5 * sizeof(float); 
const GLuint OFFSET_SCALE  =  7 * sizeof(float); 
const GLuint OFFSET_RADIUS =  9 * sizeof(float); 
const GLuint OFFSET_DS     = 11 * sizeof(float); 
const GLuint OFFSET_DT     = 14 * sizeof(float); 
const GLuint OFFSET_NORMAL = 17 * sizeof(float); 
const GLuint STRIDE        = sizeof(FURVERTEX); // 80 bytes 
 
// partial derivatives of bivariate function 
const float DELTA = 0.01; 
inline D3DXVECTOR3 deriv_u(FurMesh::FUNC f, float u, float v) 
{ return (f(u+DELTA, v) - f(u-DELTA, v)) / (2*DELTA); } 
inline D3DXVECTOR3 deriv_v(FurMesh::FUNC f, float u, float v) 
{ return (f(u, v+DELTA) - f(u, v-DELTA)) / (2*DELTA); } 
inline D3DXVECTOR3 deriv_uu(FurMesh::FUNC f, float u, float v) 
{ return (deriv_u(f, u+DELTA, v) - deriv_u(f, u-DELTA, v)) / (2*DELTA); } 
inline D3DXVECTOR3 deriv_vv(FurMesh::FUNC f, float u, float v) 
{ return (deriv_v(f, u, v+DELTA) - deriv_v(f, u, v-DELTA)) / (2*DELTA); } 
inline D3DXVECTOR3 deriv_uv(FurMesh::FUNC f, float u, float v) 
{ return (deriv_u(f, u, v+DELTA) - deriv_u(f, u, v-DELTA)) / (2*DELTA); } 
 
 
//----------------------------------------------------------------------------- 
// FurMesh 
//----------------------------------------------------------------------------- 
FurMesh::FurMesh() 
{ 
	m_Name         = ""; 
	m_NumVertex    = 0; 
	m_NumIndex     = 0; 
	m_VertexBuffer = 0; 
	m_IndexBuffer  = 0; 
} 
 
 
//----------------------------------------------------------------------------- 
// ~FurMesh 
//----------------------------------------------------------------------------- 
FurMesh::~FurMesh() 
{ 
	glFreeObjectBufferATI(m_VertexBuffer); 
	glFreeObjectBufferATI(m_IndexBuffer); 
} 
 
 
//----------------------------------------------------------------------------- 
// Init 
//----------------------------------------------------------------------------- 
bool FurMesh::Init(const PARAM ¶m) 
{ 
	m_Name = param.name; 
 
	int num_u = param.num_u; 
	int num_v = param.num_v; 
	FUNC func = param.func; 
	float scale_s = param.fur_scale_s; 
	float scale_t = param.fur_scale_t; 
 
	m_NumVertex = (num_u + 1) * (num_v + 1); 
	m_NumIndex  = num_u * num_v * 6; 
 
	// vertex buffer 
	{ 
		int i, j; 
		FURVERTEX *pVertices = new FURVERTEX[m_NumVertex]; 
		FURVERTEX *p = pVertices; 
 
		for (j = 0; j <= num_v; j++) 
		for (i = 0; i <= num_u; i++) 
		{ 
			float u = float(i) / num_u; 
			float v = float(j) / num_v; 
 
			// vertex position 
			p->pos = func(u, v); 
 
			// texture coord for normal map 
			p->tex1 = D3DXVECTOR2(u, v); 
 
			// texture coord for fur texture 
			p->tex2 = D3DXVECTOR2(scale_s * u, scale_t * v); 
 
			// partial derivatives with respect to (u, v) 
			D3DXVECTOR3& Pu  = deriv_u(func, u, v); 
			D3DXVECTOR3& Pv  = deriv_v(func, u, v); 
			D3DXVECTOR3& Puu = deriv_uu(func, u, v); 
		//	D3DXVECTOR3& Puv = deriv_uv(func, u, v); 
			D3DXVECTOR3& Pvv = deriv_vv(func, u, v); 
 
			// basis vectors of local texture space 
			D3DXVec3Normalize(&p->ds, &Pu); 
			D3DXVec3Normalize(&p->dt, &Pv); 
			D3DXVec3Normalize(&p->normal, D3DXVec3Cross(&p->normal, &Pu, &Pv)); 
 
			// scale factor 
			p->scale.x = scale_s / D3DXVec3Length(&Pu); 
			p->scale.y = scale_t / D3DXVec3Length(&Pv); 
 
			// radii of curvature 
			{ 
				// first and second fundamental forms 
				// http://mathworld.wolfram.com/FundamentalForms.html 
				float E = D3DXVec3LengthSq(&Pu); 
			//	float F = D3DXVec3Dot(&Pu, &Pv); 
				float G = D3DXVec3LengthSq(&Pv); 
				float e = D3DXVec3Dot(&p->normal, &Puu); 
			//	float f = D3DXVec3Dot(&p->normal, &Puv); 
				float g = D3DXVec3Dot(&p->normal, &Pvv); 
 
				// normal curvatures in the directions of u and v 
				// http://mathworld.wolfram.com/NormalCurvature.html 
				float curvature_u = -e / E; 
				float curvature_v = -g / G; 
 
				// radii of curvature corresponding to the normal curvatures 
				// http://mathworld.wolfram.com/RadiusofCurvature.html 
				if (curvature_u < 0.001) curvature_u = 0.001; 
				p->radius.x = 1.0 / curvature_u; 
				if (curvature_v < 0.001) curvature_v = 0.001; 
				p->radius.y = 1.0 / curvature_v; 
 
				// to be accurate, principal curvatures should be taken into account... 
				// http://mathworld.wolfram.com/PrincipalCurvatures.html 
			} 
 
			p++; 
		} 
 
		m_VertexBuffer = glNewObjectBufferATI(m_NumVertex * sizeof(FURVERTEX), pVertices, GL_STATIC_ATI); 
		delete [] pVertices; 
	} 
 
	// index buffer (triangle list) 
	{ 
		int i, j, k; 
		GLuint *pIndices = new GLuint[m_NumIndex]; 
		GLuint *p = pIndices; 
 
		for (j = 0; j < num_v; j++) 
		{ 
			k = j * (num_u + 1); 
			for (i = 0; i < num_u; i++, k++) 
			{ 
				*p++ = k; 
				*p++ = k + 1; 
				*p++ = k + (num_u + 1); 
				*p++ = k + (num_u + 1) + 1; 
				*p++ = k + (num_u + 1); 
				*p++ = k + 1; 
			} 
		} 
 
		m_IndexBuffer = glNewObjectBufferATI(m_NumIndex * sizeof(GLuint), pIndices, GL_STATIC_ATI); 
		delete [] pIndices; 
	} 
 
	if (glGetError()) 
		return false; 
	return true; 
} 
 
 
//----------------------------------------------------------------------------- 
// Draw 
//----------------------------------------------------------------------------- 
void FurMesh::Draw() const 
{ 
	// element array 
	glEnableClientState(GL_ELEMENT_ARRAY_ATI); 
	glArrayObjectATI(GL_ELEMENT_ARRAY_ATI, 1, GL_UNSIGNED_INT, 0, m_IndexBuffer, 0); 
 
	// vertex position 
	glEnableClientState(GL_VERTEX_ARRAY); 
	glArrayObjectATI(GL_VERTEX_ARRAY, 3, GL_FLOAT, STRIDE, m_VertexBuffer, OFFSET_POS); 
 
	// texture coord for normal map 
	glClientActiveTextureARB(GL_TEXTURE0_ARB); 
	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
	glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 2, GL_FLOAT, STRIDE, m_VertexBuffer, OFFSET_TEX1); 
 
	// texture coord for fur texture 
	glClientActiveTextureARB(GL_TEXTURE1_ARB); 
	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
	glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 2, GL_FLOAT, STRIDE, m_VertexBuffer, OFFSET_TEX2); 
 
	// scale factor 
	glClientActiveTextureARB(GL_TEXTURE2_ARB); 
	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
	glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 2, GL_FLOAT, STRIDE, m_VertexBuffer, OFFSET_SCALE); 
 
	// radius of curvature 
	glClientActiveTextureARB(GL_TEXTURE3_ARB); 
	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
	glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 2, GL_FLOAT, STRIDE, m_VertexBuffer, OFFSET_RADIUS); 
 
	// tangent vector along s 
	glClientActiveTextureARB(GL_TEXTURE4_ARB); 
	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
	glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 3, GL_FLOAT, STRIDE, m_VertexBuffer, OFFSET_DS); 
 
	// tangent vector along t 
	glClientActiveTextureARB(GL_TEXTURE5_ARB); 
	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
	glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 3, GL_FLOAT, STRIDE, m_VertexBuffer, OFFSET_DT); 
 
	// normal vector 
	glEnableClientState(GL_NORMAL_ARRAY); 
	glArrayObjectATI(GL_NORMAL_ARRAY, 3, GL_FLOAT, STRIDE, m_VertexBuffer, OFFSET_NORMAL); 
 
	// draw triangle list 
	glDrawElementArrayATI(GL_TRIANGLES, m_NumIndex); 
 
	// disable arrays 
	glDisableClientState(GL_ELEMENT_ARRAY_ATI); 
	glDisableClientState(GL_VERTEX_ARRAY); 
	glDisableClientState(GL_NORMAL_ARRAY); 
	glClientActiveTextureARB(GL_TEXTURE0_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
	glClientActiveTextureARB(GL_TEXTURE1_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
	glClientActiveTextureARB(GL_TEXTURE2_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
	glClientActiveTextureARB(GL_TEXTURE3_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
	glClientActiveTextureARB(GL_TEXTURE4_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
	glClientActiveTextureARB(GL_TEXTURE5_ARB); glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
	glClientActiveTextureARB(GL_TEXTURE0_ARB); 
}