Example #1
0
DGLE_RESULT DGLE_API CMesh::RecalculateTangentSpace()
{
	if (!_pBuffer)
		return S_FALSE;
	
	TDrawDataDesc desc;
		
	_pBuffer->GetBufferDrawDataDesc(desc);

	if (desc.uiTextureVertexOffset == -1 ||
		(desc.uiTangentOffset == -1 && desc.uiBinormalOffset != -1) || (desc.uiTangentOffset != -1 && desc.uiBinormalOffset == -1)) // confusing situation should never happen
		return E_ABORT;

	if (desc.uiNormalOffset == -1)
		RecalculateNormals(false);

	uint stride, verts_data_size, verts_count, idxs_data_size, idxs_count;
	_CopyMeshData(desc, stride, verts_data_size, verts_count, idxs_data_size, idxs_count);

	TDrawDataDesc desc_new(desc);
	bool do_delete_new = false;

	if (desc.uiTangentOffset == -1 && desc.uiBinormalOffset == -1)
	{
		do_delete_new = true;

		const uint new_verts_data_size = verts_data_size + verts_count * 6 * sizeof(float);
		desc_new.pData = new uint8[new_verts_data_size + idxs_data_size];
		memcpy(desc_new.pData, desc.pData, verts_data_size);

		desc_new.uiTangentOffset = verts_data_size;
		desc_new.uiTangentStride = 0;

		desc_new.uiBinormalOffset = verts_data_size + verts_count * 3 * sizeof(float);
		desc_new.uiBinormalStride = 0;

		if (idxs_count != 0)
		{
			desc_new.pIndexBuffer = &desc_new.pData[new_verts_data_size];
			memcpy(&desc_new.pData[new_verts_data_size], &desc.pData[verts_data_size], idxs_data_size);
		}

		memset(&desc_new.pData[verts_data_size], 0, new_verts_data_size - verts_data_size);
	}
	else
	{
		const uint t_stride = desc_new.uiTangentStride == 0 ? 3 * sizeof(float) : desc_new.uiTangentStride,
			b_stride = desc_new.uiBinormalStride == 0 ? 3 * sizeof(float) : desc_new.uiBinormalStride;

		for (uint i = 0; i < verts_count; ++i)
		{
			*(reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiTangentOffset + i * t_stride])) = TVector3();
			*(reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiBinormalOffset + i * b_stride])) = TVector3();
		}
	}

	const uint t_stride = desc_new.uiTangentStride == 0 ? 3 * sizeof(float) : desc_new.uiTangentStride,
		b_stride = desc_new.uiBinormalStride == 0 ? 3 * sizeof(float) : desc_new.uiBinormalStride,
		tex_stride = desc_new.uiTextureVertexStride == 0 ? 2 * sizeof(float) : desc_new.uiTextureVertexStride,
		v_stride = desc_new.uiVertexStride == 0 ? 3 * sizeof(float) : desc_new.uiVertexStride,
		n_stride = desc_new.uiNormalStride == 0 ? 3 * sizeof(float) : desc_new.uiNormalStride,
		count = idxs_count == 0 ? verts_count / 3 : idxs_count / 3;

	for(uint i = 0; i < count; ++i)
	{
		uint face[3];

		if (idxs_count == 0)
		{
			face[0] = i * 3;
			face[1] = i * 3 + 1;
			face[2] = i * 3 + 2;
		}
		else
			if (desc_new.bIndexBuffer32)
			{
				face[0] = reinterpret_cast<uint *>(&desc_new.pIndexBuffer[i * 3 * sizeof(uint)])[0];
				face[1] = reinterpret_cast<uint *>(&desc_new.pIndexBuffer[i * 3 * sizeof(uint)])[1];
				face[2] = reinterpret_cast<uint *>(&desc_new.pIndexBuffer[i * 3 * sizeof(uint)])[2];
			}
			else
			{
				face[0] = reinterpret_cast<uint16 *>(&desc_new.pIndexBuffer[i * 3 * sizeof(uint16)])[0];
				face[1] = reinterpret_cast<uint16 *>(&desc_new.pIndexBuffer[i * 3 * sizeof(uint16)])[1];
				face[2] = reinterpret_cast<uint16 *>(&desc_new.pIndexBuffer[i * 3 * sizeof(uint16)])[2];
			}
			
		const TPoint3 * const v[3] = {
			reinterpret_cast<TPoint3 *>(&desc_new.pData[face[0] * v_stride]),
			reinterpret_cast<TPoint3 *>(&desc_new.pData[face[1] * v_stride]),
			reinterpret_cast<TPoint3 *>(&desc_new.pData[face[2] * v_stride])};

		const TPoint2 * const t[3] = {
			reinterpret_cast<TPoint2 *>(&desc_new.pData[desc_new.uiTextureVertexOffset + face[0] * tex_stride]),
			reinterpret_cast<TPoint2 *>(&desc_new.pData[desc_new.uiTextureVertexOffset + face[1] * tex_stride]),
			reinterpret_cast<TPoint2 *>(&desc_new.pData[desc_new.uiTextureVertexOffset + face[2] * tex_stride])};

		const TVector3 v1 = *v[1] - *v[0], v2 = *v[2] - *v[0];
		const TVector2 v3 = *t[1] - *t[0], v4 = *t[2] - *t[0];

		const float d = v3.Cross(v4);

		if (d == 0.f) continue;

		const float r = 1.f / d;

		const TVector3 sdir = TVector3(v4.y * v1.x - v4.x * v2.x, v4.y * v1.y - v4.x * v2.y, v4.y * v1.z - v4.x * v2.z) * r,
			tdir = TVector3(v3.x * v2.x - v3.y * v1.x, v3.x * v2.y - v3.y * v1.y, v3.x * v2.z - v3.y * v1.z) * r;

		*(reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiTangentOffset + face[0] * t_stride])) += sdir;
		*(reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiTangentOffset + face[1] * t_stride])) += sdir;
		*(reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiTangentOffset + face[2] * t_stride])) += sdir;

		*(reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiBinormalOffset + face[0] * b_stride])) += tdir;
		*(reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiBinormalOffset + face[1] * b_stride])) += tdir;
		*(reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiBinormalOffset + face[2] * b_stride])) += tdir;
	}

	for (uint i = 0; i < verts_count; ++i)
	{
		const TVector3 * const normal = reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiNormalOffset + i * n_stride]);
		TVector3 *tangent = reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiTangentOffset + i * t_stride]),
			*binormal = reinterpret_cast<TVector3 *>(&desc_new.pData[desc_new.uiBinormalOffset + i * b_stride]);
		
		float dot_1 = normal->Dot(*tangent), dot_2;
		*tangent = (*tangent - *normal * dot_1).Normalize();
		dot_1 = normal->Dot(*tangent);
		dot_2 = tangent->Dot(*binormal);
		*binormal = (*binormal - *normal * dot_1 + *tangent * dot_2).Normalize();
	}

	PARANOIC_CHECK_RES(_pBuffer->Reallocate(desc_new, verts_count, idxs_count, CRDM_TRIANGLES));

	if (do_delete_new)
		delete[] desc_new.pData;

	delete[] desc.pData;

	return S_OK;
}