/// <summary> /// Gets the texture maps for the model /// </summary> /// <returns>The texture maps in byte arrays inside a ModelTextureData class</returns> public ModelTextureData GetModelMaps(Color?customColor = null, bool colorChangeShader = false) { var texMapData = GetTexMapData(); var dimensions = EqualizeTextureSizes(texMapData); var materialType = GetMaterialType(_mtrlData.MTRLPath); var diffuseMap = new List <byte>(); var normalMap = new List <byte>(); var specularMap = new List <byte>(); var emissiveMap = new List <byte>(); var alphaMap = new List <byte>(); var diffuseColorList = new List <Color>(); var specularColorList = new List <Color>(); var emissiveColorList = new List <Color>(); if (texMapData.ColorSet != null) { var colorPixels = texMapData.ColorSet.Data; for (var i = 0; i < texMapData.ColorSet.Data.Length; i += 16) { int red = colorPixels[i]; int green = colorPixels[i + 1]; int blue = colorPixels[i + 2]; int alpha = colorPixels[i + 3]; diffuseColorList.Add(new Color(red, green, blue)); red = colorPixels[i + 4]; green = colorPixels[i + 5]; blue = colorPixels[i + 6]; alpha = colorPixels[i + 7]; specularColorList.Add(new Color(red, green, blue)); red = colorPixels[i + 8]; green = colorPixels[i + 9]; blue = colorPixels[i + 10]; alpha = colorPixels[i + 11]; emissiveColorList.Add(new Color(red, green, blue)); } } else { for (var i = 0; i < 1024; i += 16) { if (!materialType.Equals("other") && !materialType.Equals("housing")) { if (customColor != null) { diffuseColorList.Add(customColor.GetValueOrDefault()); } else { if (!materialType.Equals("body")) { diffuseColorList.Add(new Color(96, 57, 19)); } else { diffuseColorList.Add(new Color(255, 255, 255)); } } } else { diffuseColorList.Add(new Color(255, 255, 255)); } specularColorList.Add(new Color(25, 25, 25)); emissiveColorList.Add(new Color(0, 0, 0)); } } byte[] diffusePixels = null, specularPixels = null, multiPixels = null, skinPixels = null, normalPixels = null; if (texMapData.Normal != null) { normalPixels = texMapData.Normal.Data; } if (texMapData.Diffuse != null) { diffusePixels = texMapData.Diffuse.Data; } if (texMapData.Specular != null) { specularPixels = texMapData.Specular.Data; } if (texMapData.Multi != null) { multiPixels = texMapData.Multi.Data; } if (texMapData.Skin != null) { skinPixels = texMapData.Skin.Data; } byte diffR = 255, diffG = 255, diffB = 255; byte specR = 255, specG = 255, specB = 255; byte normR = 255, normG = 255, normB = 255; var dataLength = 0; if (normalPixels != null) { dataLength = normalPixels.Length; } else if (diffusePixels != null) { dataLength = diffusePixels.Length; } for (var i = 3; i < dataLength; i += 4) { var alpha = 255; if (normalPixels != null) { normR = normalPixels[i - 3]; normG = normalPixels[i - 2]; alpha = normalPixels[i - 1]; // This is the normal maps blue channel, and usually acts as the alpha channel if (materialType.Equals("hair") || materialType.Equals("etc") || materialType.Equals("tail")) { normR = normalPixels[i - 3]; normG = normalPixels[i - 2]; normB = normalPixels[i - 1]; alpha = normalPixels[i]; } } else if (diffusePixels != null) { alpha = diffusePixels[i]; } if (materialType.Equals("housing")) { if (colorChangeShader) { alpha = normalPixels != null ? normalPixels[i] : 255; } else { alpha = diffusePixels != null ? diffusePixels[i] : 255; } } if (multiPixels != null) { diffR = multiPixels[i - 3]; diffG = multiPixels[i - 3]; diffB = multiPixels[i - 3]; specR = multiPixels[i - 1]; specG = multiPixels[i - 1]; specB = multiPixels[i - 1]; } else { if (diffusePixels != null) { diffR = diffusePixels[i - 3]; diffG = diffusePixels[i - 2]; diffB = diffusePixels[i - 1]; } if (specularPixels != null) { if (specularPixels.Length > i) { specR = specularPixels[i - 3]; specG = specularPixels[i - 2]; specB = specularPixels[i - 1]; } } if (skinPixels != null) { specR = skinPixels[i - 3]; specG = skinPixels[i - 2]; specB = skinPixels[i - 1]; } } Color diffuseColor, specularColor, emissiveColor, alphaColor; var pixel = 0f; var blendPercent = 0f; if (normalPixels != null) { pixel = (normalPixels[i] / 255f) * 15f; blendPercent = (float)(pixel - Math.Truncate(pixel)); } if (materialType.Equals("hair") || materialType.Equals("etc") || materialType.Equals("tail")) { pixel = 0; blendPercent = 0; } if (blendPercent != 0) { var firstColorLocation = (int)Math.Truncate(pixel); var secondColorLocation = firstColorLocation + 1; var diffColor1 = diffuseColorList[secondColorLocation]; var diffColor2 = diffuseColorList[firstColorLocation]; var firstColor = new Color(diffColor1.R, diffColor1.G, diffColor1.B, alpha); var secondColor = new Color(diffColor2.R, diffColor2.G, diffColor2.B, alpha); var diffuseBlend = Blend(firstColor, secondColor, blendPercent); var specColor1 = specularColorList[secondColorLocation]; var specColor2 = specularColorList[firstColorLocation]; firstColor = new Color(specColor1.R, specColor1.G, specColor1.B, (byte)255); secondColor = new Color(specColor2.R, specColor2.G, specColor2.B, (byte)255); var specBlend = Blend(firstColor, secondColor, blendPercent); var emisColor1 = emissiveColorList[secondColorLocation]; var emisColor2 = emissiveColorList[firstColorLocation]; firstColor = new Color(emisColor1.R, emisColor1.G, emisColor1.B, (byte)255); secondColor = new Color(emisColor2.R, emisColor2.G, emisColor2.B, (byte)255); var emisBlend = Blend(firstColor, secondColor, blendPercent); diffuseColor = new Color((int)((diffuseBlend.R / 255f) * diffR), (int)((diffuseBlend.G / 255f) * diffG), (int)((diffuseBlend.B / 255f) * diffB), alpha); specularColor = new Color((int)((specBlend.R / 255f) * specR), (int)((specBlend.G / 255f) * specG), (int)((specBlend.B / 255f) * specB), 255); emissiveColor = new Color((int)emisBlend.R, (int)emisBlend.G, (int)emisBlend.B, (int)255); } else { var colorLoc = (int)Math.Floor(pixel + 0.5f); var diffColor = diffuseColorList[colorLoc]; var specColor = specularColorList[colorLoc]; var emisColor = emissiveColorList[colorLoc]; if (materialType.Equals("hair") || materialType.Equals("etc") || materialType.Equals("tail")) { diffuseColor = new Color((int)((diffColor.R / 255f) * specR), (int)((diffColor.G / 255f) * specR), (int)((diffColor.B / 255f) * specR), alpha); specularColor = new Color((int)((specColor.R / 255f) * specG), (int)((specColor.G / 255f) * specG), (int)((specColor.B / 255f) * specG), 255); } else { diffuseColor = new Color((int)((diffColor.R / 255f) * diffR), (int)((diffColor.G / 255f) * diffG), (int)((diffColor.B / 255f) * diffB), alpha); if (materialType.Equals("body")) { specularColor = new Color((int)((specColor.R / 255f) * specG), (int)((specColor.G / 255f) * specG), (int)((specColor.B / 255f) * specG), 255); } else if (materialType.Equals("housing")) { specularColor = new Color((int)((specColor.R / 255f) * specG), (int)((specColor.G / 255f) * specG), (int)((specColor.B / 255f) * specG), 255); } else { specularColor = new Color((int)((specColor.R / 255f) * specB), (int)((specColor.G / 255f) * specB), (int)((specColor.B / 255f) * specB), 255); } } emissiveColor = new Color((int)emisColor.R, (int)emisColor.G, (int)emisColor.B, (int)255); } alphaColor = new Color((int)alpha, (int)alpha, (int)alpha, (int)alpha); diffuseMap.AddRange(BitConverter.GetBytes(diffuseColor.ToRgba())); specularMap.AddRange(BitConverter.GetBytes(specularColor.ToRgba())); emissiveMap.AddRange(BitConverter.GetBytes(emissiveColor.ToRgba())); alphaMap.AddRange(BitConverter.GetBytes(alphaColor.ToRgba())); normalMap.AddRange(BitConverter.GetBytes(new Color(normR, normG, normB, (byte)255).ToRgba())); } var modelTextureData = new ModelTextureData { Width = dimensions.Width, Height = dimensions.Height, Normal = normalMap.ToArray(), Diffuse = diffuseMap.ToArray(), Specular = specularMap.ToArray(), Emissive = emissiveMap.ToArray(), Alpha = alphaMap.ToArray() }; return(modelTextureData); }
/// <summary> /// Gets the texture maps for the model /// </summary> /// <returns>The texture maps in byte arrays inside a ModelTextureData class</returns> public static async Task <ModelTextureData> GetModelMaps(Tex tex, XivMtrl mtrl, CustomModelColors colors = null) { // Use static values as needed. if (colors == null) { colors = GetCustomColors(); } var shaderInfo = mtrl.GetShaderInfo(); var mtrlMaps = mtrl.GetAllMapInfos(); var texMapData = await GetTexMapData(tex, mtrl); var dimensions = await EqualizeTextureSizes(texMapData); var diffuseMap = new List <byte>(); var normalMap = new List <byte>(); var specularMap = new List <byte>(); var emissiveMap = new List <byte>(); var alphaMap = new List <byte>(); var diffuseColorList = new List <Color>(); var specularColorList = new List <Color>(); var emissiveColorList = new List <Color>(); byte[] diffusePixels = null, specularPixels = null, normalPixels = null; if (texMapData.Normal != null) { normalPixels = texMapData.Normal.Data; } if (texMapData.Diffuse != null) { diffusePixels = texMapData.Diffuse.Data; } if (texMapData.Specular != null) { specularPixels = texMapData.Specular.Data; } if (normalPixels == null && diffusePixels == null) { // This material doesn't actually have any readable data. var empty = new ModelTextureData { Width = 0, Height = 0, Normal = new byte[0], Diffuse = new byte[0], Specular = new byte[0], Emissive = new byte[0], Alpha = new byte[0], MaterialPath = mtrl.MTRLPath.Substring(mtrl.MTRLPath.LastIndexOf('/')) }; return(empty); } var dataLength = normalPixels != null ? normalPixels.Length : diffusePixels.Length; await Task.Run(() => { for (var i = 3; i < dataLength; i += 4) { // Load the individual pixels into memory. Color baseNormalColor = new Color(127, 127, 255, 255); Color baseDiffuseColor = new Color(255, 255, 255, 255); Color baseSpecularColor = new Color(255, 255, 255, 255); if (normalPixels != null) { baseNormalColor = new Color(normalPixels[i - 3], normalPixels[i - 2], normalPixels[i - 1], normalPixels[i]); } if (diffusePixels != null) { baseDiffuseColor = new Color(diffusePixels[i - 3], diffusePixels[i - 2], diffusePixels[i - 1], diffusePixels[i]); } if (specularPixels != null) { baseSpecularColor = new Color(specularPixels[i - 3], specularPixels[i - 2], specularPixels[i - 1], specularPixels[i]); } byte colorsetValue = baseNormalColor.A; // Calculate real colors from the inputs and shader. Color normalColor, diffuseColor, specularColor; byte opacity; ComputeShaderColors(colors, shaderInfo, baseNormalColor, baseDiffuseColor, baseSpecularColor, out normalColor, out diffuseColor, out specularColor, out opacity); Color alphaColor = new Color(opacity, opacity, opacity, opacity); // Apply colorset if needed. (This could really be baked into ComputeShaderColors) Color emissiveColor = new Color(0, 0, 0, 0); if (mtrl.ColorSetData.Count > 0) { var cs = texMapData.ColorSet.Data; Color finalDiffuseColor, finalSpecularColor; ComputeColorsetBlending(mtrl, colorsetValue, cs, diffuseColor, specularColor, out finalDiffuseColor, out finalSpecularColor, out emissiveColor); diffuseColor = finalDiffuseColor; specularColor = finalSpecularColor; } // White out the opacity channels where appropriate. diffuseColor.A = opacity; specularColor.A = 255; normalColor.A = 255; diffuseMap.AddRange(BitConverter.GetBytes(diffuseColor.ToRgba())); specularMap.AddRange(BitConverter.GetBytes(specularColor.ToRgba())); emissiveMap.AddRange(BitConverter.GetBytes(emissiveColor.ToRgba())); alphaMap.AddRange(BitConverter.GetBytes(alphaColor.ToRgba())); normalMap.AddRange(BitConverter.GetBytes(normalColor.ToRgba())); } }); var modelTextureData = new ModelTextureData { Width = dimensions.Width, Height = dimensions.Height, Normal = normalMap.ToArray(), Diffuse = diffuseMap.ToArray(), Specular = specularMap.ToArray(), Emissive = emissiveMap.ToArray(), Alpha = alphaMap.ToArray(), MaterialPath = mtrl.MTRLPath.Substring(mtrl.MTRLPath.LastIndexOf('/')) }; return(modelTextureData); }