Beispiel #1
0
        protected override IRenderableMaterial CreateMaterial(object key)
        {
            switch (key)
            {
            case uint id:
                return(base.CreateMaterial(new Kn5MaterialDescription(_kn5.GetMaterial(id))));

            case Tuple <object, uint> special:
                return(base.CreateMaterial(new Kn5MaterialDescription(special.Item1, _kn5.GetMaterial(special.Item2))));

            default:
                return(base.CreateMaterial(key));
            }
        }
Beispiel #2
0
            Tuple <IRenderableTexture, float> IAlphaTexturesProvider.GetTexture(IDeviceContextHolder contextHolder, uint materialId)
            {
                if (!_cache.TryGetValue(materialId, out var result))
                {
                    if (_texturesProvider == null)
                    {
                        _texturesProvider = new Kn5TexturesProvider(_kn5, false);
                    }

                    result = new Tuple <IRenderableTexture, float>[] { null };

                    var material = _kn5.GetMaterial(materialId);
                    if (material != null && (material.BlendMode != Kn5MaterialBlendMode.Opaque || material.AlphaTested))
                    {
                        var shader       = material.ShaderName;
                        var normalsAlpha = shader == "ksPerPixelNM" || shader == "ksPerPixelNM_UV2" || shader.Contains("_AT") || shader == "ksSkinnedMesh";
                        if (normalsAlpha || !shader.Contains("MultiMap") && shader != "ksTyres" && shader != "ksBrakeDisc")
                        {
                            var textureName = material.GetMappingByName(normalsAlpha ? "txNormal" : "txDiffuse")?.Texture;
                            var alphaRef    = material.GetPropertyValueAByName("ksAlphaRef");
                            if (textureName != null && !shader.Contains("damage"))
                            {
                                result = new[] { Tuple.Create(_texturesProvider.GetTexture(contextHolder, textureName), alphaRef) };
                            }
                        }
                    }

                    _cache[materialId] = result;
                }

                return(result[0]);
            }
Beispiel #3
0
            Tuple <IRenderableTexture, float> INormalsNormalTexturesProvider.GetTexture(IDeviceContextHolder contextHolder, uint materialId)
            {
                if (!_cache.TryGetValue(materialId, out var result))
                {
                    if (_texturesProvider == null)
                    {
                        _texturesProvider = new Kn5TexturesProvider(_kn5, false);
                    }

                    var material    = _kn5.GetMaterial(materialId);
                    var textureName = material?.GetMappingByName("txNormal")?.Texture;
                    if (textureName != null && !material.ShaderName.Contains("damage"))
                    {
                        var texture = _texturesProvider.GetTexture(contextHolder, textureName);
                        result = new[] { Tuple.Create(texture, material.GetPropertyValueAByName("normalMult") + 1f) };
                    }
                    else
                    {
                        result = new Tuple <IRenderableTexture, float>[] { null };
                    }

                    _cache[materialId] = result;
                }

                return(result[0]);
            }
Beispiel #4
0
        public int GroupOrder(IKn5 kn5, IEnumerable <Tuple <Kn5Node, double, Mat4x4> > node, Dictionary <Kn5Node, int> nodeIndices)
        {
            var isTransparent = false;
            var isBlending    = false;
            var maxIndex      = 0;

            foreach (var n in node)
            {
                isTransparent |= n.Item1.IsTransparent;
                isBlending     = kn5.GetMaterial(n.Item1.MaterialId)?.BlendMode == Kn5MaterialBlendMode.AlphaBlend;
                maxIndex       = Math.Max(maxIndex, nodeIndices[n.Item1]);
            }
            return((isTransparent ? 1 << 31 : 0) | (isBlending ? 1 << 30 : 0) | maxIndex);
        }
Beispiel #5
0
        private static IEnumerable <Kn5Node> FilterNodes(IKn5 kn5, IFilter <string> filter, Kn5Node node)
        {
            if (node.NodeClass == Kn5NodeClass.Base)
            {
                return(node.Children.SelectMany(x => FilterNodes(kn5, filter, x)));
            }

            if (!filter.Test(node.Name) ||
                kn5.GetMaterial(node.MaterialId)?.TextureMappings.Any(x => x.Name == "txNormal" || x.Name == "txNormalDetail") != false)
            {
                return(new Kn5Node[0]);
            }

            return(new[] { node });
        }
        public IRenderableMaterial CreateMaterial(object key)
        {
            if (key is uint id) {
                return new Kn5MaterialToBake(_kn5.GetMaterial(id));
            }

            if (key is Kn5MaterialDescription description) {
                return new Kn5MaterialToBake(description.Material);
            }

            if (key is Kn5AmbientShadowMaterialDescription) {
                return new Kn5MaterialToBake(null);
            }

            throw new NotSupportedException("Type: " + key?.GetType());
        }
