コード例 #1
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pPatch - 
//			*pPoints - 
//			&vecNormal - 
//			flArea - 
//-----------------------------------------------------------------------------
bool CVRADDispColl::InitPatch( int iPatch, int iParentPatch, int iChild, Vector *pPoints, int *pIndices, float &flArea )
{
	// Get the current patch.
	CPatch *pPatch = &g_Patches[iPatch];
	if ( !pPatch )
		return false;

	// Clear the patch data.
	memset( pPatch, 0, sizeof( CPatch ) );

	// Setup the parent if we are not the parent.
	CPatch *pParentPatch = NULL;
	if ( iParentPatch != g_Patches.InvalidIndex() )
	{
		// Get the parent patch.
		pParentPatch = &g_Patches[iParentPatch];
		if ( !pParentPatch )
			return false;
	}

	// Attach the face to the correct lists.
	if ( !pParentPatch )
	{
		// This is a parent.
		pPatch->ndxNext = g_FacePatches.Element( GetParentIndex() );
		g_FacePatches[GetParentIndex()] = iPatch;
		pPatch->faceNumber = GetParentIndex();
	}
	else
	{
		pPatch->ndxNext = g_Patches.InvalidIndex();
		pPatch->faceNumber = pParentPatch->faceNumber;

		// Attach to the parent patch.
		if ( iChild == 0 )
		{
			pParentPatch->child1 = iPatch;
		}
		else
		{
			pParentPatch->child2 = iPatch;
		}
	}

	// Initialize parent and children indices.
	pPatch->child1 = g_Patches.InvalidIndex();
	pPatch->child2 = g_Patches.InvalidIndex();
	pPatch->ndxNextClusterChild = g_Patches.InvalidIndex();
	pPatch->ndxNextParent = g_Patches.InvalidIndex();
	pPatch->parent = iParentPatch;

	// Get triangle edges.
	Vector vecEdges[3];
	vecEdges[0] = pPoints[1] - pPoints[0];
	vecEdges[1] = pPoints[2] - pPoints[0];
	vecEdges[2] = pPoints[2] - pPoints[1];

	// Find the longest edge.
//	float flEdgeLength = 0.0f;
//	for ( int iEdge = 0; iEdge < 3; ++iEdge )
//	{
//		if ( flEdgeLength < vecEdges[iEdge].Length() )
//		{
//			flEdgeLength = vecEdges[iEdge].Length();
//		}
//	}

	// Calculate the triangle normal and area.
	Vector vecNormal = vecEdges[1].Cross( vecEdges[0] );
	flArea = VectorNormalize( vecNormal );
	flArea *= 0.5f;

	// Initialize the patch scale.
	pPatch->scale[0] = pPatch->scale[1] = 1.0f;

	// Set the patch chop - minchop (that is what the minimum area is based on).
	pPatch->chop = dispchop;

	// Displacements are not sky!
	pPatch->sky = false;

	// Copy the winding.
	Vector vecCenter( 0.0f, 0.0f, 0.0f );
	pPatch->winding = AllocWinding( 3 );
	pPatch->winding->numpoints = 3;
	for ( int iPoint = 0; iPoint < 3; ++iPoint )
	{
		VectorCopy( pPoints[iPoint], pPatch->winding->p[iPoint] );
		VectorAdd( pPoints[iPoint], vecCenter, vecCenter );

		pPatch->indices[iPoint] = static_cast<short>( pIndices[iPoint] );
	}

	// Set the origin and normal.
	VectorScale( vecCenter, ( 1.0f / 3.0f ), vecCenter );
	VectorCopy( vecCenter, pPatch->origin );
	VectorCopy( vecNormal, pPatch->normal );

	// Create the plane.
	pPatch->plane = new dplane_t;
	if ( !pPatch->plane )
		return false;

	VectorCopy( vecNormal, pPatch->plane->normal );
	pPatch->plane->dist = vecNormal.Dot( pPoints[0] );
	pPatch->plane->type = PlaneTypeForNormal( pPatch->plane->normal );
	pPatch->planeDist = pPatch->plane->dist;

	// Set the area.
	pPatch->area = flArea;

	// Calculate the mins/maxs.
	Vector vecMin( FLT_MAX, FLT_MAX, FLT_MAX );
	Vector vecMax( FLT_MIN, FLT_MIN, FLT_MIN );
	for ( int iPoint = 0; iPoint < 3; ++iPoint )
	{
		for ( int iAxis = 0; iAxis < 3; ++iAxis )
		{
			vecMin[iAxis] = MIN( vecMin[iAxis], pPoints[iPoint][iAxis] );
			vecMax[iAxis] = MAX( vecMax[iAxis], pPoints[iPoint][iAxis] );
		}
	}

	VectorCopy( vecMin, pPatch->mins );
	VectorCopy( vecMax, pPatch->maxs );

	if ( !pParentPatch )
	{
		VectorCopy( vecMin, pPatch->face_mins );
		VectorCopy( vecMax, pPatch->face_maxs );
	}
	else
	{
		VectorCopy( pParentPatch->face_mins, pPatch->face_mins );
		VectorCopy( pParentPatch->face_maxs, pPatch->face_maxs );
	}

	// Check for bumpmap.
	dface_t *pFace = dfaces + pPatch->faceNumber;
	texinfo_t *pTexInfo = &texinfo[pFace->texinfo];
	pPatch->needsBumpmap = pTexInfo->flags & SURF_BUMPLIGHT ? true : false;

	// Misc...
	pPatch->m_IterationKey = 0;

	// Get the base light for the face.
	if ( !pParentPatch )
	{
		BaseLightForFace( &g_pFaces[pPatch->faceNumber], pPatch->baselight, &pPatch->basearea, pPatch->reflectivity );
	}
	else
	{
		VectorCopy( pParentPatch->baselight, pPatch->baselight );
		pPatch->basearea = pParentPatch->basearea;
		pPatch->reflectivity = pParentPatch->reflectivity;
	}

	return true;
}
コード例 #2
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : iPatch - 
//			iParentPatch - 
//			iChild - 
//			*pPoints - 
//			*pIndices - 
//			&flArea - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CVRADDispColl::InitParentPatch( int iPatch, Vector *pPoints, float &flArea )
{
	// Get the current patch.
	CPatch *pPatch = &g_Patches[iPatch];
	if ( !pPatch )
		return false;

	// Clear the patch data.
	memset( pPatch, 0, sizeof( CPatch ) );

	// This is a parent.
	pPatch->ndxNext = g_FacePatches.Element( GetParentIndex() );
	g_FacePatches[GetParentIndex()] = iPatch;
	pPatch->faceNumber = GetParentIndex();

	// Initialize parent and children indices.
	pPatch->child1 = g_Patches.InvalidIndex();
	pPatch->child2 = g_Patches.InvalidIndex();
	pPatch->parent = g_Patches.InvalidIndex();
	pPatch->ndxNextClusterChild = g_Patches.InvalidIndex();
	pPatch->ndxNextParent = g_Patches.InvalidIndex();

	Vector vecEdges[2];
	vecEdges[0] = pPoints[1] - pPoints[0];
	vecEdges[1] = pPoints[3] - pPoints[0];

	// Calculate the triangle normal and area.
	Vector vecNormal = vecEdges[1].Cross( vecEdges[0] );
	flArea = VectorNormalize( vecNormal );

	// Initialize the patch scale.
	pPatch->scale[0] = pPatch->scale[1] = 1.0f;

	// Set the patch chop - minchop (that is what the minimum area is based on).
	pPatch->chop = dispchop;

	// Displacements are not sky!
	pPatch->sky = false;

	// Copy the winding.
	Vector vecCenter( 0.0f, 0.0f, 0.0f );
	pPatch->winding = AllocWinding( 4 );
	pPatch->winding->numpoints = 4;
	for ( int iPoint = 0; iPoint < 4; ++iPoint )
	{
		VectorCopy( pPoints[iPoint], pPatch->winding->p[iPoint] );
		VectorAdd( pPoints[iPoint], vecCenter, vecCenter );
	}

	// Set the origin and normal.
	VectorScale( vecCenter, ( 1.0f / 4.0f ), vecCenter );
	VectorCopy( vecCenter, pPatch->origin );
	VectorCopy( vecNormal, pPatch->normal );

	// Create the plane.
	pPatch->plane = new dplane_t;
	if ( !pPatch->plane )
		return false;

	VectorCopy( vecNormal, pPatch->plane->normal );
	pPatch->plane->dist = vecNormal.Dot( pPoints[0] );
	pPatch->plane->type = PlaneTypeForNormal( pPatch->plane->normal );
	pPatch->planeDist = pPatch->plane->dist;

	// Set the area.
	pPatch->area = flArea;

	// Calculate the mins/maxs.
	Vector vecMin( FLT_MAX, FLT_MAX, FLT_MAX );
	Vector vecMax( FLT_MIN, FLT_MIN, FLT_MIN );
	for ( int iPoint = 0; iPoint < 4; ++iPoint )
	{
		for ( int iAxis = 0; iAxis < 3; ++iAxis )
		{
			vecMin[iAxis] = MIN( vecMin[iAxis], pPoints[iPoint][iAxis] );
			vecMax[iAxis] = MAX( vecMax[iAxis], pPoints[iPoint][iAxis] );
		}
	}

	VectorCopy( vecMin, pPatch->mins );
	VectorCopy( vecMax, pPatch->maxs );
	VectorCopy( vecMin, pPatch->face_mins );
	VectorCopy( vecMax, pPatch->face_maxs );

	// Check for bumpmap.
	dface_t *pFace = dfaces + pPatch->faceNumber;
	texinfo_t *pTexInfo = &texinfo[pFace->texinfo];
	pPatch->needsBumpmap = pTexInfo->flags & SURF_BUMPLIGHT ? true : false;

	// Misc...
	pPatch->m_IterationKey = 0;

	// Calculate the base light, area, and reflectivity.
	BaseLightForFace( &g_pFaces[pPatch->faceNumber], pPatch->baselight, &pPatch->basearea, pPatch->reflectivity );

	return true;
}
コード例 #3
0
ファイル: SpeedTreeWrapper.cpp プロジェクト: ak4hige/myway3d
void CSpeedTreeWrapper::RenderLeaves(void) const
{
	#ifdef WRAPPER_USE_GPU_LEAF_PLACEMENT
		m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_LeafGeometry, -1, -1, 0);
	#endif
	m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_LeafGeometry);

	// update the LOD level vertex arrays we need
	#if defined(WRAPPER_USE_GPU_LEAF_PLACEMENT) && defined(WRAPPER_USE_GPU_WIND)
		// do nothing
	#else
		#if !defined WRAPPER_USE_NO_WIND || defined WRAPPER_USE_CPU_LEAF_PLACEMENT
			// might need to draw 2 LOD's
			for (unsigned int i = 0; i < 2; ++i)
			{
				// reference to leaves structure
				const CSpeedTreeRT::SGeometry::SLeaf* pLeaf = (i == 0) ? &m_pGeometryCache->m_sLeaves0 : &m_pGeometryCache->m_sLeaves1;
				int unLod = pLeaf->m_nDiscreteLodLevel;

				#if defined WRAPPER_USE_GPU_LEAF_PLACEMENT
					if (pLeaf->m_bIsActive && !m_pLeavesUpdatedByCpu[unLod])
					{
						// update the centers
						SFVFLeafVertex* pVertex = NULL;
						m_pLeafVertexBuffer[unLod]->Lock(0, 0, reinterpret_cast<void**>(&pVertex), 0);
						for (unsigned int unLeaf = 0; unLeaf < pLeaf->m_usLeafCount; ++unLeaf)
						{
							D3DXVECTOR3 vecCenter(&(pLeaf->m_pCenterCoords[unLeaf * 3]));
							(pVertex++)->m_vPosition = vecCenter;		// vertex 0
							(pVertex++)->m_vPosition = vecCenter;		// vertex 1
							(pVertex++)->m_vPosition = vecCenter;		// vertex 2
							(pVertex++)->m_vPosition = vecCenter;		// vertex 0
							(pVertex++)->m_vPosition = vecCenter;		// vertex 2
							(pVertex++)->m_vPosition = vecCenter;		// vertex 3
						}
						m_pLeafVertexBuffer[unLod]->Unlock( );
						m_pLeavesUpdatedByCpu[unLod] = true;
					}
				#else
					if (pLeaf->m_bIsActive)
					{ 
						// update the vertices
						SFVFLeafVertex* pVertex = NULL;
						m_pLeafVertexBuffer[unLod]->Lock(0, 0, reinterpret_cast<void**>(&pVertex),0);
						for (unsigned int unLeaf = 0; unLeaf < pLeaf->m_usLeafCount; ++unLeaf)
						{
							D3DXVECTOR3 vecCenter(&(pLeaf->m_pCenterCoords[unLeaf * 3]));
							D3DXVECTOR3 vec0(&pLeaf->m_pLeafMapCoords[unLeaf][0]);
							D3DXVECTOR3 vec1(&pLeaf->m_pLeafMapCoords[unLeaf][4]);
							D3DXVECTOR3 vec2(&pLeaf->m_pLeafMapCoords[unLeaf][8]);
							D3DXVECTOR3 vec3(&pLeaf->m_pLeafMapCoords[unLeaf][12]);

							(pVertex++)->m_vPosition = vecCenter + vec0;		// vertex 0
							(pVertex++)->m_vPosition = vecCenter + vec1;		// vertex 1
							(pVertex++)->m_vPosition = vecCenter + vec2;		// vertex 2
							(pVertex++)->m_vPosition = vecCenter + vec0;		// vertex 0
							(pVertex++)->m_vPosition = vecCenter + vec2;		// vertex 2
							(pVertex++)->m_vPosition = vecCenter + vec3;		// vertex 3
						}
						m_pLeafVertexBuffer[unLod]->Unlock( );
					}
				#endif
			}
		#endif
	#endif

	PositionTree( );

	// might need to draw 2 LOD's
	for (unsigned int unLeafLevel = 0; unLeafLevel < 2; ++unLeafLevel)
	{
		const CSpeedTreeRT::SGeometry::SLeaf* pLeaf = (unLeafLevel == 0) ?
			&m_pGeometryCache->m_sLeaves0 : pLeaf = &m_pGeometryCache->m_sLeaves1;

		int unLod = pLeaf->m_nDiscreteLodLevel;

		// if this LOD is active and has leaves, draw it
		if (unLod > -1 && pLeaf->m_bIsActive && pLeaf->m_usLeafCount > 0)
		{
			m_pDx->SetStreamSource(0, m_pLeafVertexBuffer[unLod], 0, sizeof(SFVFLeafVertex));
			m_pDx->SetRenderState(D3DRS_ALPHAREF, DWORD(pLeaf->m_fAlphaTestValue));
			m_pDx->DrawPrimitive(D3DPT_TRIANGLELIST, 0, pLeaf->m_usLeafCount * 2);
		}
	}
}
コード例 #4
0
	void ProgressBar::doRender(const RenderState &rs)
	{
		if (_progress == 0)
			return;
		if (((_direction != __dir_radial_ccw) && (_direction != dir_radial_cw)) || (_progress == 1.0f))
		{
			Sprite::doRender(rs);
			return;
		}

		_vstyle._apply(rs);
		const Diffuse &df = _frame.getDiffuse();
		if (df.base)
		{
			rs.renderer->setDiffuse(df);

			unsigned int rgba = rs.renderer->getPrimaryColor().rgba();

			RectF destRect = Sprite::getDestRect();

			RectF srcRect = _frame.getSrcRect();
			float u = srcRect.pos.x;
			float v = srcRect.pos.y;

			float du = srcRect.size.x;
			float dv = srcRect.size.y;	

			u += du / 2.f;
			v += dv / 2.f;

			Vector2 pos = destRect.pos;
			const Vector2 &size = destRect.size;
			pos += size / 2.f;				

			float maxSide = std::max( size.x, size.y );

			Vector2 vecCenter( pos.x, pos.y );
			Vector2 vdiag = Vector2( pos.x + size.x / 2.f, pos.y - size.y / 2.f ) - vecCenter;
			Vector2 vdiag2 = Vector2( pos.x + size.x / 2.f, pos.y + size.y / 2.f ) - vecCenter;
			float lenDiag = vdiag.length();
			Vector2 vecCircle( pos.x, pos.y - lenDiag );

			Vector2 vecRad = vecCircle - vecCenter;

			float progress = _progress;

			float fP = MATH_PI * 2.f * progress;

			rotateVector( vecRad, fP );

			Vector2 p1(0.f, 0.f);
			Vector2 p2(0.f, 0.f);
			Vector2 p3(0.f, 0.f);

			Vector2 vert( 0.f, -1.f );
			float fA1 = Angle( vdiag, &vert );
			float fA2 = Angle( vdiag2, &vdiag );

			const int MAX_TRI = 6;

			float u1,v1,u2,v2,u3,v3;
			float result = 0.f;

			float angles[ 6 ];
			angles[ 0 ] = fA1;
			angles[ 1 ] = fA2;
			angles[ 2 ] = fA1;
			angles[ 3 ] = fA1;
			angles[ 4 ] = fA2;
			angles[ 5 ] = fA1;

			for ( int i = 0; i < MAX_TRI; i++ )
			{
				float limitLo = 0.f;
				float limitHi = 0.f;
				for (int j = 0; j < i; j++)				
					limitLo += angles[ j ];

				limitHi = limitLo + angles[ i ];

				bool bOverHi = fP > limitHi;
				bool bOverLo = fP < limitLo;
				if ( i && bOverLo )				
					continue;

				vertexPCT2 vertices[4];
				vertexPCT2* pv = vertices;

				switch (i)
				{
				case 0:
					{
						result = bOverHi ? size.x / 2.f : vecRad.x;
						p1 = Vector2(pos.x, pos.y);
						p2 = Vector2(pos.x, pos.y - size.y / 2.f);
						p3 = Vector2(pos.x + result, pos.y - size.y / 2.f);
						float fPercent = result / size.x;
						float fDU = du * fPercent;	

						u1 = u;
						v1 = v;
						u2 = u;
						v2 = ( v - dv / 2.f );
						u3 = ( u + fDU );
						v3 = ( v - dv / 2.f );
					}
					break;
				case 1:
					{					
						result = bOverHi ? size.y / 2.f : ( vecRad.y ) ;
						p1 = Vector2(pos.x, pos.y);
						p2 = Vector2(pos.x + size.x / 2.f, pos.y - size.y / 2.f);
						p3 = Vector2(pos.x + size.x / 2.f, pos.y + result );
						float fPercent = result /size.y;
						float fDV = dv * fPercent;	

						u2 = u + du / 2.f;
						v2 = ( v - dv / 2.f );
						u3 = u + du / 2.f;
						v3 = ( v + fDV );
					}
					break;
				case 2:
					{					
						result = bOverHi ? 0.f : vecRad.x ;
						p1 = Vector2(pos.x, pos.y);
						p2 = Vector2(pos.x + size.x / 2.f, pos.y + size.y / 2.f);
						p3 = Vector2(pos.x + result, pos.y + size.y / 2.f );
						float fPercent = result/size.x;
						float fDU = du * fPercent;	
						
						u2 = u + du / 2.f;
						v2 = ( v + dv / 2.f );
						u3 = u + fDU;
						v3 = ( v + dv / 2.f );
					}
					break;
				case 3:
					{					
						result = bOverHi ? ( -size.x / 2.f ) : vecRad.x ;
						p1 = Vector2(pos.x, pos.y);
						p2 = Vector2(pos.x , pos.y + size.y / 2.f);
						p3 = Vector2(pos.x + result, pos.y + size.y / 2.f );
						float fPercent = result / size.x;
						float fDU = du * fPercent;	

						u2 = u;
						v2 = ( v + dv / 2.f );
						u3 = u + fDU;
						v3 = ( v + dv / 2.f );
					}
					break;
				case 4:
					{					
						result = bOverHi ? ( -size.y / 2.f ) : vecRad.y ;
						p1 = Vector2(pos.x, pos.y);
						p2 = Vector2(pos.x - ( size.x / 2.f ) , pos.y + size.y / 2.f);
						p3 = Vector2(pos.x - ( size.x / 2.f ), pos.y + result );
						float fPercent = result / size.y;
						float fDV = dv * fPercent;	

						u2 = u - du / 2.f;
						v2 = ( v + dv / 2.f );
						u3 = u - du / 2.f;
						v3 = ( v + fDV );
					}
					break;
				case 5:
					{					
						result = bOverHi ? ( 0.f ) : vecRad.x ;
						p1 = Vector2(pos.x, pos.y);
						p2 = Vector2(pos.x - ( size.x / 2.f ), pos.y - ( size.y / 2.f ));
						p3 = Vector2(pos.x + result, pos.y - ( size.y / 2.f ) );
						float fPercent = result / size.x;
						float fDU = du * fPercent;	

						u2 = u - du / 2.f;
						v2 = ( v - dv / 2.f );
						u3 = u + fDU;
						v3 = ( v - dv / 2.f );
					}
					break;
				default:
					continue;
				}

				u1 = u;
				v1 = v;


				p1 = rs.transform.transform(p1);
				p2 = rs.transform.transform(p2);
				p3 = rs.transform.transform(p3);


				fill_tex_coord(*pv, rgba, p1, u1, v1);
				pv++;
				fill_tex_coord(*pv, rgba, p2, u2, v2);
				pv++;
				fill_tex_coord(*pv, rgba, p3, u3, v3);
				pv++;
				fill_tex_coord(*pv, rgba, p2, u2, v2);			
				pv++;

				rs.renderer->draw(vertices, sizeof(vertices), VERTEX_PCT2);			
			}
		}
	}
