public void ShouldWriteCustomTranslation()
        {
            var texture = new CompositeTexture(
                "Name",
                10,
                10,
                Patches: ImmutableArray.Create(
                    new Patch(
                        "Name2",
                        0,
                        0,
                        Translation: new Translation.Custom("SomeString"))));

            var actual = GetText(texture);

            var expected = Assemble(
                "Texture Name, 10, 10",
                "{",
                "\tPatch Name2, 0, 0",
                "\t{",
                "\t\tTranslation \"SomeString\"",
                "\t}",
                "}");

            actual.Should().Be(expected);
        }
        public void ShouldWriteDesaturateTranslation()
        {
            var texture = new CompositeTexture(
                "Name",
                10,
                10,
                Patches: ImmutableArray.Create(
                    new Patch(
                        "Name2",
                        0,
                        0,
                        Translation: new Translation.Desaturate(20))));

            var actual = GetText(texture);

            var expected = Assemble(
                "Texture Name, 10, 10",
                "{",
                "\tPatch Name2, 0, 0",
                "\t{",
                "\t\tTranslation Desaturate, 20",
                "\t}",
                "}");

            actual.Should().Be(expected);
        }
        public void ShouldWriteExampleTexture2()
        {
            var texture = new CompositeTexture(
                "SWEXPLUP",
                512,
                512,
                XScale: 4,
                YScale: 4,
                Patches: ImmutableArray.Create(
                    new Patch(
                        "AG_512_2",
                        0,
                        0),
                    new Patch(
                        "MSW1_UP",
                        64,
                        288,
                        Style: RenderStyle.CopyAlpha)));

            var actual = GetText(texture);

            var expected = Assemble(
                "Texture SWEXPLUP, 512, 512",
                "{",
                "\tXScale 4.0",
                "\tYScale 4.0",
                "\tPatch AG_512_2, 0, 0",
                "\tPatch MSW1_UP, 64, 288",
                "\t{",
                "\t\tStyle CopyAlpha",
                "\t}",
                "}");

            actual.Should().Be(expected);
        }
Example #4
0
 public FlaskTextureSource(ICoreClientAPI capi, ItemStack forContents, CompositeTexture contentTexture, Block flask)
 {
     this.capi           = capi;
     this.forContents    = forContents;
     this.contentTexture = contentTexture;
     this.corkTextPos    = capi.BlockTextureAtlas.GetPosition(flask, "topper");
     this.blockTextPos   = capi.BlockTextureAtlas.GetPosition(flask, "glass");
     this.bracingTextPos = capi.BlockTextureAtlas.GetPosition(flask, "bracing");
 }
        private static string GetText(CompositeTexture compositeTexture)
        {
            using var ms = new MemoryStream();
            using (var writer = new StreamWriter(ms, Encoding.ASCII, leaveOpen: true))
            {
                TexturesWriter.Write(compositeTexture, writer);
            }

            ms.Position      = 0;
            using var reader = new StreamReader(ms);
            return(reader.ReadToEnd());
        }
        public override void OnLoaded(ICoreAPI api)
        {
            base.OnLoaded(api);

            if (api.Side == EnumAppSide.Client)
            {
                if (Textures == null || !Textures.TryGetValue("specialSecondTexture", out grassTex))
                {
                    grassTex = Textures?.First().Value;
                }
            }
        }
Example #7
0
        public virtual TextureAtlasPosition this[string textureCode]
        {
            get
            {
                CompositeTexture cpt = null;
                if (extraTexturesByTextureName?.TryGetValue(textureCode, out cpt) == true)
                {
                    return(capi.EntityTextureAtlas.Positions[cpt.Baked.TextureSubId]);
                }

                return(defaultTexSource[textureCode]);
            }
        }
Example #8
0
        public override TextureAtlasPosition this[string textureCode]
        {
            get
            {
                CompositeTexture cpt = null;
                if (extraTexturesByTextureName != null && extraTexturesByTextureName.TryGetValue(textureCode, out cpt) == true)
                {
                    return(capi.EntityTextureAtlas.Positions[cpt.Baked.TextureSubId]);
                }

                return(skinTexPos);
            }
        }
        private void loadTexture(Shape entityShape, string code, AssetLocation location, int textureWidth, int textureHeight, string shapePathForLogging)
        {
            ICoreClientAPI api = entity.World.Api as ICoreClientAPI;

            CompositeTexture ctex = new CompositeTexture()
            {
                Base = location
            };

            entityShape.TextureSizes[code] = new int[] { textureWidth, textureHeight };

            AssetLocation shapeTexloc = location;

            // Weird backreference to the shaperenderer. Should be refactored.
            var texturesByLoc  = (entity as EntityAgent).extraTextureByLocation;
            var texturesByName = (entity as EntityAgent).extraTexturesByTextureName;

            BakedCompositeTexture bakedCtex;


            if (!texturesByLoc.TryGetValue(shapeTexloc, out bakedCtex))
            {
                int textureSubId = 0;
                TextureAtlasPosition texpos;

                IAsset texAsset = api.Assets.TryGet(location.Clone().WithPathPrefixOnce("textures/").WithPathAppendixOnce(".png"));
                if (texAsset != null)
                {
                    BitmapRef bmp = texAsset.ToBitmap(api);
                    api.EntityTextureAtlas.InsertTexture(bmp, out textureSubId, out texpos, -1);
                }
                else
                {
                    api.World.Logger.Warning("Skin part shape {0} defined texture {1}, no such texture found.", shapePathForLogging, location);
                }

                ctex.Baked = new BakedCompositeTexture()
                {
                    BakedName = location, TextureSubId = textureSubId
                };

                texturesByName[code]       = ctex;
                texturesByLoc[shapeTexloc] = ctex.Baked;
            }
            else
            {
                ctex.Baked           = bakedCtex;
                texturesByName[code] = ctex;
            }
        }
