// ***************************************************************
bool CDisplayerVisual::getDisplayFlag(TDisplayFlags flag) const
{
	//H_AUTO(R2_CDisplayerVisual_getDisplayFlag)
	nlctassert(FlagCount <= 32);
	nlassert((uint) flag < FlagCount);
	return (_DisplayFlags & (1 << flag)) != 0;
}
// ***************************************************************
void CDisplayerVisual::setDisplayFlag(TDisplayFlags flag, bool on)
{
	//H_AUTO(R2_CDisplayerVisual_setDisplayFlag)
	nlctassert(FlagCount <= 32);
	nlassert((uint) flag < FlagCount);
	setFlags(_DisplayFlags, 1 << flag, on);
}
Exemple #3
0
void CTuneMrmDlg::applySlider(UINT sliderCur, UINT sliderMax)
{
	nlctassert(NL_TMD_SLIDER_SIZE*NL_TMD_SLIDER_MAX_STEP*NL_TMD_SLIDER_STEP_SIZE < ((uint)1<<31));
	// compute actual max polygon
	uint	actualValue= sliderCur*sliderMax*NL_TMD_SLIDER_STEP_SIZE / NL_TMD_SLIDER_SIZE;

	if(_Scene)
	{
		_Scene->setGroupLoadMaxPolygon("Skin", actualValue);
	}

	// refresh text views
	ViewCurrentMaxPoly= NLMISC::toString(actualValue).c_str();
	ViewMaxValue= NLMISC::toString(sliderMax*NL_TMD_SLIDER_STEP_SIZE).c_str();

	UpdateData(FALSE);
}
Exemple #4
0
//*******************************************************************************
void CWaterEnvMap::initFlattenVB()
{
	_FlattenVB.setPreferredMemory(CVertexBuffer::AGPPreferred, true);
	_FlattenVB.setName("Flatten VB");
	_FlattenVB.clearValueEx();
	_FlattenVB.addValueEx (CVertexBuffer::Position, CVertexBuffer::Float3);
	_FlattenVB.addValueEx (CVertexBuffer::TexCoord0, CVertexBuffer::Float3);
	_FlattenVB.initEx();
	nlctassert(FVB_NUM_SIDES % 4 == 0); // number of sides must be a multiple of 4 so that sections sides will align with corners
	_FlattenVB.setNumVertices(FVB_NUM_VERTS);
	_FlattenIB.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
	_FlattenIB.setNumIndexes(3 * FVB_NUM_TRIS);
	{
		CVertexBufferReadWrite vbrw;
		CIndexBufferReadWrite ibrw;
		_FlattenVB.lock(vbrw);
		_FlattenIB.lock(ibrw);
		for(uint l = 0; l < FVB_NUM_SIDES; ++l)
		{
			double angle = NLMISC::Pi * 0.25 + 2 * NLMISC::Pi * (double) l / (double) FVB_NUM_SIDES;
			for(uint k = 0; k < FVB_NUM_SECTIONS + 1; ++k)
			{
				double radius = (double) k / (double) (FVB_NUM_SECTIONS - 1);
				float x = (float) (radius * cos(angle));
				float y = (float) (radius * sin(angle));
				if (k < FVB_NUM_SECTIONS)
				{
					ibrw.setTri(3 * 2 * (k + (l * FVB_NUM_SECTIONS)), getFVBVertex(k, l), getFVBVertex(k + 1, l + 1), getFVBVertex(k + 1, l));
					ibrw.setTri(3 * (2 * (k + (l * FVB_NUM_SECTIONS)) + 1), getFVBVertex(k, l), getFVBVertex(k, l + 1), getFVBVertex(k + 1, l + 1));
				}
				else
				{
					uint side = l / (FVB_NUM_SIDES / 4);
					switch(side)
					{
						case 0: // top
							x /= y;
							y = 1.f;
						break;
						case 1: // left
							y /= -x;
							x = -1.f;
						break;
						case 2: // bottom
							x /= -y;
							y = -1.f;
						break;
						case 3: // right
							y /= x;
							x = 1.f;
						break;
						default:
							nlassert(0);
						break;
					}
				}
				CVector dir;
				//dir.sphericToCartesian(1.f, (float) angle, (float) (NLMISC::Pi * 0.5 * acos(std::max(0.f, (1.f - (float) k / (FVB_NUM_SECTIONS - 1))))));
				dir.sphericToCartesian(1.f, (float) angle, (float) acos(std::min(1.f, (float) k / (FVB_NUM_SECTIONS - 1))));
				vbrw.setValueFloat3Ex(CVertexBuffer::Position, getFVBVertex(k, l), x, 0.5f, y);
				vbrw.setValueFloat3Ex(CVertexBuffer::TexCoord0, getFVBVertex(k, l), -dir.x, dir.z, -dir.y);
			}
		}
	}
}
// ***************************************************************************
void		CMeshMRMGeom::applyArrayRawSkinNormal1(CRawVertexNormalSkin1 *src, uint8 *destVertexPtr,
	CMatrix3x4 *boneMat3x4, uint nInf)
{
	// must write contigously in AGP, and ASM is hardcoded...
	nlctassert(NL3D_RAWSKIN_NORMAL_OFF==12);
	nlctassert(NL3D_RAWSKIN_UV_OFF==24);

	/*extern	uint TESTYOYO_NumRawSkinVertices1;
	TESTYOYO_NumRawSkinVertices1+= nInf;
	H_AUTO( TestYoyo_RawSkin1 );*/

#ifdef	NL3D_RAWSKIN_PRECACHE
	for(;nInf>0;)
	{
		// number of vertices to process for this block.
		uint	nBlockInf= min(NumCacheVertexNormal1, nInf);
		// next block.
		nInf-= nBlockInf;

		// cache the data in L1 cache.
		CFastMem::precache(src, nBlockInf * sizeof(CRawVertexNormalSkin1));
#else
	{
		uint	nBlockInf= nInf;
#endif


#ifndef NL3D_RAWSKIN_ASM
		//  for all InfluencedVertices only.
		for(;nBlockInf>0;nBlockInf--, src++, destVertexPtr+=NL3D_RAWSKIN_VERTEX_SIZE)
		{
			CVector				*dstVertex= (CVector*)(destVertexPtr);
			CVector				*dstNormal= (CVector*)(destVertexPtr + NL3D_RAWSKIN_NORMAL_OFF);

			// For 1 matrix, can write directly to AGP (if destVertexPtr is AGP...)
			// Vertex.
			boneMat3x4[ src->MatrixId[0] ].mulSetPoint( src->Vertex.Pos, *(CVector*)(destVertexPtr) );
			// Normal.
			boneMat3x4[ src->MatrixId[0] ].mulSetVector( src->Vertex.Normal, *(CVector*)(destVertexPtr + NL3D_RAWSKIN_NORMAL_OFF) );
			// UV copy.
			*(CUV*)(destVertexPtr + NL3D_RAWSKIN_UV_OFF)= src->Vertex.UV;
		}
#else
		// ASM harcoded for 36
		nlctassert(sizeof(CRawVertexNormalSkin1)==36);

		/*  116 cycles / loop typical
			58 cycles / loop in theory (no memory problem)
		*/
		__asm
		{
			mov		ecx, nBlockInf
			mov		esi, src
			mov		edi, destVertexPtr
			mov		edx, boneMat3x4
		theLoop:
			// Vertex.
			// **** boneMat3x4[ src->MatrixId[0] ].mulSetPoint( src->Vertex.Pos, *(CVector*)(destVertexPtr) );

			// eax= matrix
			mov		eax, [esi]src.MatrixId				// uop: 0/1
			lea		eax, [eax*2+eax]
			shl		eax, 4
			add		eax, edx							// uop: 1/0

			// load x y z
			fld		[esi]src.Vertex.Pos.x					// uop: 0/1
			fld		[esi]src.Vertex.Pos.y					// uop: 0/1
			fld		[esi]src.Vertex.Pos.z					// uop: 0/1
			// vout.x= (a11*vin.x + a12*vin.y + a13*vin.z + a14);
			fld		[eax]CMatrix3x4.a11				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			fld		[eax]CMatrix3x4.a12				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a13				// uop: 0/1
			fmul	st, st(2)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a14				// uop: 0/1
			faddp	st(1), st							// uop: 1/0 (3)
			fstp	dword ptr[edi]						// uop: 0/0/1/1
			// vout.y= (a21*vin.x + a22*vin.y + a23*vin.z + a24);
			fld		[eax]CMatrix3x4.a21
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a22
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a23
			fmul	st, st(2)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a24
			faddp	st(1), st
			fstp	dword ptr[edi+4]
			// vout.z= (a31*vin.x + a32*vin.y + a33*vin.z + a34);
			fld		[eax]CMatrix3x4.a31
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a32
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a33
			fmul	st, st(2)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a34
			faddp	st(1), st
			fstp	dword ptr[edi+8]
			// free x y z
			fstp	st									// uop: 1/0
			fstp	st									// uop: 1/0
			fstp	st									// uop: 1/0


			// Normal
			// **** boneMat3x4[ src->MatrixId[0] ].mulSetVector( src->Vertex.Normal, *(CVector*)(destVertexPtr + NL3D_RAWSKIN_NORMAL_OFF) );

			// load x y z
			fld		[esi]src.Vertex.Normal.x
			fld		[esi]src.Vertex.Normal.y
			fld		[esi]src.Vertex.Normal.z
			// vout.x= (a11*vin.x + a12*vin.y + a13*vin.z + a14);
			fld		[eax]CMatrix3x4.a11				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			fld		[eax]CMatrix3x4.a12				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a13				// uop: 0/1
			fmul	st, st(2)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fstp	dword ptr[edi+12]					// uop: 0/0/1/1
			// vout.y= (a21*vin.x + a22*vin.y + a23*vin.z + a24);
			fld		[eax]CMatrix3x4.a21
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a22
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a23
			fmul	st, st(2)
			faddp	st(1), st
			fstp	dword ptr[edi+16]
			// vout.z= (a31*vin.x + a32*vin.y + a33*vin.z + a34);
			fld		[eax]CMatrix3x4.a31
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a32
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a33
			fmul	st, st(2)
			faddp	st(1), st
			fstp	dword ptr[edi+20]
			// free x y z
			fstp	st
			fstp	st
			fstp	st


			// UV copy.
			// **** *(CUV*)(destVertexPtr + NL3D_RAWSKIN_UV_OFF)= src->Vertex.UV;
			mov		eax, [esi]src.Vertex.UV.U					// uop: 0/1
			mov		dword ptr[edi+24], eax				// uop: 0/0/1/1
			mov		eax, [esi]src.Vertex.UV.V					// uop: 0/1
			mov		dword ptr[edi+28], eax				// uop: 0/0/1/1


			// **** next
			add		esi, 36								// uop: 1/0
			add		edi, NL3D_RAWSKIN_VERTEX_SIZE		// uop: 1/0
			dec		ecx									// uop: 1/0
			jnz		theLoop								// uop: 1/1 (p1)

			mov		nBlockInf, ecx
			mov		src, esi
			mov		destVertexPtr, edi
		}
#endif
	}


}

// ***************************************************************************
void		CMeshMRMGeom::applyArrayRawSkinNormal2(CRawVertexNormalSkin2 *src, uint8 *destVertexPtr,
	CMatrix3x4 *boneMat3x4, uint nInf)
{
	// must write contigously in AGP, and ASM is hardcoded...
	nlctassert(NL3D_RAWSKIN_NORMAL_OFF==12);
	nlctassert(NL3D_RAWSKIN_UV_OFF==24);

	/*extern	uint TESTYOYO_NumRawSkinVertices2;
	TESTYOYO_NumRawSkinVertices2+= nInf;
	H_AUTO( TestYoyo_RawSkin2 );*/

	// Since VertexPtr may be a AGP Ram, MUST NOT read into it! (mulAdd*() do it!)
	CVector	tmpVert;

#ifdef	NL3D_RAWSKIN_PRECACHE
	for(;nInf>0;)
	{
		// number of vertices to process for this block.
		uint	nBlockInf= min(NumCacheVertexNormal2, nInf);
		// next block.
		nInf-= nBlockInf;

		// cache the data in L1 cache.
		CFastMem::precache(src, nBlockInf * sizeof(CRawVertexNormalSkin2));
#else
	{
		uint	nBlockInf= nInf;
#endif


#ifndef NL3D_RAWSKIN_ASM
		//  for all InfluencedVertices only.
		for(;nBlockInf>0;nBlockInf--, src++, destVertexPtr+=NL3D_RAWSKIN_VERTEX_SIZE)
		{
			// Vertex.
			boneMat3x4[ src->MatrixId[0] ].mulSetPoint( src->Vertex.Pos, src->Weights[0], tmpVert);
			boneMat3x4[ src->MatrixId[1] ].mulAddPoint( src->Vertex.Pos, src->Weights[1], tmpVert);
			*(CVector*)(destVertexPtr)= tmpVert;
			// Normal.
			boneMat3x4[ src->MatrixId[0] ].mulSetVector( src->Vertex.Normal, src->Weights[0], tmpVert);
			boneMat3x4[ src->MatrixId[1] ].mulAddVector( src->Vertex.Normal, src->Weights[1], tmpVert);
			*(CVector*)(destVertexPtr + NL3D_RAWSKIN_NORMAL_OFF)= tmpVert;
			// UV copy.
			*(CUV*)(destVertexPtr + NL3D_RAWSKIN_UV_OFF)= src->Vertex.UV;
		}
#else
		// ASM harcoded for 48
		nlctassert(sizeof(CRawVertexNormalSkin2)==48);

		/*  154 cycles / loop typical
			124 cycles / loop in theory (no memory problem)
		*/
		__asm
		{
			mov		ecx, nBlockInf
			mov		esi, src
			mov		edi, destVertexPtr
			mov		edx, boneMat3x4
		theLoop:
			// Vertex.
			// **** boneMat3x4[ src->MatrixId[0] ].mulSetPoint( src->Vertex.Pos, *(CVector*)(destVertexPtr) );

			// eax= matrix0
			mov		eax, [esi+0]src.MatrixId			// uop: 0/1
			lea		eax, [eax*2+eax]
			shl		eax, 4
			add		eax, edx							// uop: 1/0
			// ebx= matrix1
			mov		ebx, [esi+4]src.MatrixId			// uop: 0/1
			lea		ebx, [ebx*2+ebx]
			shl		ebx, 4
			add		ebx, edx							// uop: 1/0

			// load x y z
			fld		[esi]src.Vertex.Pos.x					// uop: 0/1
			fld		[esi]src.Vertex.Pos.y					// uop: 0/1
			fld		[esi]src.Vertex.Pos.z					// uop: 0/1

			// **** vout.x= (a11*vin.x + a12*vin.y + a13*vin.z + a14);
			// 1st Matrix
			fld		[eax]CMatrix3x4.a11				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			fld		[eax]CMatrix3x4.a12				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a13				// uop: 0/1
			fmul	st, st(2)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a14				// uop: 0/1
			faddp	st(1), st							// uop: 1/0 (3)
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a11
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a12
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a13
			fmul	st, st(3)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a14
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi]						// uop: 0/0/1/1

			// **** vout.y= (a21*vin.x + a22*vin.y + a23*vin.z + a24);
			fld		[eax]CMatrix3x4.a21
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a22
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a23
			fmul	st, st(2)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a24
			faddp	st(1), st
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a21
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a22
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a23
			fmul	st, st(3)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a24
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+4]

			// **** vout.z= (a31*vin.x + a32*vin.y + a33*vin.z + a34);
			fld		[eax]CMatrix3x4.a31
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a32
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a33
			fmul	st, st(2)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a34
			faddp	st(1), st
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a31
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a32
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a33
			fmul	st, st(3)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a34
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+8]

			// free x y z
			fstp	st									// uop: 1/0
			fstp	st									// uop: 1/0
			fstp	st									// uop: 1/0


			// Normal
			// **** boneMat3x4[ src->MatrixId[0] ].mulSetVector( src->Vertex.Normal, *(CVector*)(destVertexPtr + NL3D_RAWSKIN_NORMAL_OFF) );

			// load x y z
			fld		[esi]src.Vertex.Normal.x
			fld		[esi]src.Vertex.Normal.y
			fld		[esi]src.Vertex.Normal.z

			// **** vout.x= (a11*vin.x + a12*vin.y + a13*vin.z + a14);
			fld		[eax]CMatrix3x4.a11				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			fld		[eax]CMatrix3x4.a12				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a13				// uop: 0/1
			fmul	st, st(2)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a11
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a12
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a13
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+12]					// uop: 0/0/1/1

			// **** vout.y= (a21*vin.x + a22*vin.y + a23*vin.z + a24);
			fld		[eax]CMatrix3x4.a21
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a22
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a23
			fmul	st, st(2)
			faddp	st(1), st
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a21
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a22
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a23
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+16]

			// **** vout.z= (a31*vin.x + a32*vin.y + a33*vin.z + a34);
			fld		[eax]CMatrix3x4.a31
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a32
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a33
			fmul	st, st(2)
			faddp	st(1), st
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a31
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a32
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a33
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+20]

			// free x y z
			fstp	st
			fstp	st
			fstp	st


			// UV copy.
			// **** *(CUV*)(destVertexPtr + NL3D_RAWSKIN_UV_OFF)= src->Vertex.UV;
			mov		eax, [esi]src.Vertex.UV.U					// uop: 0/1
			mov		dword ptr[edi+24], eax				// uop: 0/0/1/1
			mov		eax, [esi]src.Vertex.UV.V					// uop: 0/1
			mov		dword ptr[edi+28], eax				// uop: 0/0/1/1


			// **** next
			add		esi, 48								// uop: 1/0
			add		edi, NL3D_RAWSKIN_VERTEX_SIZE		// uop: 1/0
			dec		ecx									// uop: 1/0
			jnz		theLoop								// uop: 1/1 (p1)

			mov		nBlockInf, ecx
			mov		src, esi
			mov		destVertexPtr, edi
		}