コード例 #5
0
ファイル: normal.cpp プロジェクト: BSVino/SMAK
void CNormalGenerator::NormalizeHeightValue(size_t x, size_t y)
{
	if (!m_avecTextureTexels.size())
		return;

	float flHiScale = ((m_iNormal2Width+m_iNormal2Height)/2.0f)/200.0f * m_flNormalTextureDepth;
	float flMidScale = ((m_iNormal2Width+m_iNormal2Height)/2.0f)/100.0f * m_flNormalTextureDepth;
	float flLowScale = ((m_iNormal2Width+m_iNormal2Height)/2.0f)/50.0f * m_flNormalTextureDepth;

	size_t iTexel;
	Texel(x, y, iTexel, m_iNormal2Width, m_iNormal2Height, false);

	tvector<Vector> avecHeights;

	float flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
	float flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
	float flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;

	Vector vecCenter((float)x, (float)y, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
	Vector vecNormal(0,0,0);

	if (Texel(x+1, y, iTexel, m_iNormal2Width, m_iNormal2Height, false))
	{
		flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
		flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
		flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;
		Vector vecNeighbor(x+1.0f, (float)y, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
		vecNormal += (vecNeighbor-vecCenter).Normalized().Cross(Vector(0, 1, 0));
	}

	if (Texel(x-1, y, iTexel, m_iNormal2Width, m_iNormal2Height, false))
	{
		flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
		flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
		flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;
		Vector vecNeighbor(x-1.0f, (float)y, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
		vecNormal += (vecNeighbor-vecCenter).Normalized().Cross(Vector(0, -1, 0));
	}

	if (Texel(x, y+1, iTexel, m_iNormal2Width, m_iNormal2Height, false))
	{
		flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
		flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
		flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;
		Vector vecNeighbor((float)x, y+1.0f, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
		vecNormal += (vecNeighbor-vecCenter).Normalized().Cross(Vector(-1, 0, 0));
	}

	if (Texel(x, y-1, iTexel, m_iNormal2Width, m_iNormal2Height, false))
	{
		flHeight = m_avecTextureTexels[iTexel].Average() * flHiScale;
		flMidPass = m_aflMidPassTexels[iTexel] * flMidScale;
		flLowPass = m_aflLowPassTexels[iTexel] * flLowScale;
		Vector vecNeighbor((float)x, y-1.0f, flHeight*m_flNormalTextureHiDepth + flMidPass*m_flNormalTextureMidDepth + flLowPass*m_flNormalTextureLoDepth);
		vecNormal += (vecNeighbor-vecCenter).Normalized().Cross(Vector(1, 0, 0));
	}

	vecNormal.Normalize();

	for (size_t i = 0; i < 3; i++)
		vecNormal[i] = RemapVal(vecNormal[i], -1.0f, 1.0f, 0.0f, 0.99f);	// Don't use 1.0 because of integer overflow.

	// Don't need to lock the data because we're guaranteed never to access the same texel twice due to the generation method.
	m_avecNormal2Texels[iTexel] = vecNormal;
}