Example #10
0
        public override int GetRandomColor(ICoreClientAPI capi, BlockPos pos, BlockFacing facing)
        {
            BELantern be = capi.World.BlockAccessor.GetBlockEntity(pos) as BELantern;

            if (be != null)
            {
                CompositeTexture tex = null;
                if (Textures.TryGetValue(be.material, out tex))
                {
                    return(capi.BlockTextureAtlas.GetRandomColor(tex.Baked.TextureSubId));
                }
            }

            return(base.GetRandomColor(capi, pos, facing));
        }
        public override void OnJsonTesselation(ref MeshData sourceMesh, ref int[] lightRgbsByCorner, BlockPos pos, Block[] chunkExtBlocks, int extIndex3d)
        {
            Block upBlock = chunkExtBlocks[extIndex3d + TileSideEnum.MoveIndex[TileSideEnum.Up]];

            if (upBlock is BlockFence)
            {
                int var = (GameMath.MurmurHash3Mod(pos.X, pos.Y, pos.Z, 8) + 1);

                MeshData mesh;
                if (!continousFenceMeches.TryGetValue(cntCode + var, out mesh))
                {
                    AssetLocation loc = Shape.Base.Clone();
                    loc.Path = loc.Path.Replace("-top", "");
                    loc.WithPathAppendixOnce(".json");
                    loc.WithPathPrefixOnce("shapes/");
                    Shape shape = capi.Assets.TryGet(loc).ToObject <Shape>();

                    CompositeTexture ct = Textures["wall"];
                    int prevSubid       = ct.Baked.TextureSubId;
                    ct.Baked.TextureSubId = ct.Baked.BakedVariants[GameMath.MurmurHash3Mod(pos.X, pos.Y, pos.Z, ct.Alternates.Length)].TextureSubId;

                    capi.Tesselator.TesselateShape(this, shape, out mesh, new Vec3f(Shape.rotateX, Shape.rotateY, Shape.rotateZ), Shape.QuantityElements, Shape.SelectiveElements);

                    ct.Baked.TextureSubId = prevSubid;

                    continousFenceMeches[cntCode] = mesh;
                }

                sourceMesh = mesh;
            }


            // Todo: make this work

            /*            int nBlockId = chunkExtIds[extIndex3d + TileSideEnum.MoveIndex[TileSideEnum.Up]];
             *          Block upblock = api.World.Blocks[nBlockId];
             *
             *          if (upblock.snowLevel >= 1 && snowLayerBlock != null)
             *          {
             *              sourceMesh = sourceMesh.Clone();
             *              sourceMesh.AddMeshData(capi.TesselatorManager.GetDefaultBlockMesh(snowLayerBlock));
             *              return;
             *          }*/

            return;  // no windwave for solid fences!

            //base.OnJsonTesselation(ref sourceMesh, ref lightRgbsByCorner, pos, chunkExtIds, chunkLightExt, extIndex3d);
        }
        public override int GetRandomColor(ICoreClientAPI capi, BlockPos pos, BlockFacing facing)
        {
            BlockEntityGenericTypedContainer be = capi.World.BlockAccessor.GetBlockEntity(pos) as BlockEntityGenericTypedContainer;

            if (be != null)
            {
                CompositeTexture tex = null;
                if (!Textures.TryGetValue(be.type + "-lid", out tex))
                {
                    Textures.TryGetValue(be.type + "-top", out tex);
                }
                return(capi.BlockTextureAtlas.GetRandomPixel(tex?.Baked == null ? 0 : tex.Baked.TextureSubId));
            }

            return(base.GetRandomColor(capi, pos, facing));
        }
