Ok, I found a solution to my problem: ConcurrentDictionary of string, VertexBuffer, ConcurrentDictionary of string, IndexBuffer and ConcurrentDictionary of string, Texture2D.
With them, I can create each VertexBuffer and IndexBuffer for a texture name stored in a string.
Then I can easily access all data I need: loading a Texture 2D, setting a name for it and setting a block to use it.
First I create each VertexBuffer and IndexBuffer for each block type in the map, storing in the ConcurrentDictionary the block's texture name as the string parameter and the data created.
When the drawing function comes, I check every VertexBuffer in the ConcurrentDictionary and decide which texture to use using its name, then get the IndexBuffer and Texture2D for it from each ConcurrentDictionary.
I'll provide more details later, if I can edit the post.
Edit: here are my codes:
First, in my content loader, I make the texture be detected and added to a ConcurrentDictionary in another class:
dynamic XNAobject = Game.Content.Load<dynamic>(path);
// [...]
else if (XNAobject is Texture2D && path.Contains("Terrain") && path.EndsWith("Atlas")) {
Console.WriteLine(this + " adicionando textura de terreno");
TextureManager.AddTerrainTexture((Texture2D)XNAobject, path);
}
Here's the class that contains the ConcurrentDictionary.
#region Texturas do Terreno
/// <summary>
/// Todas as texturas carregadas, classificadas pelo caminho do arquivo (Tag).
/// </summary>
internal static ConcurrentDictionary<string, Texture2D> TerrainTextures = new ConcurrentDictionary<string, Texture2D>();
#endregion
#endregion
#region Adicionar Textura
internal static void AddTerrainTexture(Texture2D texture2DAtlas, object tag) {
texture2DAtlas.Tag = tag;
if (!(tag is string)) { return; }
string stringTag = (string)tag;
string texture2DName = stringTag.Substring(stringTag.LastIndexOf("\\") + 1, (stringTag.LastIndexOf("Atlas")) - (stringTag.LastIndexOf("\\") + 1));
//Debug.WriteLine("textura 2D adicionada: " + texture2DName);
Texture2D oldValue;
texture2DAtlas.Name = texture2DName;
if (!TerrainTextures.TryGetValue(texture2DName, out oldValue)) { TerrainTextures.TryAdd(texture2DName, texture2DAtlas); }
}
#endregion
Here's the process of creating and saving the buffers for each texture. But I didn't show here the vertex creation still.
// Criar buffers.
#region Buffers
lock (chunk) {
chunk.IndexBuffers.Clear(); chunk.VertexBuffers.Clear();
// Adquirir dados finais do chunk.
foreach (var list in chunk.Vertexes) { string textureName = list.Key;
IVertexType[] vertexes = list.Value.ToArray();
short[] indexes = chunk.Indexes[textureName].ToArray();
if (vertexes.Length > 0) {
//// Buffer de vértices.
chunk.VertexBuffers.TryAdd(textureName,
new VertexBuffer(GraphicsDevice, typeof(VertexPositionNormalTextureLight), vertexes.Length, BufferUsage.WriteOnly));
// Converter para o tipo.
VertexPositionNormalTextureLight[] vertexesConverted = new VertexPositionNormalTextureLight[vertexes.Length];
for (int i = 0; i < vertexes.Length; i ++) {
vertexesConverted[i] = (VertexPositionNormalTextureLight)vertexes[i];
}
chunk.VertexBuffers[textureName].SetData(vertexesConverted);
// Buffer de índices.
chunk.IndexBuffers.TryAdd(textureName,
new IndexBuffer(GraphicsDevice, IndexElementSize.SixteenBits, indexes.Length, BufferUsage.WriteOnly));
chunk.IndexBuffers[textureName].SetData(indexes);
}
}
chunk.NeedsBuild = false;
}
#endregion
And some of the chunk data needed for the buffers:
#region Vértices
/// <summary>
/// Listas de todos os vértices do chunk, para serem desenhados.
/// </summary>
public ConcurrentDictionary<string, List<IVertexType>> Vertexes =
new ConcurrentDictionary<string, List<IVertexType>>();
public ConcurrentDictionary<string, short> VertexCounts = new ConcurrentDictionary<string, short>();
/// <summary>
/// Listas de todos os índices para a ordem de vértices neste chunk.
/// </summary>
public ConcurrentDictionary<string, List<short>> Indexes =
new ConcurrentDictionary<string, List<short>>();
#endregion
#region Buffers
/// <summary>
/// Lista de Buffers de vértices dos blocos do chunk.
/// Cada buffer pode ser usado para aplicar determinado efeito.
/// </summary>
public ConcurrentDictionary<string, VertexBuffer> VertexBuffers = new ConcurrentDictionary<string, VertexBuffer>();
/// <summary>
/// Lista de Buffers de índices do chunk.
/// </summary>
public ConcurrentDictionary<string, IndexBuffer> IndexBuffers = new ConcurrentDictionary<string, IndexBuffer>();
#endregion
Then, after building a VertexBuffer and a IndexBuffer for each texture, and saving in a ConcurrentDictionary with the texture's name, I can access it by the texture's name and draw it:
lock (chunk) {
// Desenhar vértices dos blocos, com as texturas para eles.
foreach (var list in chunk.VertexBuffers) { string textureName = list.Key;
Texture2D texture;
if (TextureManager.TerrainTextures.TryGetValue(textureName, out texture)) {
// Colocar a textura selecionada da lista.
TextureManager.DynamicTexturingEffect.Parameters["Texture1"].SetValue(texture);
//Debug.WriteLine(texture.Name);
// Ativar as opções de efeito para o dispositivo gráfico e desenhar com elas.
foreach (EffectPass pass in TextureManager.DynamicTexturingEffect.CurrentTechnique.Passes) {
pass.Apply();
VertexBuffer vertexBuffer; IndexBuffer indexBuffer;
if (chunk.IndexBuffers.TryGetValue(textureName, out indexBuffer) && chunk.VertexBuffers.TryGetValue(textureName, out vertexBuffer)) {
if (indexBuffer.IndexCount > 0) {
lock (GraphicsDevice) {
GraphicsDevice.SetVertexBuffer(vertexBuffer);
GraphicsDevice.Indices = indexBuffer;
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexBuffer.VertexCount, 0, indexBuffer.IndexCount / 3);
}
}
}
}
}
}
}