void TerrainTessellator::draw(const GraphicsDevice& device, unsigned levelOfDetail, unsigned primitiveCount, const IndexBufferCollection& indexBuffers, const std::vector<TerrainInstance>& instances, unsigned numInstances) const
{
	instanceVertexBuffer.setData(instances, D3DLOCK_DISCARD);

	device.setStreamSource(vertexBuffer, sizeof(TerrainVertex));
	device.setStreamSourceFreq(0, D3DSTREAMSOURCE_INDEXEDDATA | numInstances);

	device.setStreamSource(instanceVertexBuffer, sizeof(TerrainInstance), 1);
	device.setStreamSourceFreq(1, D3DSTREAMSOURCE_INSTANCEDATA | 1);

	device.setVertexDeclaration(instanceVertexDeclaration);

	device.setIndices(indexBuffers[levelOfDetail]);

	device.drawIndexedPrimitive(D3DPT_TRIANGLELIST, primitiveCount, numVertices);
}
void FBXModel::draw(const GraphicsDevice& device, const GameTime& gameTime, const Matrix& world, const Matrix& view, const Matrix& projection, const std::vector<Matrix>& instanceTransforms, unsigned numInstances, FBXEffect& effect, bool shadowMap)
{
	if (numInstances == 0)
		return;

	instanceVertexBuffer.setData(&instanceTransforms[0], numInstances, D3DLOCK_DISCARD);

	if (!animations.empty())
		effect.setBoneMatrices(getBoneMatrices(getAnimationFrame(gameTime)));

	effect.setTechnique(!animations.empty(), shadowMap);

	effect.setCamera(camera);
	effect.setLight(light);
	effect.setClipPlane(clipPlane);
	effect.setAlphaCutoff(alphaCutoff);

	effect.setWorld(world);
	effect.setView(view);
	effect.setProjection(projection);

	device.setVertexDeclaration(vertexDeclaration);

	device.setStreamSource(instanceVertexBuffer, sizeof(InstanceType), 1);
	device.setStreamSourceFreq(1, D3DSTREAMSOURCE_INSTANCEDATA | 1);

	effect.beginSinglePass();

	for (MeshMap::iterator it = meshes.begin(); it != meshes.end(); ++it)
	{
		FBXMesh& fbxMesh = it->second;

		if (!fbxMesh.visible)
			continue;

		Mesh& mesh = fbxMesh.mesh;

		device.setIndices(mesh.getIndexBuffer());

		device.setStreamSource(mesh.getVertexBuffer(), sizeof(FBXVertex));
		device.setStreamSourceFreq(0, D3DSTREAMSOURCE_INDEXEDDATA | numInstances);

		unsigned numMaterials = fbxMesh.materials.size();

		Mesh::AttributeTable attributeTable = mesh.getAttributeTable(numMaterials);

		for (unsigned j = 0; j < numMaterials; ++j)
		{
			FBXMaterial& fbxMaterial = fbxMesh.materials[j];

			Material material = fbxMaterial.material;

			if (Vector3(material.Diffuse) == keyColor)
				material.Diffuse = Vector4((keyColorEnabled) ? keyColorReplace : keyColor);

			if (Vector3(material.Ambient) == keyColor)
				material.Ambient = Vector4((keyColorEnabled) ? keyColorReplace : keyColor);

			switch (fbxMesh.colorFunction)
			{
				case FBXColorFunction::colorMultiply:
					{
						material.Ambient = Vector4(material.Ambient) * Vector4(fbxMesh.color);
						material.Diffuse = Vector4(material.Diffuse) * Vector4(fbxMesh.color);
						effect.setColormap(fbxMaterial.texture);
					}
					break;

				case FBXColorFunction::colorOverride:
					{
						material.Ambient = fbxMesh.color;
						material.Diffuse = fbxMesh.color;
						effect.setColormap(defaultTexture);
					}
					break;

				case FBXColorFunction::colorAdd:
					{
						material.Ambient = Vector4(Vector3(fbxMesh.color + Vector3(material.Ambient)));
						material.Diffuse = Vector4(Vector3(fbxMesh.color + Vector3(material.Diffuse)));
						effect.setColormap(fbxMaterial.texture);
					}
					break;
			}

			effect.setMaterial(material);
			effect.commitChanges();

			D3DXATTRIBUTERANGE& range = attributeTable[j];

			device.drawIndexedPrimitive(D3DPT_TRIANGLELIST, range.FaceCount, range.VertexCount, 0, range.VertexStart, range.FaceStart * 3);
		}
	}

	effect.endSinglePass();
}