Beispiel #7
0
        public Kn5MaterialDialog([CanBeNull] BaseRenderer renderer, [CanBeNull] CarObject car, [CanBeNull] CarSkinObject activeSkin, [NotNull] IKn5 kn5,
                                 uint materialId)
        {
            ValuesStorage.Remove("__userpresets_p_" + PresetableKey);
            ValuesStorage.Remove("__userpresets_c_" + PresetableKey);

            var material = kn5.GetMaterial(materialId);

            if (material != null && renderer != null)
            {
                var properties  = material.ShaderProperties.Select(x => x.Clone()).ToArray();
                var depthMode   = material.DepthMode;
                var alphaTested = material.AlphaTested;
                var blendMode   = material.BlendMode;
                _dispose = new ActionAsDisposable(() => {
                    foreach (var property in material.ShaderProperties)
                    {
                        property.CopyFrom(properties.FirstOrDefault(x => x.Name == property.Name));
                    }

                    material.DepthMode   = depthMode;
                    material.AlphaTested = alphaTested;
                    material.BlendMode   = blendMode;
                    (renderer as IKn5ObjectRenderer)?.RefreshMaterial(kn5, materialId);
                });
            }

            DataContext = new ViewModel(renderer, kn5, activeSkin, materialId)
            {
                Close = Close
            };

            InitializeComponent();
            Buttons = new[] {
                kn5.IsEditable?CreateExtraDialogButton(AppStrings.Toolbar_Save, new AsyncCommand(async() => {
                    var d = _dispose;
                    try {
                        _dispose = null;
                        await Model.UpdateKn5AndClose(false);
                    } catch (Exception e) {
                        _dispose = d;
                        NonfatalError.Notify("Can’t save material", e);
                    }
                }, () => Model.IsChanged).ListenOn(Model, nameof(Model.IsChanged)), true) : null,
                    CancelButton
            };
        }
Beispiel #8
0
        protected static IEnumerable <IKn5RenderableObject> Flatten(IKn5 kn5, IEnumerable <IRenderableObject> root, [CanBeNull] string textureName,
                                                                    [CanBeNull] string objectPath)
        {
            var split = Lazier.Create(() => objectPath?.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries));

            bool TestObjectPath(IKn5RenderableObject obj)
            {
                var s = split.Value;

                if (s == null || s.Length < 1)
                {
                    return(true);
                }
                if (s[s.Length - 1] != obj.OriginalNode.Name)
                {
                    return(false);
                }
                return(kn5.GetObjectPath(obj.OriginalNode) == objectPath);
            }

            return(Flatten(root, x => {
                if (!(x is IKn5RenderableObject k))
                {
                    return true;
                }
                if (!TestObjectPath(k))
                {
                    return false;
                }
                if (textureName == null)
                {
                    return true;
                }
                var material = kn5.GetMaterial(k.OriginalNode.MaterialId);
                return material != null && material.TextureMappings.Where(y => y.Name != "txDetail" && y.Name != "txNormalDetail")
                .Any(m => m.Texture == textureName);
            }));