Example #13
0
        public static void Write(CompositeTexture texture, StreamWriter writer)
        {
            var output = new WriterUtil();

            var optional = texture.Optional ? "optional " : "";

            output = output
                     .Line($"{texture.Namespace} {optional}{texture.Name}, {texture.Width}, {texture.Height}")
                     .OpenBrace()
                     .OptionalLine("XScale", texture.XScale, 1)
                     .OptionalLine("YScale", texture.YScale, 1)
                     .OptionalLine(nameof(texture.Offset), texture.Offset, new TextureOffset(), offset => $"{offset.Horizontal}, {offset.Vertical}")
                     .Flag(nameof(texture.WorldPanning), texture.WorldPanning)
                     .Flag(nameof(texture.NoDecals), texture.NoDecals);

            foreach (var patch in texture.Patches)
            {
        private void fullnessMeterDraw(Context ctx, ImageSurface surface, ElementBounds currentBounds)
        {
            ItemSlot liquidSlot = Inventory[1]; // Water ID Slot

            if (liquidSlot.Empty)
            {
                return;
            }

            BlockEntitySingleSink besink = capi.World.BlockAccessor.GetBlockEntity(BlockEntityPosition) as BlockEntitySingleSink;
            float itemsPerLitre          = 1f;
            int   capacity = besink.CapacityLitres;

            WaterTightContainableProps props = BlockLiquidContainerBase.GetInContainerProps(liquidSlot.Itemstack);

            if (props != null)
            {
                itemsPerLitre = props.ItemsPerLitre;
                capacity      = Math.Max(capacity, props.MaxStackSize);
            }

            float fullnessRelative = liquidSlot.StackSize / itemsPerLitre / capacity;


            double offY = (1 - fullnessRelative) * currentBounds.InnerHeight;

            ctx.Rectangle(0, offY, currentBounds.InnerWidth, currentBounds.InnerHeight - offY);
            //ctx.SetSourceRGBA(ravg/255.0, gavg / 255.0, bavg / 255.0, aavg / 255.0);
            //ctx.Fill();

            CompositeTexture tex = liquidSlot.Itemstack.Collectible.Attributes?["waterTightContainerProps"]?["texture"]?.AsObject <CompositeTexture>(null, liquidSlot.Itemstack.Collectible.Code.Domain);

            if (tex != null)
            {
                ctx.Save();
                Matrix m = ctx.Matrix;
                m.Scale(GuiElement.scaled(3), GuiElement.scaled(3));
                ctx.Matrix = m;

                AssetLocation loc = tex.Base.Clone().WithPathAppendixOnce(".png");
                GuiElement.fillWithPattern(capi, ctx, loc.Path, true, false);

                ctx.Restore();
            }
        }
Example #15
0
        public override void OnLoaded(ICoreAPI api)
        {
            base.OnLoaded(api);

            chunksize = api.World.BlockAccessor.ChunkSize;

            if (api is ICoreClientAPI)
            {
                Block fullCoverBlock = api.World.GetBlock(this.CodeWithParts("7"));
                mapColorTextureSubId = fullCoverBlock.Textures["specialSecondTexture"].Baked.TextureSubId;

                var soilBlock = api.World.GetBlock(new AssetLocation("soil-low-normal"));
                if (soilBlock.Textures == null || !soilBlock.Textures.TryGetValue("specialSecondTexture", out grassTex))
                {
                    grassTex = soilBlock.Textures?.First().Value;
                }
            }
        }
        public void Rebase(DynFoliageProperties props)
        {
            if (TexturesBasePath == null)
            {
                TexturesBasePath = props.TexturesBasePath;
            }
            if (Textures == null)
            {
                Textures = new Dictionary <string, CompositeTexture>();
                foreach (var val in props.Textures)
                {
                    Textures[val.Key] = val.Value.Clone();
                }
            }

            LeafParticlesTexture    = props.LeafParticlesTexture?.Clone();
            BlossomParticlesTexture = props.BlossomParticlesTexture?.Clone();
        }
Example #17
0
        // We need the tool item textures also in the block atlas
        public override void OnCollectTextures(ICoreAPI api, ITextureLocationDictionary textureDict)
        {
            base.OnCollectTextures(api, textureDict);

            for (int i = 0; i < api.World.Items.Count; i++)
            {
                Item item = api.World.Items[i];
                if (item.Tool == null && item.Attributes?["rackable"].AsBool() != true)
                {
                    continue;
                }

                ToolTextures tt = new ToolTextures();


                if (item.Shape != null)
                {
                    IAsset asset = api.Assets.TryGet(item.Shape.Base.Clone().WithPathPrefixOnce("shapes/").WithPathAppendixOnce(".json"));
                    if (asset != null)
                    {
                        Shape shape = asset.ToObject <Shape>();
                        foreach (var val in shape.Textures)
                        {
                            CompositeTexture ctex = new CompositeTexture(val.Value.Clone());
                            ctex.Bake(api.Assets);

                            textureDict.AddTextureLocation(new AssetLocationAndSource(ctex.Baked.BakedName, "Shape code " + item.Shape.Base));
                            tt.TextureSubIdsByCode[val.Key] = textureDict[new AssetLocationAndSource(ctex.Baked.BakedName)];
                        }
                    }
                }

                foreach (var val in item.Textures)
                {
                    val.Value.Bake(api.Assets);
                    textureDict.AddTextureLocation(new AssetLocationAndSource(val.Value.Baked.BakedName, "Item code " + item.Code));
                    tt.TextureSubIdsByCode[val.Key] = textureDict[new AssetLocationAndSource(val.Value.Baked.BakedName)];
                }



                ToolTextureSubIds(api)[item] = tt;
            }
        }
        public void ShouldWriteTextureOffset()
        {
            var texture = new CompositeTexture(
                "Name",
                10,
                10,
                Offset: new TextureOffset(5, 6),
                Patches: ImmutableArray <Patch> .Empty);

            var actual = GetText(texture);

            var expected = Assemble(
                "Texture Name, 10, 10",
                "{",
                "\tOffset 5, 6",
                "}");

            actual.Should().Be(expected);
        }
Example #19
0
        private void fullnessMeterDraw(Context ctx, ImageSurface surface, ElementBounds currentBounds)
        {
            ItemSlot liquidSlot = Inventory[6] as ItemSlot;

            if (liquidSlot.Empty)
            {
                return;
            }

            BlockEntityCauld becauld       = capi.World.BlockAccessor.GetBlockEntity(BlockEntityPosition) as BlockEntityCauld;
            float            itemsPerLitre = 1f;
            int capacity = becauld.capacityLitres;

            WaterTightContainableProps props = BlockLiquidContainerBase.GetContainableProps(liquidSlot.Itemstack);

            if (props != null)
            {
                itemsPerLitre = props.ItemsPerLitre;
                capacity      = Math.Max(capacity, props.MaxStackSize);
            }

            float fullnessRelative = liquidSlot.StackSize / itemsPerLitre / capacity;

            double offY = (1 - fullnessRelative) * currentBounds.InnerHeight;

            ctx.Rectangle(0, offY, currentBounds.InnerWidth, currentBounds.InnerHeight - offY);

            CompositeTexture tex = props?.Texture ?? liquidSlot.Itemstack.Collectible.Attributes?["inContainerTexture"].AsObject <CompositeTexture>(null, liquidSlot.Itemstack.Collectible.Code.Domain);

            if (tex != null)
            {
                ctx.Save();
                Matrix m = ctx.Matrix;
                m.Scale(GuiElement.scaled(3), GuiElement.scaled(3));
                ctx.Matrix = m;

                AssetLocation loc = tex.Base.Clone().WithPathAppendixOnce(".png");
                GuiElement.fillWithPattern(capi, ctx, loc, true, false, tex.Alpha);

                ctx.Restore();
            }
        }
        public void ShouldNotWritePatchParentsIfNoContent()
        {
            var texture = new CompositeTexture(
                "Name",
                10,
                10,
                Patches: ImmutableArray.Create(
                    new Patch(
                        "Name2",
                        0,
                        0)));

            var actual = GetText(texture);

            var expected = Assemble(
                "Texture Name, 10, 10",
                "{",
                "\tPatch Name2, 0, 0",
                "}");

            actual.Should().Be(expected);
        }
        public void ShouldWriteLadderTexture()
        {
            var texture = new CompositeTexture(
                "ALADDER2",
                72,
                256,
                Patches: ImmutableArray.Create(
                    new Patch("RW45_1", 0, 0, Rotate: PatchRotation.Rotate90),
                    new Patch("RW45_1", 0, 64, Rotate: PatchRotation.Rotate90),
                    new Patch("RW45_1", 0, 128, Rotate: PatchRotation.Rotate90),
                    new Patch("RW45_1", 0, 172, Rotate: PatchRotation.Rotate90)));

            var actual = GetText(texture);

            var expected = Assemble(
                "Texture ALADDER2, 72, 256",
                "{",
                "\tPatch RW45_1, 0, 0",
                "\t{",
                "\t\tRotate 90",
                "\t}",
                "\tPatch RW45_1, 0, 64",
                "\t{",
                "\t\tRotate 90",
                "\t}",
                "\tPatch RW45_1, 0, 128",
                "\t{",
                "\t\tRotate 90",
                "\t}",
                "\tPatch RW45_1, 0, 172",
                "\t{",
                "\t\tRotate 90",
                "\t}",
                "}");

            actual.Should().Be(expected);
        }
Example #22
0
        public void TesselateShape()
        {
            CompositeShape compositeShape = entity.Properties.Client.Shape;
            Shape          entityShape    = entity.Properties.Client.LoadedShape;

            if (entityShape == null)
            {
                return;
            }

            ShapeElement headElement = null;

            // Only for player entity for now
            if (entityShape.Elements != null && HeadControl)
            {
                headElement = FindHead(entityShape.Elements);
            }

            entityShape.ResolveAndLoadJoints(headElement);


            ITexPositionSource texSource = GetTextureSource();
            MeshData           meshdata;

            if (entity.Properties.Client.Shape.VoxelizeTexture)
            {
                int altTexNumber = entity.WatchedAttributes.GetInt("textureIndex", 0);

                TextureAtlasPosition pos = texSource["all"];
                CompositeTexture     tex = altTexNumber == 0 ? entity.Properties.Client.FirstTexture : entity.Properties.Client.FirstTexture.Alternates[altTexNumber - 1];
                meshdata = capi.Tesselator.VoxelizeTexture(tex, capi.EntityTextureAtlas.Size, pos);
                for (int i = 0; i < meshdata.xyz.Length; i += 3)
                {
                    meshdata.xyz[i]     -= 0.125f;
                    meshdata.xyz[i + 1] -= 0.5f;
                    meshdata.xyz[i + 2] += 0.125f / 2;
                }

                curAnimator = new BlendEntityAnimator(entity, new Animation[0], new ShapeElement[0], new Dictionary <int, AnimationJoint>());
            }
            else
            {
                string animDictkey = (entity.Code + entity.Properties.Client.Shape.Base.ToString());

                try
                {
                    capi.Tesselator.TesselateShapeWithJointIds("entity", entityShape, out meshdata, texSource, new Vec3f(), compositeShape.QuantityElements, compositeShape.SelectiveElements);
                } catch (Exception e)
                {
                    capi.World.Logger.Fatal("Failed tesselating entity {0} with id {1}. Entity will probably be invisible!. The teselator threw {2}", entity.Code, entity.EntityId, e);
                    curAnimator = new BlendEntityAnimator(entity, entityShape.Animations, entityShape.Elements, entityShape.JointsById, headElement);
                    return;
                }


                // We cache animations because they are cpu intensive to calculate
                if (AnimationsByShape.ContainsKey(animDictkey))
                {
                    entityShape.Animations = AnimationsByShape[animDictkey];
                }
                else
                {
                    for (int i = 0; entityShape.Animations != null && i < entityShape.Animations.Length; i++)
                    {
                        entityShape.Animations[i].GenerateAllFrames(entityShape.Elements, entityShape.JointsById);
                    }

                    AnimationsByShape[animDictkey] = entityShape.Animations;
                }

                curAnimator = new BlendEntityAnimator(entity, entityShape.Animations, entityShape.Elements, entityShape.JointsById, headElement);
            }

            meshdata.Rgba2 = null;

            if (meshRefOpaque != null)
            {
                capi.Render.DeleteMesh(meshRefOpaque);
                meshRefOpaque = null;
            }
            if (meshRefOit != null)
            {
                capi.Render.DeleteMesh(meshRefOit);
                meshRefOit = null;
            }

            MeshData opaqueMesh = meshdata.Clone().Clear();
            MeshData oitMesh    = meshdata.Clone().Clear();

            opaqueMesh.AddMeshData(meshdata, EnumChunkRenderPass.Opaque);
            oitMesh.AddMeshData(meshdata, EnumChunkRenderPass.Transparent);

            if (opaqueMesh.VerticesCount > 0)
            {
                meshRefOpaque = capi.Render.UploadMesh(opaqueMesh);
            }

            if (oitMesh.VerticesCount > 0)
            {
                meshRefOit = capi.Render.UploadMesh(oitMesh);
            }
        }
 public ContainerTextureSource(ICoreClientAPI capi, ItemStack forContents, CompositeTexture contentTexture)
 {
     this.capi           = capi;
     this.forContents    = forContents;
     this.contentTexture = contentTexture;
 }
Example #24
0
        public virtual void TesselateShape()
        {
            if (!loaded)
            {
                return;
            }

            shapeFresh = true;
            CompositeShape compositeShape = OverrideCompositeShape != null ? OverrideCompositeShape : entity.Properties.Client.Shape;

            Shape entityShape = OverrideEntityShape != null ? OverrideEntityShape : entity.Properties.Client.LoadedShapeForEntity;

            if (entityShape == null)
            {
                return;
            }

            OnTesselation?.Invoke(ref entityShape, compositeShape.Base.ToString());
            entity.OnTesselation(ref entityShape, compositeShape.Base.ToString());

            defaultTexSource = GetTextureSource();

            TyronThreadPool.QueueTask(() =>
            {
                MeshData meshdata;

                if (entity.Properties.Client.Shape.VoxelizeTexture)
                {
                    int altTexNumber = entity.WatchedAttributes.GetInt("textureIndex", 0);

                    TextureAtlasPosition pos      = defaultTexSource["all"];
                    CompositeTexture[] Alternates = entity.Properties.Client.FirstTexture.Alternates;

                    CompositeTexture tex = altTexNumber == 0 ? entity.Properties.Client.FirstTexture : Alternates[altTexNumber % Alternates.Length];
                    meshdata             = capi.Tesselator.VoxelizeTexture(tex, capi.EntityTextureAtlas.Size, pos);
                    for (int i = 0; i < meshdata.xyz.Length; i += 3)
                    {
                        meshdata.xyz[i]     -= 0.125f;
                        meshdata.xyz[i + 1] -= 0.5f;
                        meshdata.xyz[i + 2] += 0.125f / 2;
                    }
                }
                else
                {
                    try
                    {
                        TesselationMetaData meta = new TesselationMetaData()
                        {
                            quantityElements  = compositeShape.QuantityElements,
                            selectiveElements = compositeShape.SelectiveElements,
                            texSource         = this,
                            withJointIds      = true,
                            withDamageEffect  = true,
                            typeForLogging    = "entity"
                        };

                        capi.Tesselator.TesselateShape(meta, entityShape, out meshdata, new Vec3f(compositeShape.rotateX, compositeShape.rotateY, compositeShape.rotateZ));

                        meshdata.Translate(compositeShape.offsetX, compositeShape.offsetY, compositeShape.offsetZ);
                    }
                    catch (Exception e)
                    {
                        capi.World.Logger.Fatal("Failed tesselating entity {0} with id {1}. Entity will probably be invisible!. The teselator threw {2}", entity.Code, entity.EntityId, e);
                        return;
                    }
                }

                MeshData opaqueMesh = meshdata.Clone().Clear();
                MeshData oitMesh    = meshdata.Clone().Clear();
                opaqueMesh.AddMeshData(meshdata, EnumChunkRenderPass.Opaque);
                oitMesh.AddMeshData(meshdata, EnumChunkRenderPass.Transparent);

                capi.Event.EnqueueMainThreadTask(() =>
                {
                    if (meshRefOpaque != null)
                    {
                        meshRefOpaque.Dispose();
                        meshRefOpaque = null;
                    }
                    if (meshRefOit != null)
                    {
                        meshRefOit.Dispose();
                        meshRefOit = null;
                    }

                    if (capi.IsShuttingDown)
                    {
                        return;
                    }

                    if (opaqueMesh.VerticesCount > 0)
                    {
                        meshRefOpaque = capi.Render.UploadMesh(opaqueMesh);
                    }

                    if (oitMesh.VerticesCount > 0)
                    {
                        meshRefOit = capi.Render.UploadMesh(oitMesh);
                    }
                }, "uploadentitymesh");

                capi.TesselatorManager.ThreadDispose();
            });
        }
Example #25
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="code">Any unique Identifier</param>
        /// <param name="cshape"></param>
        /// <param name="entityShape"></param>
        /// <param name="shapePathForLogging"></param>
        /// <param name="disableElements"></param>
        /// <returns></returns>
        protected Shape addGearToShape(string code, CompositeShape cshape, Shape entityShape, string shapePathForLogging, string[] disableElements = null, Dictionary <string, AssetLocation> textureOverrides = null)
        {
            AssetLocation shapePath = shapePath = cshape.Base.CopyWithPath("shapes/" + cshape.Base.Path + ".json");

            if (disableElements != null)
            {
                foreach (var val in disableElements)
                {
                    entityShape.RemoveElementByName(val);
                }
            }

            IAsset asset = Api.Assets.TryGet(shapePath);

            if (asset == null)
            {
                Api.World.Logger.Warning("Compositshape {0} (code: {2}) defined but not found, was supposed to be at {1}. Part will be invisible.", cshape.Base, shapePath, code);
                return(null);
            }

            Shape armorShape;

            try
            {
                armorShape = asset.ToObject <Shape>();
            }
            catch (Exception e)
            {
                Api.World.Logger.Warning("Exception thrown when trying to load gear shape {0} (code: {2}) . Will be invisible. Exception: {1}", cshape.Base, e, code);
                return(null);
            }

            bool added = applyStepParents(null, armorShape.Elements, entityShape, code, cshape, shapePathForLogging);


            if (added && armorShape.Textures != null)
            {
                Dictionary <string, AssetLocation> newdict = new Dictionary <string, AssetLocation>();
                foreach (var val in armorShape.Textures)
                {
                    newdict[code + "-" + val.Key] = val.Value;
                }

                // Texture overrides
                if (textureOverrides != null)
                {
                    foreach (var val in textureOverrides)
                    {
                        newdict[code + "-" + val.Key] = val.Value;
                    }
                }

                armorShape.Textures = newdict;

                foreach (var val in armorShape.Textures)
                {
                    CompositeTexture ctex = new CompositeTexture()
                    {
                        Base = val.Value
                    };

                    entityShape.TextureSizes[val.Key] = new int[] { armorShape.TextureWidth, armorShape.TextureHeight };

                    AssetLocation armorTexLoc = val.Value;

                    // Weird backreference to the shaperenderer. Should be refactored.
                    var texturesByLoc  = extraTextureByLocation;
                    var texturesByName = extraTexturesByTextureName;

                    BakedCompositeTexture bakedCtex;

                    ICoreClientAPI capi = Api as ICoreClientAPI;

                    if (!texturesByLoc.TryGetValue(armorTexLoc, out bakedCtex))
                    {
                        int textureSubId = 0;
                        TextureAtlasPosition texpos;

                        IAsset texAsset = Api.Assets.TryGet(val.Value.Clone().WithPathPrefixOnce("textures/").WithPathAppendixOnce(".png"));
                        if (texAsset != null)
                        {
                            BitmapRef bmp = texAsset.ToBitmap(capi);
                            capi.EntityTextureAtlas.InsertTexture(bmp, out textureSubId, out texpos);
                        }
                        else
                        {
                            capi.World.Logger.Warning("Entity armor shape {0} defined texture {1}, not no such texture found.", shapePath, val.Value);
                        }

                        ctex.Baked = new BakedCompositeTexture()
                        {
                            BakedName = val.Value, TextureSubId = textureSubId
                        };

                        texturesByName[val.Key]    = ctex;
                        texturesByLoc[armorTexLoc] = ctex.Baked;
                    }
                    else
                    {
                        ctex.Baked = bakedCtex;
                        texturesByName[val.Key] = ctex;
                    }
                }

                foreach (var val in armorShape.TextureSizes)
                {
                    entityShape.TextureSizes[val.Key] = val.Value;
                }
            }

            return(entityShape);
        }
Example #26
0
        protected Shape addGearToShape(ItemSlot slot, Shape entityShape, string shapePathForLogging)
        {
            if (slot.Empty)
            {
                return(entityShape);
            }
            ItemStack  stack   = slot.Itemstack;
            JsonObject attrObj = stack.Collectible.Attributes;


            string[] disableElements = attrObj?["disableElements"]?.AsArray <string>(null);
            if (disableElements != null)
            {
                foreach (var val in disableElements)
                {
                    entityShape.RemoveElementByName(val);
                }
            }

            if (attrObj?["wearableAttachment"].Exists != true)
            {
                return(entityShape);
            }

            CompositeShape compArmorShape = !attrObj["attachShape"].Exists ? (stack.Class == EnumItemClass.Item ? stack.Item.Shape : stack.Block.Shape) : attrObj["attachShape"].AsObject <CompositeShape>(null, stack.Collectible.Code.Domain);

            AssetLocation shapePath = shapePath = compArmorShape.Base.CopyWithPath("shapes/" + compArmorShape.Base.Path + ".json");



            IAsset asset = Api.Assets.TryGet(shapePath);

            if (asset == null)
            {
                Api.World.Logger.Warning("Entity armor shape {0} defined in {1} {2} not found, was supposed to be at {3}. Armor piece will be invisible.", compArmorShape.Base, stack.Class, stack.Collectible.Code, shapePath);
                return(null);
            }

            Shape armorShape;

            try
            {
                armorShape = asset.ToObject <Shape>();
            }
            catch (Exception e)
            {
                Api.World.Logger.Warning("Exception thrown when trying to load entity armor shape {0} defined in {1} {2}. Armor piece will be invisible. Exception: {3}", compArmorShape.Base, slot.Itemstack.Class, slot.Itemstack.Collectible.Code, e);
                return(null);
            }

            bool added = false;

            foreach (var val in armorShape.Elements)
            {
                ShapeElement elem;

                if (val.StepParentName != null)
                {
                    elem = entityShape.GetElementByName(val.StepParentName, StringComparison.InvariantCultureIgnoreCase);
                    if (elem == null)
                    {
                        Api.World.Logger.Warning("Entity armor shape {0} defined in {1} {2} requires step parent element with name {3}, but no such element was found in shape {4}. Will not be visible.", compArmorShape.Base, slot.Itemstack.Class, slot.Itemstack.Collectible.Code, val.StepParentName, shapePathForLogging);
                        continue;
                    }
                }
                else
                {
                    Api.World.Logger.Warning("Entity armor shape element {0} in shape {1} defined in {2} {3} did not define a step parent element. Will not be visible.", val.Name, compArmorShape.Base, slot.Itemstack.Class, slot.Itemstack.Collectible.Code);
                    continue;
                }

                if (elem.Children == null)
                {
                    elem.Children = new ShapeElement[] { val };
                }
                else
                {
                    elem.Children = elem.Children.Append(val);
                }

                val.SetJointIdRecursive(elem.JointId);
                val.WalkRecursive((el) =>
                {
                    foreach (var face in el.Faces)
                    {
                        face.Value.Texture = "#" + stack.Collectible.Code + "-" + face.Value.Texture.TrimStart('#');
                    }
                });

                added = true;
            }

            if (added && armorShape.Textures != null)
            {
                Dictionary <string, AssetLocation> newdict = new Dictionary <string, AssetLocation>();
                foreach (var val in armorShape.Textures)
                {
                    newdict[stack.Collectible.Code + "-" + val.Key] = val.Value;
                }

                // Item overrides
                var collDict = stack.Class == EnumItemClass.Block ? stack.Block.Textures : stack.Item.Textures;
                foreach (var val in collDict)
                {
                    newdict[stack.Collectible.Code + "-" + val.Key] = val.Value.Base;
                }

                armorShape.Textures = newdict;

                foreach (var val in armorShape.Textures)
                {
                    CompositeTexture ctex = new CompositeTexture()
                    {
                        Base = val.Value
                    };

                    entityShape.TextureSizes[val.Key] = new int[] { armorShape.TextureWidth, armorShape.TextureHeight };

                    AssetLocation armorTexLoc = val.Value;

                    // Weird backreference to the shaperenderer. Should be refactored.
                    var texturesByLoc  = extraTextureByLocation;
                    var texturesByName = extraTexturesByTextureName;

                    BakedCompositeTexture bakedCtex;

                    ICoreClientAPI capi = Api as ICoreClientAPI;

                    if (!texturesByLoc.TryGetValue(armorTexLoc, out bakedCtex))
                    {
                        int textureSubId = 0;
                        TextureAtlasPosition texpos;

                        IAsset texAsset = Api.Assets.TryGet(val.Value.Clone().WithPathPrefixOnce("textures/").WithPathAppendixOnce(".png"));
                        if (texAsset != null)
                        {
                            BitmapRef bmp = texAsset.ToBitmap(capi);
                            capi.EntityTextureAtlas.InsertTextureCached(val.Value, bmp, out textureSubId, out texpos);
                        }
                        else
                        {
                            capi.World.Logger.Warning("Entity armor shape {0} defined texture {1}, no such texture found.", shapePath, val.Value);
                        }

                        ctex.Baked = new BakedCompositeTexture()
                        {
                            BakedName = val.Value, TextureSubId = textureSubId
                        };

                        texturesByName[val.Key]    = ctex;
                        texturesByLoc[armorTexLoc] = ctex.Baked;
                    }
                    else
                    {
                        ctex.Baked = bakedCtex;
                        texturesByName[val.Key] = ctex;
                    }
                }

                foreach (var val in armorShape.TextureSizes)
                {
                    entityShape.TextureSizes[val.Key] = val.Value;
                }
            }

            return(entityShape);
        }
Example #27
0
        public virtual void TesselateShape()
        {
            CompositeShape compositeShape = OverrideCompositeShape != null ? OverrideCompositeShape : entity.Properties.Client.Shape;
            Shape          entityShape    = OverrideEntityShape != null ? OverrideEntityShape : entity.Properties.Client.LoadedShape;

            if (entityShape == null)
            {
                return;
            }

            if (eagent != null)
            {
                entityShape = addGearToShape(entityShape, compositeShape.Base.ToString());
            }

            defaultTexSource = GetTextureSource();
            MeshData meshdata;

            if (entity.Properties.Client.Shape.VoxelizeTexture)
            {
                int altTexNumber = entity.WatchedAttributes.GetInt("textureIndex", 0);

                TextureAtlasPosition pos        = defaultTexSource["all"];
                CompositeTexture[]   Alternates = entity.Properties.Client.FirstTexture.Alternates;

                CompositeTexture tex = altTexNumber == 0 ? entity.Properties.Client.FirstTexture : Alternates[altTexNumber % Alternates.Length];
                meshdata = capi.Tesselator.VoxelizeTexture(tex, capi.EntityTextureAtlas.Size, pos);
                for (int i = 0; i < meshdata.xyz.Length; i += 3)
                {
                    meshdata.xyz[i]     -= 0.125f;
                    meshdata.xyz[i + 1] -= 0.5f;
                    meshdata.xyz[i + 2] += 0.125f / 2;
                }
            }
            else
            {
                try
                {
                    capi.Tesselator.TesselateShapeWithJointIds("entity", entityShape, out meshdata, this, new Vec3f(), compositeShape.QuantityElements, compositeShape.SelectiveElements);

                    meshdata.Translate(compositeShape.offsetX, compositeShape.offsetY, compositeShape.offsetZ);
                } catch (Exception e)
                {
                    capi.World.Logger.Fatal("Failed tesselating entity {0} with id {1}. Entity will probably be invisible!. The teselator threw {2}", entity.Code, entity.EntityId, e);
                    return;
                }
            }

            meshdata.Rgba2 = null;

            if (meshRefOpaque != null)
            {
                capi.Render.DeleteMesh(meshRefOpaque);
                meshRefOpaque = null;
            }
            if (meshRefOit != null)
            {
                capi.Render.DeleteMesh(meshRefOit);
                meshRefOit = null;
            }

            MeshData opaqueMesh = meshdata.Clone().Clear();
            MeshData oitMesh    = meshdata.Clone().Clear();

            opaqueMesh.AddMeshData(meshdata, EnumChunkRenderPass.Opaque);
            oitMesh.AddMeshData(meshdata, EnumChunkRenderPass.Transparent);

            if (opaqueMesh.VerticesCount > 0)
            {
                meshRefOpaque = capi.Render.UploadMesh(opaqueMesh);
            }

            if (oitMesh.VerticesCount > 0)
            {
                meshRefOit = capi.Render.UploadMesh(oitMesh);
            }
        }