public static void BuildAvatarGeometry(StudioMdlWriter meshBuilder, StudioBone bone) { Contract.Requires(meshBuilder != null && bone != null); string task = "BuildGeometry_" + bone.Node.Name; Rbx2Source.ScheduleTasks(task); Node node = bone.Node; BasePart part = bone.Part1; bool isAvatarLimb = bone.IsAvatarBone; string matName = part.Name; if (isAvatarLimb) { BodyPart?limb = GetLimb(part); if (!limb.HasValue) { throw new ArgumentException("Provided StudioBone did not point to a limb correctly."); } matName = Rbx2Source.GetEnumName(limb.Value); } var material = new ValveMaterial() { UseAvatarMap = isAvatarLimb }; Rbx2Source.Print("Building Geometry for {0}", part.Name); Rbx2Source.IncrementStack(); Mesh geometry = Mesh.BakePart(part, material); meshBuilder.Materials[matName] = material; for (int i = 0; i < geometry.NumFaces; i++) { Triangle tri = new Triangle() { Node = node, FaceIndex = i, Mesh = geometry, Material = matName }; meshBuilder.Triangles.Add(tri); } Rbx2Source.DecrementStack(); Rbx2Source.MarkTaskCompleted(task); }
public static void BuildAvatarGeometry(StudioMdlWriter meshBuilder, Bone bone) { string task = "BuildGeometry_" + bone.Node.Name; Rbx2Source.ScheduleTasks(task); Node node = bone.Node; Part part = bone.Part1; bool IsAvatarLimb = bone.IsAvatarBone; string materialName; if (IsAvatarLimb) { Limb limb = GetLimb(part); materialName = Rbx2Source.GetEnumName(limb); } else { materialName = part.Name; } Material material = new Material(); material.UseAvatarMap = IsAvatarLimb; Rbx2Source.Print("Building Geometry for {0}", part.Name); Rbx2Source.IncrementStack(); Mesh geometry = Mesh.BakePart(part, material); if (!meshBuilder.Materials.ContainsKey(materialName)) { meshBuilder.Materials.Add(materialName, material); } for (int i = 0; i < geometry.FaceCount; i++) { Triangle tri = new Triangle(); tri.Node = node; tri.Mesh = geometry; tri.FaceIndex = i; tri.Material = materialName; meshBuilder.Triangles.Add(tri); } Rbx2Source.DecrementStack(); Rbx2Source.MarkTaskCompleted(task); }
public static void BuildAvatarGeometry(StudioMdlWriter meshBuilder, Bone bone) { string task = "BuildGeometry_" + bone.Node.Name; Rbx2Source.ScheduleTasks(task); Node node = bone.Node; BasePart part = bone.Part1; bool isAvatarLimb = bone.IsAvatarBone; string matName = part.Name; if (isAvatarLimb) { Limb limb = GetLimb(part); matName = Rbx2Source.GetEnumName(limb); } Material material = new Material(); material.UseAvatarMap = isAvatarLimb; Rbx2Source.Print("Building Geometry for {0}", part.Name); Rbx2Source.IncrementStack(); Mesh geometry = Mesh.BakePart(part, material); meshBuilder.Materials[matName] = material; for (int i = 0; i < geometry.NumFaces; i++) { Triangle tri = new Triangle() { Node = node, FaceIndex = i, Mesh = geometry, Material = matName }; meshBuilder.Triangles.Add(tri); } Rbx2Source.DecrementStack(); Rbx2Source.MarkTaskCompleted(task); }
public AssemblerData Assemble(UserAvatar avatar) { Contract.Requires(avatar != null); UserInfo userInfo = avatar.UserInfo; string userName = FileUtility.MakeNameWindowsSafe(userInfo.Username); string appData = Environment.GetEnvironmentVariable("LocalAppData"); string rbx2Src = Path.Combine(appData, "Rbx2Source"); string avatars = Path.Combine(rbx2Src, "Avatars"); string userBin = Path.Combine(avatars, userName); string modelDir = Path.Combine(userBin, "Model"); string anim8Dir = Path.Combine(modelDir, "Animations"); string texturesDir = Path.Combine(userBin, "Textures"); string materialsDir = Path.Combine(userBin, "Materials"); FileUtility.InitiateEmptyDirectories(modelDir, anim8Dir, texturesDir, materialsDir); AvatarType avatarType = avatar.PlayerAvatarType; ICharacterAssembler assembler; if (avatarType == AvatarType.R15) { assembler = new R15CharacterAssembler(); } else { assembler = new R6CharacterAssembler(); } string compileDir = "roblox_avatars/" + userName; string avatarTypeName = Rbx2Source.GetEnumName(avatarType); Folder characterAssets = AppendCharacterAssets(avatar, avatarTypeName); Rbx2Source.ScheduleTasks ( "BuildCharacter", "BuildCollisionModel", "BuildAnimations", "BuildTextures", "BuildMaterials", "BuildCompilerScript" ); Rbx2Source.PrintHeader("BUILDING CHARACTER MODEL"); #region Build Character Model /////////////////////////////////////////////////////////////////////////////////////////////////////// StudioMdlWriter writer = assembler.AssembleModel(characterAssets, avatar.Scales, DEBUG_RAPID_ASSEMBLY); string studioMdl = writer.BuildFile(); string modelPath = Path.Combine(modelDir, "CharacterModel.smd"); FileUtility.WriteFile(modelPath, studioMdl); string staticPose = writer.BuildFile(false); string refPath = Path.Combine(modelDir, "ReferencePos.smd"); FileUtility.WriteFile(refPath, staticPose); Rbx2Source.MarkTaskCompleted("BuildCharacter"); /////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion Rbx2Source.PrintHeader("BUILDING COLLISION MODEL"); #region Build Character Collisions /////////////////////////////////////////////////////////////////////////////////////////////////////// Folder collisionAssets = AppendCollisionAssets(avatar, avatarTypeName); StudioMdlWriter collisionWriter = assembler.AssembleModel(collisionAssets, avatar.Scales, true); string collisionModel = collisionWriter.BuildFile(); string cmodelPath = Path.Combine(modelDir, "CollisionModel.smd"); FileUtility.WriteFile(cmodelPath, collisionModel); byte[] collisionJoints = assembler.CollisionModelScript; string cjointsPath = Path.Combine(modelDir, "CollisionJoints.qc"); FileUtility.WriteFile(cjointsPath, collisionJoints); Rbx2Source.MarkTaskCompleted("BuildCollisionModel"); /////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion Rbx2Source.PrintHeader("BUILDING CHARACTER ANIMATIONS"); #region Build Character Animations /////////////////////////////////////////////////////////////////////////////////////////////////////// var animIds = assembler.CollectAnimationIds(avatar); var compileAnims = new Dictionary <string, Asset>(); if (animIds.Count > 0) { Rbx2Source.Print("Collecting Animations..."); Rbx2Source.IncrementStack(); Action <string, Asset> collectAnimation = (animName, animAsset) => { if (!compileAnims.ContainsKey(animName)) { Rbx2Source.Print("Collected animation {0} with id {1}", animName, animAsset.Id); compileAnims.Add(animName, animAsset); } }; foreach (string animName in animIds.Keys) { var animId = animIds[animName]; var animAsset = animId.GetAsset(); var import = animAsset.OpenAsModel(); if (animId.AnimationType == AnimationType.R15AnimFolder) { Folder r15Anim = import.FindFirstChild <Folder>("R15Anim"); if (r15Anim != null) { foreach (Instance animDef in r15Anim.GetChildren()) { if (animDef.Name == "idle") { var anims = animDef.GetChildrenOfType <Animation>(); if (anims.Length == 2) { var getLookAnim = anims.OrderBy((anim) => { var weight = anim.FindFirstChild <NumberValue>("Weight"); if (weight != null) { return(weight.Value); } return(0.0); }); var lookAnim = getLookAnim.First(); lookAnim.Destroy(); Asset lookAsset = Asset.GetByAssetId(lookAnim.AnimationId); collectAnimation("Idle2", lookAsset); } } Animation compileAnim = animDef.FindFirstChildOfClass <Animation>(); if (compileAnim != null) { Asset compileAsset = Asset.GetByAssetId(compileAnim.AnimationId); string compileName = animName; if (animDef.Name == "pose") { compileName = "Pose"; } collectAnimation(compileName, compileAsset); } } } } else { collectAnimation(animName, animAsset); } } Rbx2Source.DecrementStack(); } else { Rbx2Source.Print("No animations found :("); } if (compileAnims.Count > 0) { Rbx2Source.Print("Assembling Animations..."); Rbx2Source.IncrementStack(); foreach (string animName in compileAnims.Keys) { Rbx2Source.Print("Building Animation {0}...", animName); Asset animAsset = compileAnims[animName]; var import = animAsset.OpenAsModel(); var sequence = import.FindFirstChildOfClass <KeyframeSequence>(); sequence.Name = animName; var avatarTypeRef = new StringValue() { Value = $"{avatarType}", Name = "AvatarType", Parent = sequence }; string animation = AnimationBuilder.Assemble(sequence, writer.Skeleton[0].Bones); string animPath = Path.Combine(anim8Dir, animName + ".smd"); FileUtility.WriteFile(animPath, animation); } Rbx2Source.DecrementStack(); } Rbx2Source.MarkTaskCompleted("BuildAnimations"); /////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion Rbx2Source.PrintHeader("BUILDING CHARACTER TEXTURES"); #region Build Character Textures /////////////////////////////////////////////////////////////////////////////////////////////////////// var materials = writer.Materials; TextureBindings textures; if (DEBUG_RAPID_ASSEMBLY) { textures = new TextureBindings(); materials.Clear(); } else { TextureCompositor texCompositor = assembler.ComposeTextureMap(characterAssets, avatar.BodyColors); textures = assembler.BindTextures(texCompositor, materials); } var images = textures.Images; textures.MaterialDirectory = compileDir; foreach (string imageName in images.Keys) { Rbx2Source.Print("Writing Image {0}.png", imageName); Image image = images[imageName]; string imagePath = Path.Combine(texturesDir, imageName + ".png"); try { image.Save(imagePath, ImageFormat.Png); } catch { Rbx2Source.Print("IMAGE {0}.png FAILED TO SAVE!", imageName); } FileUtility.LockFile(imagePath); } CompositData.FreeAllocatedTextures(); Rbx2Source.MarkTaskCompleted("BuildTextures"); /////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion Rbx2Source.PrintHeader("WRITING MATERIAL FILES"); #region Write Material Files /////////////////////////////////////////////////////////////////////////////////////////////////////// var matLinks = textures.MatLinks; foreach (string mtlName in matLinks.Keys) { Rbx2Source.Print("Building VMT {0}.vmt", mtlName); string targetVtf = matLinks[mtlName]; string vmtPath = Path.Combine(materialsDir, mtlName + ".vmt"); ValveMaterial mtl = materials[mtlName]; mtl.SetVmtField("basetexture", "models/" + compileDir + "/" + targetVtf); mtl.WriteVmtFile(vmtPath); } Rbx2Source.MarkTaskCompleted("BuildMaterials"); /////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion Rbx2Source.PrintHeader("WRITING COMPILER SCRIPT"); #region Write Compiler Script /////////////////////////////////////////////////////////////////////////////////////////////////////// string modelName = compileDir + ".mdl"; QuakeCWriter qc = new QuakeCWriter(); qc.Add("body", userName, "CharacterModel.smd"); qc.Add("modelname", modelName); qc.Add("upaxis", "y"); // Compute the floor level of the avatar. Folder assembly = characterAssets.FindFirstChild <Folder>("ASSEMBLY"); if (assembly != null) { float floor = ComputeFloorLevel(assembly); string origin = "0 " + floor.ToInvariantString() + " 0"; qc.Add("origin", origin); } qc.Add("cdmaterials", "models/" + compileDir); qc.Add("surfaceprop", "flesh"); qc.Add("include", "CollisionJoints.qc"); QuakeCItem refAnim = qc.Add("sequence", "reference", "ReferencePos.smd"); refAnim.AddSubItem("fps", 1); refAnim.AddSubItem("loop"); foreach (string animName in compileAnims.Keys) { QuakeCItem sequence = qc.Add("sequence", animName.ToLowerInvariant(), "Animations/" + animName + ".smd"); sequence.AddSubItem("fps", AnimationBuilder.FrameRate); if (avatarType == AvatarType.R6) { sequence.AddSubItem("delta"); } sequence.AddSubItem("loop"); } string qcFile = qc.ToString(); string qcPath = Path.Combine(modelDir, "Compile.qc"); FileUtility.WriteFile(qcPath, qcFile); Rbx2Source.MarkTaskCompleted("BuildCompilerScript"); /////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion AssemblerData data = new AssemblerData() { ModelData = writer, ModelName = modelName, TextureData = textures, CompilerScript = qcPath, RootDirectory = userBin, CompileDirectory = compileDir, TextureDirectory = texturesDir, MaterialDirectory = materialsDir, }; return(data); }
public TextureBindings BindTextures(TextureCompositor compositor, Dictionary <string, ValveMaterial> materials) { Contract.Requires(compositor != null && materials != null); TextureBindings textures = new TextureBindings(); Bitmap core = compositor.BakeTextureMap(); Rbx2Source.SetDebugImage(core); Bitmap head = TextureCompositor.CropBitmap(core, RECT_HEAD); textures.BindTexture("Head", head); Bitmap body = TextureCompositor.CropBitmap(core, RECT_BODY); Folder characterAssets = compositor.CharacterAssets; Rbx2Source.Print("Processing Package Textures..."); Rbx2Source.IncrementStack(); // Collect CharacterMeshes var packagedLimbs = characterAssets .GetChildrenOfType <CharacterMesh>() .ToDictionary(mesh => mesh.BodyPart); // Compose the textures that will be used var limbOverlays = new Dictionary <BodyPart, long>(); var limbBitmaps = new Dictionary <long, Bitmap>() { { 0, body } }; foreach (BodyPart limb in LimbMatcher.Keys) { // Head is already textured, ignore it. if (limb == BodyPart.Head) { continue; } // Is there a CharacterMesh for this limb? if (packagedLimbs.ContainsKey(limb)) { // Check the CharacterMesh textures. CharacterMesh mesh = packagedLimbs[limb]; if (mesh.OverlayTextureId > 0) { // Use the overlay texture for this limb. long overlayId = mesh.OverlayTextureId; limbOverlays.Add(limb, overlayId); // Compose this overlay texture with the body texture if it doesn't exist yet. if (!limbBitmaps.ContainsKey(overlayId)) { Asset overlayAsset = Asset.Get(overlayId); TextureCompositor overlayCompositor = new TextureCompositor(AvatarType.R6, RECT_FULL); overlayCompositor.SetContext("Overlay Texture " + overlayId); overlayCompositor.AppendTexture(overlayAsset, RECT_BODY, 1); overlayCompositor.AppendTexture(body, RECT_BODY); Bitmap overlayTex = overlayCompositor.BakeTextureMap(RECT_BODY); limbBitmaps.Add(overlayId, overlayTex); } continue; } else if (mesh.BaseTextureId > 0) { // Use the base texture for this limb. long baseId = mesh.BaseTextureId; limbOverlays.Add(limb, baseId); // Compose the base texture if it doesn't exist yet. if (!limbBitmaps.ContainsKey(baseId)) { Asset baseAsset = Asset.Get(baseId); TextureCompositor baseCompositor = new TextureCompositor(AvatarType.R6, RECT_FULL); baseCompositor.SetContext("Base Texture " + baseId); baseCompositor.AppendTexture(baseAsset, RECT_BODY); Bitmap baseTex = baseCompositor.BakeTextureMap(RECT_BODY); limbBitmaps.Add(baseId, baseTex); } continue; } } // If no continue statement is reached, fallback to using the body texture. // This occurs if the limb has no package, or the package limb has no textures. limbOverlays.Add(limb, 0); } // Add the images into the texture assembly. foreach (long id in limbBitmaps.Keys) { Bitmap bitmap = limbBitmaps[id]; string matName = GetBodyMatName(id); textures.BindTexture(matName, bitmap, false); } // Link the limbs to their textures. foreach (BodyPart limb in limbOverlays.Keys) { long id = limbOverlays[limb]; string matName = GetBodyMatName(id); string limbName = Rbx2Source.GetEnumName(limb); textures.BindTextureAlias(limbName, matName); } // Handle the rest of the materials foreach (string matName in materials.Keys) { if (!textures.MatLinks.ContainsKey(matName)) { ValveMaterial material = materials[matName]; Asset texture = material.TextureAsset; TextureCompositor matComp = new TextureCompositor(AvatarType.R6, RECT_ITEM); matComp.SetContext("Accessory Texture " + matName); matComp.AppendTexture(texture, RECT_ITEM); Bitmap bitmap = matComp.BakeTextureMap(); textures.BindTexture(matName, bitmap); } } Rbx2Source.DecrementStack(); return(textures); }
public StudioMdlWriter AssembleModel(Folder characterAssets, AvatarScale scale) { StudioMdlWriter meshBuilder = new StudioMdlWriter(); // Build Character Folder import = RBXM.LoadFromAsset(R15AssemblyAsset); Folder assembly = import.FindFirstChild <Folder>("ASSEMBLY"); assembly.Parent = characterAssets; Part head = assembly.FindFirstChild <Part>("Head"); Vector3 avatarScale = GetAvatarScale(scale); foreach (Instance asset in characterAssets.GetChildren()) { if (asset.IsA("Part")) { Part existing = assembly.FindFirstChild <Part>(asset.Name); if (existing != null) { existing.Destroy(); } asset.Parent = assembly; } else if (asset.IsA("Accoutrement")) { PrepareAccessory(asset, assembly); } else if (asset.IsA("DataModelMesh")) { OverwriteHead(asset, head); } } // Avatar Scaling foreach (Part part in assembly.GetChildrenOfClass <Part>()) { Limb limb = GetLimb(part); if (limb != Limb.Unknown) { part.Size *= avatarScale; foreach (Attachment attachment in part.GetChildrenOfClass <Attachment>()) { attachment.CFrame = CFrame.Scale(attachment.CFrame, avatarScale); } } } Part torso = assembly.FindFirstChild <Part>("LowerTorso"); torso.CFrame = new CFrame(); BoneKeyframe keyframe = AssembleBones(meshBuilder, torso); List <Bone> bones = keyframe.Bones; // Build File Data. Rbx2Source.Print("Building Geometry..."); Rbx2Source.IncrementStack(); foreach (Bone bone in bones) { BuildAvatarGeometry(meshBuilder, bone); } Rbx2Source.DecrementStack(); return(meshBuilder); }
public Bitmap BakeTextureMap() { var bitmap = new Bitmap(canvas.Width, canvas.Height); layers.Sort(); composed = 0; Rbx2Source.Print("Composing " + context + "..."); Rbx2Source.IncrementStack(); foreach (CompositData composit in layers) { var buffer = Graphics.FromImage(bitmap); var drawFlags = composit.DrawFlags; var canvas = composit.Rect; if (drawFlags.HasFlag(DrawFlags.Rect)) { if (drawFlags.HasFlag(DrawFlags.Color)) { composit.UseBrush(brush => buffer.FillRectangle(brush, canvas)); } else if (drawFlags.HasFlag(DrawFlags.Texture)) { Bitmap image = composit.GetTextureBitmap(); if (composit.FlipMode > 0) { image.RotateFlip(composit.FlipMode); } buffer.DrawImage(image, canvas); } } else if (drawFlags.HasFlag(DrawFlags.Guide)) { Mesh guide = composit.Guide; for (int face = 0; face < guide.NumFaces; face++) { Vertex[] verts = composit.GetGuideVerts(face); Point offset = canvas.Location; Point[] poly = verts .Select(vert => vert.ToPoint(canvas, offset)) .ToArray(); if (drawFlags.HasFlag(DrawFlags.Color)) { composit.UseBrush(brush => buffer.FillPolygon(brush, poly)); } else if (drawFlags.HasFlag(DrawFlags.Texture)) { Bitmap texture = composit.GetTextureBitmap(); Rectangle bbox = GetBoundingBox(poly); Point origin = bbox.Location; Bitmap drawLayer = new Bitmap(bbox.Width, bbox.Height); Point[] uv = verts .Select(vert => vert.ToUV(texture)) .ToArray(); int origin_X = origin.X, origin_Y = origin.Y; for (int x = bbox.Left; x < bbox.Right; x++) { for (int y = bbox.Top; y < bbox.Bottom; y++) { var pixel = new Point(x, y); var bcPoint = new BarycentricPoint(pixel, poly); if (bcPoint.InBounds()) { var uvPixel = bcPoint.ToCartesian(uv); Color color = texture.GetPixel(uvPixel.X, uvPixel.Y); drawLayer.SetPixel(x - origin_X, y - origin_Y, color); } } } buffer.DrawImage(drawLayer, origin); drawLayer.Dispose(); } } } Rbx2Source.Print("{0}/{1} layers composed...", ++composed, layers.Count); if (layers.Count > 2) { Rbx2Source.SetDebugImage(bitmap); } buffer.Dispose(); } Rbx2Source.Print("Done!"); Rbx2Source.DecrementStack(); return(bitmap); }
public StudioMdlWriter AssembleModel(Folder characterAssets, AvatarScale scale, bool collisionModel = false) { Contract.Requires(characterAssets != null); StudioMdlWriter meshBuilder = new StudioMdlWriter(); // Build Character var import = R15AssemblyAsset.OpenAsModel(); Folder assembly = import.FindFirstChild <Folder>("ASSEMBLY"); BasePart head = assembly.FindFirstChild <BasePart>("Head"); assembly.Parent = characterAssets; foreach (Instance asset in characterAssets.GetChildren()) { if (asset is BasePart) { BasePart existing = assembly.FindFirstChild <BasePart>(asset.Name); if (existing != null) { existing.Destroy(); } asset.Parent = assembly; } else if (asset is Folder && asset.Name == "R15ArtistIntent") { foreach (BasePart child in asset.GetChildrenOfType <BasePart>()) { BasePart existing = assembly.FindFirstChild <BasePart>(child.Name); if (existing != null) { existing.Destroy(); } child.Parent = assembly; } } else if (asset is Accoutrement && !collisionModel) { PrepareAccessory(asset, assembly); } else if (asset is DataModelMesh) { OverwriteHead(asset as DataModelMesh, head); } } // Apply limb scaling var parts = assembly.GetChildrenOfType <BasePart>(); var attachMap = new Dictionary <string, Attachment>(); var avatarParts = parts.Where((part) => { var limb = GetLimb(part); return(limb.HasValue); }); var accessoryParts = parts.Except(avatarParts); foreach (BasePart avatarPart in avatarParts) { Vector3 limbScale = ComputeLimbScale(scale, avatarPart); foreach (Attachment att in avatarPart.GetChildrenOfType <Attachment>()) { attachMap[att.Name] = att; } ScalePart(avatarPart, limbScale); } // Apply accessory scaling foreach (BasePart handle in accessoryParts) { Attachment handleAtt = handle.FindFirstChildOfClass <Attachment>(); if (handleAtt != null) { string attName = handleAtt.Name; if (attachMap.ContainsKey(attName)) { Attachment avatarAtt = attachMap[attName]; BasePart avatarPart = avatarAtt.Parent as BasePart; Vector3 accessoryScale = ComputeAccessoryScale(scale, avatarPart, handle); ScalePart(handle, accessoryScale); } } } BasePart torso = assembly.FindFirstChild <BasePart>("LowerTorso"); torso.CFrame = new CFrame(); BoneKeyframe keyframe = AssembleBones(meshBuilder, torso); List <StudioBone> bones = keyframe.Bones; // Build File Data. Rbx2Source.Print("Building Geometry..."); Rbx2Source.IncrementStack(); foreach (StudioBone bone in bones) { BuildAvatarGeometry(meshBuilder, bone); } Rbx2Source.DecrementStack(); return(meshBuilder); }
public static async Task <string> Compile(GameInfo gameInfo, AssemblerData data) { Contract.Requires(gameInfo != null && data != null); if (!gameInfo.ReadyToUse) { throw new Exception("This gameinfo.txt file isn't ready to use!"); } Rbx2Source.PrintHeader("COMPILING MODEL"); #region Compile Model ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// string studioMdlPath = gameInfo.StudioMdlPath; ThirdPartyUtility studioMdl = new ThirdPartyUtility(studioMdlPath); studioMdl.AddParameter("game", gameInfo.GameDirectory); studioMdl.AddParameter("nop4"); studioMdl.AddFile(data.CompilerScript); await studioMdl.RunWithOutput(); Rbx2Source.MarkTaskCompleted("CompileModel"); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion Rbx2Source.PrintHeader("COMPILING TEXTURES"); #region Compile Textures ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (!File.Exists(vtfCompilerPath)) { byte[] vtfZip = ResourceUtility.GetResource("VTFCmd.zip"); using (MemoryStream extract = new MemoryStream(vtfZip)) using (ZipArchive archive = new ZipArchive(extract)) { foreach (ZipArchiveEntry entry in archive.Entries) { string name = entry.Name; string path = Path.Combine(utilityDir, name); using (Stream stream = entry.Open()) { byte[] file = FileUtility.ReadFullStream(stream); FileUtility.WriteFile(path, file); } } } } string pngWildcard = Path.Combine(data.TextureDirectory, "*.png"); vtfCompiler = new ThirdPartyUtility(vtfCompilerPath); vtfCompiler.AddParameter("resize"); vtfCompiler.AddParameter("folder", pngWildcard); vtfCompiler.AddParameter("format", "ABGR8888"); // No compression? THIS IS FINE vtfCompiler.AddParameter("output", data.MaterialDirectory); await vtfCompiler.RunWithOutput(); Rbx2Source.MarkTaskCompleted("CompileTextures"); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion Rbx2Source.PrintHeader("MOVING TEXTURES"); #region Move Textures ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// string gameDirectory = gameInfo.GameDirectory; string modelPath = Path.Combine(gameDirectory, "models", data.ModelName); string materialPath = Path.Combine(gameDirectory, "materials", "models", data.CompileDirectory); FileUtility.InitiateEmptyDirectories(materialPath); foreach (string filePath in Directory.GetFiles(data.MaterialDirectory)) { FileInfo info = new FileInfo(filePath); string fileName = info.Name; Rbx2Source.Print("Moving File: {0}", fileName); Rbx2Source.IncrementStack(); Rbx2Source.Print("From: {0}", filePath); string destFilePath = Path.Combine(materialPath, fileName); info.CopyTo(destFilePath); Rbx2Source.Print("To: {0}", destFilePath); Rbx2Source.DecrementStack(); } Rbx2Source.MarkTaskCompleted("MoveTextures"); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endregion return(modelPath); }
public Bitmap BakeTextureMap() { Bitmap bitmap = new Bitmap(canvas.Width, canvas.Height); layers.Sort(); composed = 0; Rbx2Source.Print("Composing " + context + "..."); Rbx2Source.IncrementStack(); foreach (CompositData composit in layers) { Graphics buffer = Graphics.FromImage(bitmap); DrawMode drawMode = composit.DrawMode; DrawType drawType = composit.DrawType; Rectangle compositCanvas = composit.Rect; if (drawMode == DrawMode.Rect) { if (drawType == DrawType.Color) { using (Brush brush = new SolidBrush(composit.DrawColor)) buffer.FillRectangle(brush, compositCanvas); } else if (drawType == DrawType.Texture) { Bitmap image = composit.GetTextureBitmap(); if (composit.FlipMode > 0) { image.RotateFlip(composit.FlipMode); } buffer.DrawImage(image, compositCanvas); } } else if (drawMode == DrawMode.Guide) { Mesh guide = composit.Guide; for (int face = 0; face < guide.FaceCount; face++) { Vertex[] verts = composit.GetGuideVerts(face); Point offset = compositCanvas.Location; Point vert_a = CompositUtil.VertexToPoint(verts[0], compositCanvas, offset); Point vert_b = CompositUtil.VertexToPoint(verts[1], compositCanvas, offset); Point vert_c = CompositUtil.VertexToPoint(verts[2], compositCanvas, offset); Point[] polygon = new Point[3] { vert_a, vert_b, vert_c }; if (drawType == DrawType.Color) { using (Brush brush = new SolidBrush(composit.DrawColor)) buffer.FillPolygon(brush, polygon); } else if (drawType == DrawType.Texture) { Bitmap texture = composit.GetTextureBitmap(); Rectangle bbox = CompositUtil.GetBoundingBox(vert_a, vert_b, vert_c); Point origin = bbox.Location; int width = bbox.Width; int height = bbox.Height; Bitmap drawLayer = new Bitmap(width, height); Point uv_a = CompositUtil.VertexToUV(verts[0], texture); Point uv_b = CompositUtil.VertexToUV(verts[1], texture); Point uv_c = CompositUtil.VertexToUV(verts[2], texture); for (int x = bbox.Left; x < bbox.Right; x++) { for (int y = bbox.Top; y < bbox.Bottom; y++) { Point pixel = new Point(x, y); BarycentricPoint bcPixel = CompositUtil.ToBarycentric(pixel, vert_a, vert_b, vert_c); if (CompositUtil.InTriangle(bcPixel)) { Point uvPixel = CompositUtil.ToCartesian(bcPixel, uv_a, uv_b, uv_c); Color color = texture.GetPixel(uvPixel.X, uvPixel.Y); drawLayer.SetPixel(x - origin.X, y - origin.Y, color); } } } buffer.DrawImage(drawLayer, origin); drawLayer.Dispose(); } } } Rbx2Source.Print("{0}/{1} layers composed...", ++composed, layers.Count); if (layers.Count > 2) { Rbx2Source.SetDebugImage(bitmap); } buffer.Dispose(); } Rbx2Source.Print("Done!"); Rbx2Source.DecrementStack(); return(bitmap); }