Beispiel #9
0
        private static async Task PrepareForGenerationAsync(Kn5NodeFilterContext filterContext, IKn5 kn5, CarLodGeneratorStageParams stage, bool printNodes)
        {
            var mergeRules  = new CarLodGeneratorMergeRules(filterContext, stage);
            var toMerge     = new Dictionary <Kn5Node, List <Tuple <Kn5Node, double, Mat4x4> > >();
            var nodeIndices = new Dictionary <Kn5Node, int>();

            MergeNode(kn5.RootNode, kn5.RootNode, 1d);
            foreach (var pair in toMerge)
            {
                var mergeData = pair.Value.GroupBy(x => mergeRules.MergeGroup(x.Item1, x.Item2))
                                .OrderBy(v => mergeRules.GroupOrder(kn5, v, nodeIndices)).Select(v => v.ToList()).ToList();
                await Task.Run(() => {
                    foreach (var group in mergeData)
                    {
                        MergeMeshes(pair.Key, group, mergeRules, stage);
                    }
                });
            }
            foreach (var node in kn5.Nodes.Where(x => x.Children?.Count > 1).ToList())
            {
                var meshesList = node.Children
                                 .Where(x => x.NodeClass != Kn5NodeClass.Base)
                                 .Select((x, i) => new { x, i = OrderIndex(x, i) })
                                 .OrderBy(x => x.i)
                                 .Select(x => x.x).ToList();
                if (meshesList.Count > 0)
                {
                    if (node.Children.Any(x => x.NodeClass == Kn5NodeClass.Base))
                    {
                        node.Children = node.Children.Where(x => x.NodeClass == Kn5NodeClass.Base)
                                        .Prepend(Kn5Node.CreateBaseNode($"__{meshesList[0].Name}_wrap_", meshesList, true))
                                        .Select((x, i) => new { x, i = OrderIndex(x, i) })
                                        .OrderBy(x => x.i)
                                        .Select(x => x.x).ToList();
                    }
                    else
                    {
                        node.Children = meshesList;
                    }
                }
            }
            if (printNodes)
            {
                PrintNode(kn5.RootNode, 0, 0);
            }
            mergeRules.FinalizeKn5(kn5);

            var duplicateNames = kn5.Nodes.GroupBy(x => $"{x.NodeClass}/{x.Name}")
                                 .Select(x => x.ToList()).Where(x => x.Count > 1).ToList();

            foreach (var group in duplicateNames)
            {
                AcToolsLogging.Write($"Duplicate name: {group[0].Name} ({group[0].NodeClass})");
                foreach (var toRename in group.Skip(1).Select((x, i) => new { x, i }))
                {
                    toRename.x.Name = $"{toRename.x.Name}___$unique:{toRename.i}";
                }
            }

            int OrderIndex(Kn5Node node, int index)
            {
                return(index + (AnyTransparent(node) ? 1 << 10 : 0));
            }

            void PrintNode(Kn5Node node, int level, int index)
            {
                var postfix = node.NodeClass == Kn5NodeClass.Base ? "" :
                              $"{(node.IsTransparent ? ", transparent" : "")}, material: {kn5.GetMaterial(node.MaterialId)?.Name}";

                AcToolsLogging.Write(
                    $"{new string('\t', level)}{node.Name} [{node.NodeClass}{postfix}, index: {OrderIndex(node, index)}, aabb: {filterContext.GetAabb3(node)}]");
                if (node.NodeClass == Kn5NodeClass.Base)
                {
                    for (var i = 0; i < node.Children.Count; i++)
                    {
                        PrintNode(node.Children[i], level + 1, i);
                    }
                }
            }

            bool AnyTransparent(Kn5Node node)
            {
                return(node.NodeClass == Kn5NodeClass.Base
                        ? node.Children.Any(AnyTransparent)
                        : node.IsTransparent || kn5.GetMaterial(node.MaterialId)?.BlendMode == Kn5MaterialBlendMode.AlphaBlend);
            }

            void ApplyPriority(Kn5Node mesh, double priority)
            {
                var offset = MoveAsideDistance(priority, stage);

                for (var i = 0; i < mesh.Vertices.Length; i++)
                {
                    Apply(ref mesh.Vertices[i]);
                }
                mesh.Tag = priority;

                void Apply(ref Kn5Node.Vertex v)
                {
                    v.Position[0] = v.Position[0] * (float)priority + offset.X;
                    v.Position[1] = v.Position[1] * (float)priority + offset.Y;
                    v.Position[2] = v.Position[2] * (float)priority + offset.Z;
                }
            }

            bool MergeNode(Kn5Node node, Kn5Node mergeRoot, double priority)
            {
                nodeIndices[node] = nodeIndices.Count;

                if (node != mergeRoot)
                {
                    if (mergeRules.CanSkipNode(node))
                    {
                        if (node.NodeClass == Kn5NodeClass.Base && !mergeRules.HasParentWithSameName(node) && !mergeRules.CanRemoveEmptyNode(node))
                        {
                            node.Children.Clear();
                            return(true);
                        }
                        return(false);
                    }

                    var priorityAdjustment = mergeRules.CalculateReductionPriority(node);
                    if (priorityAdjustment != 1d && (priorityAdjustment < priority || priority == 1d || node.NodeClass == Kn5NodeClass.Mesh))
                    {
                        priority = priorityAdjustment;
                    }

                    if (node.NodeClass == Kn5NodeClass.Mesh)
                    {
                        if (mergeRoot != null && mergeRules.CanMerge(node))
                        {
                            if (!toMerge.ContainsKey(mergeRoot))
                            {
                                toMerge[mergeRoot] = new List <Tuple <Kn5Node, double, Mat4x4> >();
                            }
                            toMerge[mergeRoot].Add(Tuple.Create(node, priority, node.CalculateTransformRelativeToParent(mergeRoot)));
                            return(false);
                        }
                        if (priority != 1d)
                        {
                            ApplyPriority(node, priority);
                        }
                        return(true);
                    }

                    if (node.NodeClass == Kn5NodeClass.SkinnedMesh)
                    {
                        return(true);
                    }

                    if (mergeRoot != null)
                    {
                        if (!mergeRules.CanMerge(node))
                        {
                            mergeRoot = null;
                        }
                        else if (node.Name != mergeRoot.Name && mergeRules.IsNodeMergeRoot(node))
                        {
                            mergeRoot = node;
                        }
                    }
                }

                for (var i = 0; i < node.Children.Count; ++i)
                {
                    if (!MergeNode(node.Children[i], mergeRoot, priority))
                    {
                        node.Children.RemoveAt(i);
                        --i;
                    }
                }

                return(node.Children.Count > 0 || mergeRoot == node || !mergeRules.CanRemoveEmptyNode(node));
            }
        }