#endif
	}

}

// ***************************************************************************
void		CMeshMRMGeom::applyArrayRawSkinNormal3(CRawVertexNormalSkin3 *src, uint8 *destVertexPtr,
	CMatrix3x4 *boneMat3x4, uint nInf)
{
	// must write contigously in AGP, and ASM is hardcoded...
	nlctassert(NL3D_RAWSKIN_NORMAL_OFF==12);
	nlctassert(NL3D_RAWSKIN_UV_OFF==24);

	/*extern	uint TESTYOYO_NumRawSkinVertices3;
	TESTYOYO_NumRawSkinVertices3+= nInf;
	H_AUTO( TestYoyo_RawSkin3 );*/

	// Since VertexPtr may be a AGP Ram, MUST NOT read into it! (mulAdd*() do it!)
	CVector	tmpVert;

#ifdef	NL3D_RAWSKIN_PRECACHE
	for(;nInf>0;)
	{
		// number of vertices to process for this block.
		uint	nBlockInf= min(NumCacheVertexNormal3, nInf);
		// next block.
		nInf-= nBlockInf;

		// cache the data in L1 cache.
		CFastMem::precache(src, nBlockInf * sizeof(CRawVertexNormalSkin3));
#else
	{
		uint	nBlockInf= nInf;
#endif


#ifndef NL3D_RAWSKIN_ASM
		//  for all InfluencedVertices only.
		for(;nBlockInf>0;nBlockInf--, src++, destVertexPtr+=NL3D_RAWSKIN_VERTEX_SIZE)
		{
			// Vertex.
			boneMat3x4[ src->MatrixId[0] ].mulSetPoint( src->Vertex.Pos, src->Weights[0], tmpVert);
			boneMat3x4[ src->MatrixId[1] ].mulAddPoint( src->Vertex.Pos, src->Weights[1], tmpVert);
			boneMat3x4[ src->MatrixId[2] ].mulAddPoint( src->Vertex.Pos, src->Weights[2], tmpVert);
			*(CVector*)(destVertexPtr)= tmpVert;
			// Normal.
			boneMat3x4[ src->MatrixId[0] ].mulSetVector( src->Vertex.Normal, src->Weights[0], tmpVert);
			boneMat3x4[ src->MatrixId[1] ].mulAddVector( src->Vertex.Normal, src->Weights[1], tmpVert);
			boneMat3x4[ src->MatrixId[2] ].mulAddVector( src->Vertex.Normal, src->Weights[2], tmpVert);
			*(CVector*)(destVertexPtr + NL3D_RAWSKIN_NORMAL_OFF)= tmpVert;
			// UV copy.
			*(CUV*)(destVertexPtr + NL3D_RAWSKIN_UV_OFF)= src->Vertex.UV;
		}
#else
		// ASM harcoded for 56
		nlctassert(sizeof(CRawVertexNormalSkin3)==56);


		/*  226 cycles / loop typical
			192 cycles / loop in theory (no memory problem)
			148 optimal
		*/
		__asm
		{
			mov		ecx, nBlockInf
			mov		esi, src
			mov		edi, destVertexPtr
		theLoop:
			// Vertex.
			// **** boneMat3x4[ src->MatrixId[0] ].mulSetPoint( src->Vertex.Pos, *(CVector*)(destVertexPtr) );

			// eax= matrix0
			mov		eax, [esi+0]src.MatrixId			// uop: 0/1
			lea		eax, [eax*2+eax]
			shl		eax, 4
			add		eax, boneMat3x4						// uop: 1/0
			// ebx= matrix1
			mov		ebx, [esi+4]src.MatrixId			// uop: 0/1
			lea		ebx, [ebx*2+ebx]
			shl		ebx, 4
			add		ebx, boneMat3x4						// uop: 1/0
			// edx= matrix2
			mov		edx, [esi+8]src.MatrixId			// uop: 0/1
			lea		edx, [edx*2+edx]
			shl		edx, 4
			add		edx, boneMat3x4						// uop: 1/0

			// load x y z
			fld		[esi]src.Vertex.Pos.x					// uop: 0/1
			fld		[esi]src.Vertex.Pos.y					// uop: 0/1
			fld		[esi]src.Vertex.Pos.z					// uop: 0/1

			// **** vout.x= (a11*vin.x + a12*vin.y + a13*vin.z + a14);
			// 1st Matrix
			fld		[eax]CMatrix3x4.a11				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			fld		[eax]CMatrix3x4.a12				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a13				// uop: 0/1
			fmul	st, st(2)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a14				// uop: 0/1
			faddp	st(1), st							// uop: 1/0 (3)
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a11
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a12
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a13
			fmul	st, st(3)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a14
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// 3rd matrix
			fld		[edx]CMatrix3x4.a11
			fmul	st, st(4)
			fld		[edx]CMatrix3x4.a12
			fmul	st, st(4)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a13
			fmul	st, st(3)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a14
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+8]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi]						// uop: 0/0/1/1

			// **** vout.y= (a21*vin.x + a22*vin.y + a23*vin.z + a24);
			fld		[eax]CMatrix3x4.a21
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a22
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a23
			fmul	st, st(2)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a24
			faddp	st(1), st
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a21
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a22
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a23
			fmul	st, st(3)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a24
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// 3rd matrix
			fld		[edx]CMatrix3x4.a21
			fmul	st, st(4)
			fld		[edx]CMatrix3x4.a22
			fmul	st, st(4)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a23
			fmul	st, st(3)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a24
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+8]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+4]

			// **** vout.z= (a31*vin.x + a32*vin.y + a33*vin.z + a34);
			fld		[eax]CMatrix3x4.a31
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a32
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a33
			fmul	st, st(2)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a34
			faddp	st(1), st
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a31
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a32
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a33
			fmul	st, st(3)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a34
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// 3rd matrix
			fld		[edx]CMatrix3x4.a31
			fmul	st, st(4)
			fld		[edx]CMatrix3x4.a32
			fmul	st, st(4)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a33
			fmul	st, st(3)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a34
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+8]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+8]

			// free x y z
			fstp	st									// uop: 1/0
			fstp	st									// uop: 1/0
			fstp	st									// uop: 1/0


			// Normal
			// **** boneMat3x4[ src->MatrixId[0] ].mulSetVector( src->Vertex.Normal, *(CVector*)(destVertexPtr + NL3D_RAWSKIN_NORMAL_OFF) );

			// load x y z
			fld		[esi]src.Vertex.Normal.x
			fld		[esi]src.Vertex.Normal.y
			fld		[esi]src.Vertex.Normal.z
			// **** vout.x= (a11*vin.x + a12*vin.y + a13*vin.z + a14);
			fld		[eax]CMatrix3x4.a11				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			fld		[eax]CMatrix3x4.a12				// uop: 0/1
			fmul	st, st(3)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			fld		[eax]CMatrix3x4.a13				// uop: 0/1
			fmul	st, st(2)							// uop: 1/0 (5)
			faddp	st(1), st							// uop: 1/0 (3)
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a11
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a12
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a13
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// 3rd matrix
			fld		[edx]CMatrix3x4.a11
			fmul	st, st(4)
			fld		[edx]CMatrix3x4.a12
			fmul	st, st(4)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a13
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+8]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+12]					// uop: 0/0/1/1

			// **** vout.y= (a21*vin.x + a22*vin.y + a23*vin.z + a24);
			fld		[eax]CMatrix3x4.a21
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a22
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a23
			fmul	st, st(2)
			faddp	st(1), st
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a21
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a22
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a23
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// 3rd matrix
			fld		[edx]CMatrix3x4.a21
			fmul	st, st(4)
			fld		[edx]CMatrix3x4.a22
			fmul	st, st(4)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a23
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+8]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+16]

			// **** vout.z= (a31*vin.x + a32*vin.y + a33*vin.z + a34);
			fld		[eax]CMatrix3x4.a31
			fmul	st, st(3)
			fld		[eax]CMatrix3x4.a32
			fmul	st, st(3)
			faddp	st(1), st
			fld		[eax]CMatrix3x4.a33
			fmul	st, st(2)
			faddp	st(1), st
			// mul by scale
			fmul	[esi+0]src.Weights

			// 2nd matrix
			fld		[ebx]CMatrix3x4.a31
			fmul	st, st(4)
			fld		[ebx]CMatrix3x4.a32
			fmul	st, st(4)
			faddp	st(1), st
			fld		[ebx]CMatrix3x4.a33
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+4]src.Weights
			faddp	st(1), st

			// 3rd matrix
			fld		[edx]CMatrix3x4.a31
			fmul	st, st(4)
			fld		[edx]CMatrix3x4.a32
			fmul	st, st(4)
			faddp	st(1), st
			fld		[edx]CMatrix3x4.a33
			fmul	st, st(3)
			faddp	st(1), st
			// mul by scale, and append
			fmul	[esi+8]src.Weights
			faddp	st(1), st

			// store
			fstp	dword ptr[edi+20]

			// free x y z
			fstp	st
			fstp	st
			fstp	st


			// UV copy.
			// **** *(CUV*)(destVertexPtr + NL3D_RAWSKIN_UV_OFF)= src->Vertex.UV;
			mov		eax, [esi]src.Vertex.UV.U					// uop: 0/1
			mov		dword ptr[edi+24], eax				// uop: 0/0/1/1
			mov		eax, [esi]src.Vertex.UV.V					// uop: 0/1
			mov		dword ptr[edi+28], eax				// uop: 0/0/1/1


			// **** next
			add		esi, 56								// uop: 1/0
			add		edi, NL3D_RAWSKIN_VERTEX_SIZE		// uop: 1/0
			dec		ecx									// uop: 1/0
			jnz		theLoop								// uop: 1/1 (p1)

			mov		nBlockInf, ecx
			mov		src, esi
			mov		destVertexPtr, edi
		}
#endif

	}
}

// ***************************************************************************
void		CMeshMRMGeom::applyArrayRawSkinNormal4(CRawVertexNormalSkin4 *src, uint8 *destVertexPtr,
	CMatrix3x4 *boneMat3x4, uint nInf)
{
	// must write contigously in AGP, and ASM is hardcoded...
	nlctassert(NL3D_RAWSKIN_NORMAL_OFF==12);
	nlctassert(NL3D_RAWSKIN_UV_OFF==24);

	/*extern	uint TESTYOYO_NumRawSkinVertices4;
	TESTYOYO_NumRawSkinVertices4+= nInf;
	H_AUTO( TestYoyo_RawSkin4 );*/

	// Since VertexPtr may be a AGP Ram, MUST NOT read into it! (mulAdd*() do it!)
	CVector	tmpVert;

#ifdef	NL3D_RAWSKIN_PRECACHE
	for(;nInf>0;)
	{
		// number of vertices to process for this block.
		uint	nBlockInf= min(NumCacheVertexNormal4, nInf);
		// next block.
		nInf-= nBlockInf;

		// cache the data in L1 cache.
		CFastMem::precache(src, nBlockInf * sizeof(CRawVertexNormalSkin4));
#else
	{
		uint	nBlockInf= nInf;
#endif

		//  for all InfluencedVertices only.
		for(;nBlockInf>0;nBlockInf--, src++, destVertexPtr+=NL3D_RAWSKIN_VERTEX_SIZE)
		{
			// Vertex.
			boneMat3x4[ src->MatrixId[0] ].mulSetPoint( src->Vertex.Pos, src->Weights[0], tmpVert);
			boneMat3x4[ src->MatrixId[1] ].mulAddPoint( src->Vertex.Pos, src->Weights[1], tmpVert);
			boneMat3x4[ src->MatrixId[2] ].mulAddPoint( src->Vertex.Pos, src->Weights[2], tmpVert);
			boneMat3x4[ src->MatrixId[3] ].mulAddPoint( src->Vertex.Pos, src->Weights[3], tmpVert);
			*(CVector*)(destVertexPtr)= tmpVert;
			// Normal.
			boneMat3x4[ src->MatrixId[0] ].mulSetVector( src->Vertex.Normal, src->Weights[0], tmpVert);
			boneMat3x4[ src->MatrixId[1] ].mulAddVector( src->Vertex.Normal, src->Weights[1], tmpVert);
			boneMat3x4[ src->MatrixId[2] ].mulAddVector( src->Vertex.Normal, src->Weights[2], tmpVert);
			boneMat3x4[ src->MatrixId[3] ].mulAddVector( src->Vertex.Normal, src->Weights[3], tmpVert);
			*(CVector*)(destVertexPtr + NL3D_RAWSKIN_NORMAL_OFF)= tmpVert;
			// UV copy.
			*(CUV*)(destVertexPtr + NL3D_RAWSKIN_UV_OFF)= src->Vertex.UV;
		}

		// NB: ASM not done for 4 vertices, cause very rare and negligeable ...
	}
}


// ***************************************************************************
void	CMeshMRMGeom::applyRawSkinWithNormal(CLod &lod, CRawSkinNormalCache &rawSkinLod, const CSkeletonModel *skeleton, uint8 *vbHard, float alphaLod)
{
	nlassert(_Skinned);
	if(_SkinWeights.size()==0)
		return;

	// Some assert
	//===========================
	// must have XYZ, Normal and UV only
	nlassert( _VBufferFinal.getVertexFormat() == (CVertexBuffer::PositionFlag | CVertexBuffer::NormalFlag | CVertexBuffer::TexCoord0Flag) );
	nlassert( _VBufferFinal.getValueType(CVertexBuffer::TexCoord0) == CVertexBuffer::Float2 );
	nlassert( _VBufferFinal.getVertexSize() ==NL3D_RAWSKIN_VERTEX_SIZE);

	// HardCoded for normalOff==12 (see applyArrayRawSkinNormal*)
	nlassert( _VBufferFinal.getNormalOff()==NL3D_RAWSKIN_NORMAL_OFF );
	nlassert( _VBufferFinal.getTexCoordOff()==NL3D_RAWSKIN_UV_OFF );
	// assert, code below is written especially for 4 per vertex.
	nlassert( NL3D_MESH_SKINNING_MAX_MATRIX==4 );


	// Compute useful Matrix for this lod.
	//===========================
	// Those arrays map the array of bones in skeleton.
	static	vector<CMatrix3x4>			boneMat3x4;
	computeBoneMatrixes3x4(boneMat3x4, lod.MatrixInfluences, skeleton);


	// TestYoyo
	/*extern	uint TESTYOYO_NumRawSkinVertices;
	TESTYOYO_NumRawSkinVertices+= rawSkinLod.Vertices1.size();
	TESTYOYO_NumRawSkinVertices+= rawSkinLod.Vertices2.size();
	TESTYOYO_NumRawSkinVertices+= rawSkinLod.Vertices3.size();
	TESTYOYO_NumRawSkinVertices+= rawSkinLod.Vertices4.size();*/


	uint	nInf;

	// Manage "SoftVertices"
	if(rawSkinLod.TotalSoftVertices)
	{
		// apply skinning into Temp RAM for vertices that are Src of Geomorph
		//===========================
		static	vector<uint8>	tempSkin;
		uint	tempVbSize= rawSkinLod.TotalSoftVertices*NL3D_RAWSKIN_VERTEX_SIZE;
		if(tempSkin.size() < tempVbSize)
			tempSkin.resize(tempVbSize);
		uint8		*destVertexPtr= &tempSkin[0];

		// 1 Matrix
		nInf= rawSkinLod.SoftVertices[0];
		if(nInf>0)
		{
			applyArrayRawSkinNormal1(&rawSkinLod.Vertices1[0], destVertexPtr, &boneMat3x4[0], nInf);
			destVertexPtr+= nInf * NL3D_RAWSKIN_VERTEX_SIZE;
		}
		// 2 Matrix
		nInf= rawSkinLod.SoftVertices[1];
		if(nInf>0)
		{
			applyArrayRawSkinNormal2(&rawSkinLod.Vertices2[0], destVertexPtr, &boneMat3x4[0], nInf);
			destVertexPtr+= nInf * NL3D_RAWSKIN_VERTEX_SIZE;
		}
		// 3 Matrix
		nInf= rawSkinLod.SoftVertices[2];
		if(nInf>0)
		{
			applyArrayRawSkinNormal3(&rawSkinLod.Vertices3[0], destVertexPtr, &boneMat3x4[0], nInf);
			destVertexPtr+= nInf * NL3D_RAWSKIN_VERTEX_SIZE;
		}
		// 4 Matrix
		nInf= rawSkinLod.SoftVertices[3];
		if(nInf>0)
		{
			applyArrayRawSkinNormal4(&rawSkinLod.Vertices4[0], destVertexPtr, &boneMat3x4[0], nInf);
			destVertexPtr+= nInf * NL3D_RAWSKIN_VERTEX_SIZE;
		}

		// Fast Copy this into AGP Ram. NB: done before Geomorphs, because ensure some precaching this way!!
		//===========================
		// Skin geomorphs.
		uint8	*vbHardStart= vbHard + rawSkinLod.Geomorphs.size()*NL3D_RAWSKIN_VERTEX_SIZE;

		// fast copy
		CFastMem::memcpy(vbHardStart, &tempSkin[0], tempVbSize);

		// Geomorphs directly into AGP Ram
		//===========================
		clamp(alphaLod, 0.f, 1.f);
		float		a= alphaLod;
		float		a1= 1 - alphaLod;

		// Fast Geomorph
		applyGeomorphPosNormalUV0(rawSkinLod.Geomorphs, &tempSkin[0], vbHard, NL3D_RAWSKIN_VERTEX_SIZE, a, a1);
	}

	// Manage HardVertices
	if(rawSkinLod.TotalHardVertices)
	{
		// apply skinning directly into AGP RAM for vertices that are not Src of Geomorph
		//===========================
		uint	startId;

		// Skip Geomorphs and SoftVertices.
		uint8		*destVertexPtr= vbHard + (rawSkinLod.Geomorphs.size()+rawSkinLod.TotalSoftVertices)*NL3D_RAWSKIN_VERTEX_SIZE;

		// 1 Matrix
		nInf= rawSkinLod.HardVertices[0];
		startId= rawSkinLod.SoftVertices[0];
		if(nInf>0)
		{
			applyArrayRawSkinNormal1(&rawSkinLod.Vertices1[startId], destVertexPtr, &boneMat3x4[0], nInf);
			destVertexPtr+= nInf * NL3D_RAWSKIN_VERTEX_SIZE;
		}
		// 2 Matrix
		nInf= rawSkinLod.HardVertices[1];
		startId= rawSkinLod.SoftVertices[1];
		if(nInf>0)
		{
			applyArrayRawSkinNormal2(&rawSkinLod.Vertices2[startId], destVertexPtr, &boneMat3x4[0], nInf);
			destVertexPtr+= nInf * NL3D_RAWSKIN_VERTEX_SIZE;
		}
		// 3 Matrix
		nInf= rawSkinLod.HardVertices[2];
		startId= rawSkinLod.SoftVertices[2];
		if(nInf>0)
		{
			applyArrayRawSkinNormal3(&rawSkinLod.Vertices3[startId], destVertexPtr, &boneMat3x4[0], nInf);
			destVertexPtr+= nInf * NL3D_RAWSKIN_VERTEX_SIZE;
		}
		// 4 Matrix
		nInf= rawSkinLod.HardVertices[3];
		startId= rawSkinLod.SoftVertices[3];
		if(nInf>0)
		{
			applyArrayRawSkinNormal4(&rawSkinLod.Vertices4[startId], destVertexPtr, &boneMat3x4[0], nInf);
			destVertexPtr+= nInf * NL3D_RAWSKIN_VERTEX_SIZE;
		}
	}
}
Exemple #6
0
// Remplit les différents informations concernant le craft par un item
void FillCraftData( char craft, int eco, int level, bool creature, int bestStat, 
				    int worstStat1, int worstStat2, CSString& outStr )
{
	CSString data;
	char buf[10];
	int index;
	static CSString carac[] = { "Durability", "Weight", "SapLoad", "DMG", "Speed",
			                    "Range", "DodgeModifier", "ParryModifier", 
					            "AdversaryDodgeModifier", "AdversaryParryModifier",
						        "ProtectionFactor", "MaxSlashingProtection",
						        "MaxBluntProtection", "MaxPiercingProtection",
						        "ElementalCastingTimeFactor", "ElementalPowerFactor",
						        "OffensiveAfflictionCastingTimeFactor", 
						        "OffensiveAfflictionPowerFactor", "HealCastingTimeFactor",
						        "HealPowerFactor", "DefensiveAfflictionCastingTimeFactor",
						        "DefensiveAfflictionPowerFactor",
								"AcidProtection",
								"ColdProtection",
								"FireProtection",
								"RotProtection",
								"ShockWaveProtection",
								"PoisonProtection",
								"ElectricityProtection",
								"DesertResistance",
								"ForestResistance",
								"LacustreResistance",
								"JungleResistance",
								"PrimaryRootResistance",
							};
	nlctassert((sizeof(carac)/sizeof(carac[0]))==NumMPStats);

	static int mediumStatsByStatQuality[] = { 20, 35, 50, 65, 80 };
	int stat, remaining, nbToRaise, ajout;
	int stats[NumMPStats];

	index = craft - 'A';

	outStr = "        <STRUCT Name=\"";
	outStr += craftParts[index].Desc;
	outStr += "\">\n";

	nbToRaise = 0;
	remaining = 0;
	ajout = 0;

	currentDocItem.push( DtCraftSlotName, craftParts[index].Desc.splitFrom( "(" ).splitTo( ")" ) );

	// enregistrements des stats de chaque
	// caractèristique
	for ( int i=0; i<NumMPStats; i++ )
	{
		if ( craftParts[index].Carac[i]  )
		{
			if ( !creature )
				stat = mediumStatsByStatQuality[ level-1 ];
			else
				stat = mediumStatsByStatQuality[ level ];
			
			// gestion des points forts/faibles de la MP
			if ( i == bestStat )
			{
				if ( worstStat2 == -1 )
					stat += 20;
				else
					stat += 40;

				if ( stat > 100 )
				{
					// si une des stats dépasse 100, les autres
					// stats sont augmentées
					remaining = stat - 100;
					stat = 100;
				}
			}
			else if ( ( i == worstStat1 ) || ( i == worstStat2 ) )
			{
				stat -= 20;

				// durabilité minimum
				if ( ( i == 0 ) && ( stat < 1 ) )
					stat = 1;
			}
			else
				nbToRaise++;

			stats[i] = stat;
		}
		else 
			stats[i] = -1;
	}

	if ( nbToRaise != 0 )
		ajout = remaining/nbToRaise;
	
	// ajout des informations pour chaque carac
	for ( int i=0; i<NumMPStats; i++ )
	{
		if ( stats[i] != -1 )
		{
			if ( ( i != bestStat ) && ( i != worstStat1 ) && ( i != worstStat2 ) )
				stats[i] += ajout;
		
			outStr += "          <ATOM Name=\"";
			outStr += carac[i];
			outStr += "\" Value=\"";
			
			sprintf( buf, "%d", stats[i] );

			outStr += buf;
			outStr += "\"/>\n";
		}
	}

	// CraftCivSpec en fonction de l'écosystème
	outStr += "          <ATOM Name=\"CraftCivSpec\" Value=\"";
	CSString craftCiv;

	switch ( eco )
	{
	case 'c' :
		outStr += "common";
		craftCiv = "All";
		break;

	case 'd' :
		outStr += "fyros";
		craftCiv = "Fyros";
		break;

	case 'f' :
		outStr += "matis";
		craftCiv = "Matis";
		break;

	case 'j' :
		outStr += "zorai";
		craftCiv = "Zorai";
		break;

	case 'l' :
		outStr += "tryker";
		craftCiv = "Tryker";
		break;

	case 'p' :
		outStr += "common";
		craftCiv = "All";
		break;
	}

	currentDocItem.push( DtCraftCivSpec, craftCiv );

	outStr += "\"/>\n        </STRUCT>\n";
}