Ejemplo n.º 1
0
        internal int GetStride(ShaderAttributeIds attribute)
        {
            switch (attribute)
            {
            case ShaderAttributeIds.Position:
            case ShaderAttributeIds.Normal:
                return(4 * 3);

            case ShaderAttributeIds.Color0:
            case ShaderAttributeIds.Color1:
                return(4 * 4);

            case ShaderAttributeIds.Tex0:
            case ShaderAttributeIds.Tex1:
            case ShaderAttributeIds.Tex2:
            case ShaderAttributeIds.Tex3:
            case ShaderAttributeIds.Tex4:
            case ShaderAttributeIds.Tex5:
            case ShaderAttributeIds.Tex6:
            case ShaderAttributeIds.Tex7:
                return(4 * 2);

            default:
                WLog.Warning(LogCategory.Rendering, this, "Unsupported ShaderAttributeId: {0}", attribute);
                return(0);
            }
        }
Ejemplo n.º 2
0
        public static Shader GenerateShader(Material fromMat)
        {
            Shader shader  = new Shader(fromMat.Name);
            bool   success = GenerateVertexShader(shader, fromMat);

            if (success)
            {
                success = GenerateFragmentShader(shader, fromMat);
            }

            if (!success)
            {
                WLog.Warning(LogCategory.ShaderCompiler, shader, "Failed to generate shader for material {0}", fromMat.Name);
                shader.Dispose();

                // ToDo: Generate stub-shader here that expects Pos/UV and single texture.
                shader = new Shader(fromMat.Name);
                shader.CompileSource(File.ReadAllText("RenderSystem/Shaders/frag.glsl"), ShaderType.FragmentShader);
                shader.CompileSource(File.ReadAllText("RenderSystem/Shaders/vert.glsl"), ShaderType.VertexShader);
                shader.LinkShader();
                return(shader);
            }

            if (!shader.LinkShader())
            {
                shader.Dispose();
                shader = null;
            }

            return(shader);
        }
Ejemplo n.º 3
0
        public T GetProperty <T>(string propertyName)
        {
            Property prop = null;

            for (int i = 0; i < Properties.Count; i++)
            {
                if (string.Compare(propertyName, Properties[i].Name, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    prop = Properties[i];
                    break;
                }
            }

            if (prop == null)
            {
                WLog.Warning(LogCategory.EditorCore, this, "Requested Property {0} on object {1}, but no property found!", propertyName, this);
                return(default(T));
            }

            if (prop.Value == null)
            {
                return(default(T));
            }

            return((T)prop.Value);
        }
Ejemplo n.º 4
0
        private static string GetAlphaInString(GXCombineAlphaInput inputType, GXKonstAlphaSel konst, TevOrder texMapping)
        {
            switch (inputType)
            {
            case GXCombineAlphaInput.AlphaPrev: return(m_tevOutputRegs[0] + ".a");

            case GXCombineAlphaInput.A0: return(m_tevOutputRegs[1] + ".a");

            case GXCombineAlphaInput.A1: return(m_tevOutputRegs[2] + ".a");

            case GXCombineAlphaInput.A2: return(m_tevOutputRegs[3] + ".a");

            case GXCombineAlphaInput.TexAlpha: return(GetTexTapString(texMapping) + ".a");

            case GXCombineAlphaInput.RasAlpha: return(GetVertColorString(texMapping) + ".a");

            case GXCombineAlphaInput.Konst: return(GetKonstAlphaString(konst));

            case GXCombineAlphaInput.Zero: return("0.0f");

            default:
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Unknown Alpha Input type: {0}", inputType);
                return("0.0f");
            }
        }
Ejemplo n.º 5
0
        public static DepthFunction GetOpenGLDepthFunc(GXCompareType gxCompare)
        {
            switch (gxCompare)
            {
            case GXCompareType.Never: return(DepthFunction.Never);

            case GXCompareType.Less: return(DepthFunction.Less);

            case GXCompareType.Equal: return(DepthFunction.Equal);

            case GXCompareType.LEqual: return(DepthFunction.Lequal);

            case GXCompareType.Greater: return(DepthFunction.Greater);

            case GXCompareType.NEqual: return(DepthFunction.Notequal);

            case GXCompareType.GEqual: return(DepthFunction.Gequal);

            case GXCompareType.Always: return(DepthFunction.Always);

            default:
                WLog.Warning(LogCategory.Rendering, null, "Unsupported GXCompareType: \"{0}\" in GetOpenGLDepthFunc!", gxCompare);
                return(DepthFunction.Less);
            }
        }
Ejemplo n.º 6
0
        public static BlendingFactorDest GetOpenGLBlendDest(GXBlendModeControl gxMode)
        {
            switch (gxMode)
            {
            case GXBlendModeControl.Zero: return(BlendingFactorDest.Zero);

            case GXBlendModeControl.One: return(BlendingFactorDest.One);

            case GXBlendModeControl.SrcColor: return(BlendingFactorDest.SrcColor);

            case GXBlendModeControl.InverseSrcColor: return(BlendingFactorDest.OneMinusSrcColor);

            case GXBlendModeControl.SrcAlpha: return(BlendingFactorDest.SrcAlpha);

            case GXBlendModeControl.InverseSrcAlpha: return(BlendingFactorDest.OneMinusSrcAlpha);

            case GXBlendModeControl.DstAlpha: return(BlendingFactorDest.DstAlpha);

            case GXBlendModeControl.InverseDstAlpha: return(BlendingFactorDest.OneMinusDstAlpha);

            default:
                WLog.Warning(LogCategory.Rendering, null, "Unsupported GXBlendModeControl: \"{0}\" in GetOpenGLBlendDest!", gxMode);
                return(BlendingFactorDest.OneMinusSrcAlpha);
            }
        }
Ejemplo n.º 7
0
        private static string GetVertColorString(TevOrder orderInfo)
        {
            switch (orderInfo.ChannelId)
            {
            case GXColorChannelId.Color0: return("Color0.rgb");

            case GXColorChannelId.Color1: return("Color1.rgb");

            case GXColorChannelId.Alpha0: return("Color0.aaaa");

            case GXColorChannelId.Alpha1: return("Color1.aaaa");

            case GXColorChannelId.Color0A0: return("Color0.rgba");

            case GXColorChannelId.Color1A1: return("Color1.rgba");

            case GXColorChannelId.ColorZero: return("0.rrrr");

            case GXColorChannelId.AlphaBump:
            case GXColorChannelId.AlphaBumpN:
            case GXColorChannelId.ColorNull:
            default:
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Unsupported ChannelId: {0}", orderInfo.ChannelId);
                return("vec4(0.0, 1.0, 0.0, 1.0)");
            }
        }
Ejemplo n.º 8
0
        private static string GetKonstAlphaString(GXKonstAlphaSel konst)
        {
            switch (konst)
            {
            case GXKonstAlphaSel.KASel_1: return("1.0");

            case GXKonstAlphaSel.KASel_7_8: return("0.875");

            case GXKonstAlphaSel.KASel_3_4: return("0.75");

            case GXKonstAlphaSel.KASel_5_8: return("0.625");

            case GXKonstAlphaSel.KASel_1_2: return("0.5");

            case GXKonstAlphaSel.KASel_3_8: return("0.375");

            case GXKonstAlphaSel.KASel_1_4: return("0.25");

            case GXKonstAlphaSel.KASel_1_8: return("0.125");

            case GXKonstAlphaSel.KASel_K0_R: return("konst0.r");

            case GXKonstAlphaSel.KASel_K1_R: return("konst1.r");

            case GXKonstAlphaSel.KASel_K2_R: return("konst2.r");

            case GXKonstAlphaSel.KASel_K3_R: return("konst3.r");

            case GXKonstAlphaSel.KASel_K0_G: return("konst0.g");

            case GXKonstAlphaSel.KASel_K1_G: return("konst1.g");

            case GXKonstAlphaSel.KASel_K2_G: return("konst2.g");

            case GXKonstAlphaSel.KASel_K3_G: return("konst3.g");

            case GXKonstAlphaSel.KASel_K0_B: return("konst0.b");

            case GXKonstAlphaSel.KASel_K1_B: return("konst1.b");

            case GXKonstAlphaSel.KASel_K2_B: return("konst2.b");

            case GXKonstAlphaSel.KASel_K3_B: return("konst3.b");

            case GXKonstAlphaSel.KASel_K0_A: return("konst0.a");

            case GXKonstAlphaSel.KASel_K1_A: return("konst1.a");

            case GXKonstAlphaSel.KASel_K2_A: return("konst2.a");

            case GXKonstAlphaSel.KASel_K3_A: return("konst3.a");

            default:
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Unsupported GXKonstAlphaSel: {0}, returning 1.0", konst);
                return("1.0");
            }
        }
Ejemplo n.º 9
0
        public void RemoveProperty(string propertyName)
        {
            for (int i = 0; i < Properties.Count; i++)
            {
                if (string.Compare(propertyName, Properties[i].Name, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    Properties.RemoveAt(i);
                    return;
                }
            }

            WLog.Warning(LogCategory.EditorCore, this, "Tried to remove Property {0} on object {1}, but no property found!", propertyName, this);
        }
Ejemplo n.º 10
0
        public void PostProcessEntities()
        {
            foreach (var kvp in m_entityData)
            {
                foreach (var entity in kvp.Value)
                {
                    MapEntityDataDescriptor origTemplate = m_editorCore.Templates.MapEntityDataDescriptors.Find(x => string.Compare(x.FourCC, entity.FourCC, StringComparison.InvariantCultureIgnoreCase) == 0);
                    if (origTemplate == null)
                    {
                        WLog.Warning(LogCategory.EntityLoading, null, "Failed to find template for entity {0}, not attempting to post-process.", entity);
                        continue;
                    }

                    foreach (Property property in entity.Fields.Properties)
                    {
                        var origTemplateProperty = origTemplate.Fields.Find(x => x.FieldName == property.Name);
                        if (origTemplateProperty == null)
                        {
                            WLog.Warning(LogCategory.EntityLoading, null, "Failed to find property {0} on template {1} for entity {2}, not attempting to post-process.", property.Name, origTemplate.FourCC, entity);
                            continue;
                        }

                        // We cheated earlier and stored the various reference-type ones as their index values. That means the type of the object doesn't actually
                        // reflect the Type field. Thus, we now need to go back, patch up the references, and set them to be their proper type. Yeah!
                        switch (origTemplateProperty.FieldType)
                        {
                        case PropertyType.ObjectReference:
                        case PropertyType.ObjectReferenceShort:
                        {
                            int objIndex = (int)property.Value;
                            property.Value = ResolveEntityReference(entity.FourCC, origTemplateProperty, objIndex, kvp.Key);
                        }
                        break;

                        case PropertyType.ObjectReferenceArray:
                        {
                            BindingList <object> indexes      = (BindingList <object>)property.Value;
                            BindingList <object> resolvedRefs = new BindingList <object>();
                            for (int i = 0; i < indexes.Count; i++)
                            {
                                var obj = ResolveEntityReference(entity.FourCC, origTemplateProperty, (int)indexes[i], kvp.Key);
                                resolvedRefs.Add(obj);
                            }
                            property.Value = resolvedRefs;
                        }
                        break;
                        }
                    }
                }
            }
        }
Ejemplo n.º 11
0
        private object ResolveEntityReference(string askingChunkFourCC, DataDescriptorField templateProperty, int index, Scene scene)
        {
            switch (templateProperty.ReferenceType)
            {
            case ReferenceTypes.Room:
                // Some things will specify a Room index of 255 for "This isn't Used", so we're going to special-case handle that.
                if (index == 0xFF)
                {
                    return(null);
                }

                if (index < m_map.Rooms.Count)
                {
                    return(m_map.Rooms[index]);
                }
                else
                {
                    WLog.Warning(LogCategory.EntityLoading, null, "Chunk {0} requested reference for room but index is out of range. (Property Name: {1}, Index: {2})", askingChunkFourCC, templateProperty.FieldName, index);
                }
                return(null);

            case ReferenceTypes.FourCC:
                // Get an (ordered) list of all chunks of that type.
                List <RawMapEntity> potentialRefs = new List <RawMapEntity>();
                foreach (var entity in m_entityData[scene])
                {
                    if (entity.FourCC == templateProperty.ReferenceFourCCType)
                    {
                        potentialRefs.Add(entity);
                    }
                }

                // There's an edge-case here where some maps omit an entity (such as Fairy01 not having a Virt chunk) but use index 0 (Fairy01's Pale chunk)
                // and so it was finding no potentialRefs
                if (index < potentialRefs.Count)
                {
                    return(potentialRefs[index]);
                }
                else
                {
                    WLog.Warning(LogCategory.EntityLoading, null, "Chunk {0} requested reference for property {1} but index ({2}) is out of range.", askingChunkFourCC, templateProperty.FieldName, index);
                }
                return(null);
            }

            return(null);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// This function is used to convert from a flat-file of J3DFileResource.InfoNodes into a treeview-type version of SceneNode.
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="allNodes"></param>
        /// <param name="currentListIndex"></param>
        /// <returns></returns>
        private static int ConvertInfoHiearchyToSceneGraph(ref SceneNode parent, List <InfoNode> allNodes, int currentListIndex)
        {
            for (int i = currentListIndex; i < allNodes.Count; i++)
            {
                InfoNode  curNode = allNodes[i];
                SceneNode newNode = new SceneNode();

                switch (curNode.Type)
                {
                case HierarchyDataTypes.NewNode:
                    // Increase the depth of the hierarchy by creating a new node and then processing all of the next nodes as its children.
                    // This function is recursive and will return the integer value of how many nodes it processed, this allows us to skip
                    // the list forward that many now that they've been handled.
                    newNode.Type  = HierarchyDataTypes.NewNode;
                    newNode.Value = curNode.Value;

                    i += ConvertInfoHiearchyToSceneGraph(ref newNode, allNodes, i + 1);
                    parent.Children.Add(newNode);
                    break;

                case HierarchyDataTypes.EndNode:
                    // Alternatively, if it's a EndNode, that's our signal to go up a level. We return the number of nodes that were processed between the last NewNode
                    // and this EndNode at this depth in the hierarchy.
                    return(i - currentListIndex + 1);

                case HierarchyDataTypes.Material:
                case HierarchyDataTypes.Joint:
                case HierarchyDataTypes.Batch:
                case HierarchyDataTypes.Finish:

                    // If it's any of the above we simply create a node for them. We create and pull from a different InfoNode because
                    // Hitting a NewNode can modify the value of i so curNode is now no longer valid.
                    InfoNode thisNode = allNodes[i];
                    newNode.Type  = thisNode.Type;
                    newNode.Value = thisNode.Value;
                    parent.Children.Add(newNode);
                    break;

                default:
                    WLog.Warning(LogCategory.ModelLoading, null, "Unsupported HierarchyDataType \"{0}\" in model!", curNode.Type);
                    break;
                }
            }

            return(0);
        }
Ejemplo n.º 13
0
        public bool CompileSource(string code, ShaderType type)
        {
            // Generate a new shader and clean up the old shader with a warning if they forgot to link before
            // trying to compile again.
            int shaderAddress = -1;

            switch (type)
            {
            case ShaderType.FragmentShader:
                if (m_fragmentAddress >= 0)
                {
                    WLog.Warning(LogCategory.ShaderCompiler, this, "Shader \"{0}\" called CompileSource for ShaderType: {1} twice before linking! Disposing old shader.", Name, type);
                    GL.DeleteShader(m_fragmentAddress);
                }
                m_fragmentAddress = GL.CreateShader(type);
                shaderAddress     = m_fragmentAddress;
                break;

            case ShaderType.VertexShader:
                if (m_vertexAddress >= 0)
                {
                    WLog.Warning(LogCategory.ShaderCompiler, this, "Shader \"{0}\" called CompileSource for ShaderType: {1} twice before linking! Disposing old shader.", Name, type);
                    GL.DeleteShader(m_fragmentAddress);
                }
                m_vertexAddress = GL.CreateShader(type);
                shaderAddress   = m_vertexAddress;
                break;
            }

            GL.ShaderSource(shaderAddress, code);

            GL.CompileShader(shaderAddress);
            //GL.AttachShader(program, address);

            int compileStatus;

            GL.GetShader(shaderAddress, ShaderParameter.CompileStatus, out compileStatus);

            if (compileStatus != 1)
            {
                WLog.Warning(LogCategory.ShaderCompiler, this, "Failed to compile shader {0}. Log:\n{1}", Name, GL.GetShaderInfoLog(shaderAddress));
                return(false);
            }

            return(true);
        }
Ejemplo n.º 14
0
        private static string GetAlphaOpString(GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp, byte outputRegIndex, string[] alphaInputs)
        {
            string        channelSelect = ".a";
            string        dest          = m_tevOutputRegs[outputRegIndex] + channelSelect;
            StringBuilder sb            = new StringBuilder();

            switch (op)
            {
            case GXTevOp.Add:
            case GXTevOp.Sub:
            {
                // out_color = (d + lerp(a, b, c)); - Add
                // out_color = (d - lerp(a, b, c)); - Sub
                string compareOp = (op == GXTevOp.Add) ? "+" : "-";
                sb.AppendLine(string.Format("{0} = ({1} {5} mix({2}, {3}, {4}));", dest, alphaInputs[3], alphaInputs[0], alphaInputs[1], alphaInputs[2], compareOp));
                sb.AppendLine(GetModString(outputRegIndex, bias, scale, clamp, true));
            }
            break;

            case GXTevOp.Comp_A8_EQ:
            case GXTevOp.Comp_A8_GT:
            {
                // out_color = (d + ((a.a > b.a) ? c : 0))
                string compareOp = (op == GXTevOp.Comp_R8_GT) ? ">" : "==";
                sb.AppendLine(string.Format("{0} = ({1} + (({2} {5} {3}) ? {4} : 0))", dest, alphaInputs[3], alphaInputs[0], alphaInputs[1], alphaInputs[2], compareOp));
            }
            break;

            default:
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Unsupported op in GetAlphaOpString: {0}", op);
                sb.AppendLine("// Invalid Alpha op for TEV broke here.");
                break;
            }

            if (op == GXTevOp.Comp_A8_GT || op == GXTevOp.Comp_A8_EQ)
            {
                // if(bias != 3 || scale != 1 || clamp != 1)
                // warn unexpected bias/scale/etc
            }

            return(sb.ToString());
        }
Ejemplo n.º 15
0
        private static string GetCompareString(GXCompareType compare, string a, byte refVal)
        {
            string outStr = "";
            float  fRef   = refVal / 255f;

            if (compare != GXCompareType.Always)
            {
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Untested alpha-test functionality: {0}", compare);
            }

            switch (compare)
            {
            case GXCompareType.Never: outStr = "false"; break;

            case GXCompareType.Less: outStr = "<"; break;

            case GXCompareType.Equal: outStr = "=="; break;

            case GXCompareType.LEqual: outStr = "<="; break;

            case GXCompareType.Greater: outStr = ">"; break;

            case GXCompareType.NEqual: outStr = "!="; break;

            case GXCompareType.GEqual: outStr = ">="; break;

            case GXCompareType.Always: outStr = "true"; break;

            default:
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Invalid comparison function, defaulting to always.");
                outStr = "true";
                break;
            }

            if (outStr == "false" || outStr == "true")
            {
                return(outStr);
            }

            return(string.Format("{0} {1} {2}", a, outStr, fRef));
        }
Ejemplo n.º 16
0
        private static string GetColorInString(GXCombineColorInput inputType, GXKonstColorSel konst, TevOrder texMapping)
        {
            switch (inputType)
            {
            case GXCombineColorInput.ColorPrev: return(m_tevOutputRegs[0] + ".rgb");

            case GXCombineColorInput.AlphaPrev: return(m_tevOutputRegs[0] + ".aaa");

            case GXCombineColorInput.C0: return(m_tevOutputRegs[1] + ".rgb");

            case GXCombineColorInput.A0: return(m_tevOutputRegs[1] + ".aaa");

            case GXCombineColorInput.C1: return(m_tevOutputRegs[2] + ".rgb");

            case GXCombineColorInput.A1: return(m_tevOutputRegs[2] + ".aaa");

            case GXCombineColorInput.C2: return(m_tevOutputRegs[3] + ".rgb");

            case GXCombineColorInput.A2: return(m_tevOutputRegs[3] + ".aaa");

            case GXCombineColorInput.TexColor: return(GetTexTapString(texMapping) + ".rgb");

            case GXCombineColorInput.TexAlpha: return(GetTexTapString(texMapping) + ".aaa");

            case GXCombineColorInput.RasColor: return(GetVertColorString(texMapping) + ".rgb");

            case GXCombineColorInput.RasAlpha: return(GetVertColorString(texMapping) + ".aaa");

            case GXCombineColorInput.One: return("1.0f.rrr");

            case GXCombineColorInput.Half: return("0.5f.rrr");

            case GXCombineColorInput.Konst: return(GetKonstColorString(konst) + ".rgb");

            case GXCombineColorInput.Zero: return("0.0f.rrr");

            default:
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Unknown Color Input type: {0}", inputType);
                return("0.0f.rrr");
            }
        }
Ejemplo n.º 17
0
        public void SetProperty(string propertyName, object value)
        {
            Property prop = null;

            for (int i = 0; i < Properties.Count; i++)
            {
                if (string.Compare(propertyName, Properties[i].Name, StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    prop = Properties[i];
                    break;
                }
            }

            if (prop != null)
            {
                prop.Value = value;
                return;
            }

            WLog.Warning(LogCategory.EditorCore, this, "Tried to set Property {0} on object {1}, but no property found!", propertyName, this);
        }
Ejemplo n.º 18
0
        internal VertexAttribPointerType GetAttributePointerType(ShaderAttributeIds attribute)
        {
            switch (attribute)
            {
            case ShaderAttributeIds.Position:
            case ShaderAttributeIds.Normal:
            case ShaderAttributeIds.Color0:
            case ShaderAttributeIds.Color1:
            case ShaderAttributeIds.Tex0:
            case ShaderAttributeIds.Tex1:
            case ShaderAttributeIds.Tex2:
            case ShaderAttributeIds.Tex3:
            case ShaderAttributeIds.Tex4:
            case ShaderAttributeIds.Tex5:
            case ShaderAttributeIds.Tex6:
            case ShaderAttributeIds.Tex7:
                return(VertexAttribPointerType.Float);

            default:
                WLog.Warning(LogCategory.Rendering, this, "Unsupported ShaderAttributeId: {0}", attribute);
                return(VertexAttribPointerType.Float);
            }
        }
Ejemplo n.º 19
0
        public Map CreateFromDirectory(WWorld world, EditorCore editorCore, string folderPath)
        {
            if (world == null)
            {
                throw new ArgumentNullException("world", "No world to load map into specified.");
            }

            if (string.IsNullOrEmpty(folderPath))
            {
                throw new ArgumentException("folderPath is null or empty!");
            }

            if (!System.IO.Directory.Exists(folderPath))
            {
                throw new System.IO.DirectoryNotFoundException("folderPath not found, ensure the directory exists first!");
            }

            // Calculate the Map Name from the folderPath - it should be the last segment of the folder path.s
            System.IO.DirectoryInfo rootFolderInfo = new System.IO.DirectoryInfo(folderPath);
            string mapName = rootFolderInfo.Name;


            // Sort the directories in rootFolderInfo into natural order, instead of alphabetical order which solves issues
            // where room indexes were getting remapped to the wrong one.
            IEnumerable <System.IO.DirectoryInfo> subFolders = rootFolderInfo.GetDirectories().OrderByNatural(x => x.Name);
            IEnumerable <System.IO.FileInfo>      subFiles   = rootFolderInfo.GetFiles().OrderByNatural(x => x.Name);

            // Maps are stored in two distinct parts. A Stage which encompasses global data for all rooms, and then
            // one or more rooms. We're going to load both the room and stage into ZArchives and then load the data
            // stored in them into different data.
            var archiveFolderMap = new Dictionary <string, VirtualFilesystemDirectory>();

            foreach (var dirInfo in subFolders)
            {
                VirtualFilesystemDirectory archive = null;

                string folderName = dirInfo.Name;
                if (folderName.ToLower().StartsWith("stage"))
                {
                    archive = new VirtualFilesystemDirectory(folderName);

                    if (archiveFolderMap.ContainsKey("stage"))
                    {
                        WLog.Warning(LogCategory.EditorCore, null, "{0} contains more than one stage archive, ignoring second...", folderPath);
                        continue;
                    }
                }
                else if (folderName.ToLower().StartsWith("room"))
                {
                    archive = new VirtualFilesystemDirectory(folderName);
                }

                // sea has LOD folders which don't have the right sub-folder setup, boo. This skips them for now,
                // maybe later we can add an ArchiveType.LOD.
                if (archive == null)
                {
                    continue;
                }

                // Fill the archives with their contents.
                archive.ImportFromDisk(dirInfo.FullName);
                archiveFolderMap[folderName.ToLower()] = archive;
            }

            // We're also going to try and process the files inside the folder to see if they're archives.
            foreach (var fileInfo in subFiles)
            {
                VirtualFilesystemDirectory archive = WArchiveTools.ArcUtilities.LoadArchive(fileInfo.FullName);

                // File wasn't a valid RARC archive.
                if (archive == null)
                {
                    continue;
                }

                if (archive.Name.ToLower().StartsWith("stage"))
                {
                    if (archiveFolderMap.ContainsKey("stage"))
                    {
                        WLog.Warning(LogCategory.EditorCore, null, "{0} contains more than one stage archive, ignoring second...", folderPath);
                        continue;
                    }
                }

                string arcName = System.IO.Path.GetFileNameWithoutExtension(fileInfo.FullName).ToLower();
                archiveFolderMap[arcName] = archive;
            }

            Map newMap = new Map();

            newMap.Name            = mapName;
            newMap.ProjectFilePath = System.IO.Path.GetDirectoryName(folderPath);

            var sceneMap = CreateScenesFromArchives(newMap, archiveFolderMap);

            LoadEntities(newMap, editorCore, sceneMap, world);
            LoadModels(sceneMap);

            return(newMap);
        }
Ejemplo n.º 20
0
        private static void LoadSHP1SectionFromFile(MeshVertexAttributeHolder vertexData, Mesh j3dMesh, EndianBinaryReader reader, long chunkStart)
        {
            short batchCount           = reader.ReadInt16();
            short padding              = reader.ReadInt16();
            int   batchOffset          = reader.ReadInt32();
            int   unknownTableOffset   = reader.ReadInt32(); // Another one of those 0->(n-1) counters. I think all sections have it? Might be part of the way they used inheritance to write files.
            int   alwaysZero           = reader.ReadInt32(); Trace.Assert(alwaysZero == 0);
            int   attributeOffset      = reader.ReadInt32();
            int   matrixTableOffset    = reader.ReadInt32();
            int   primitiveDataOffset  = reader.ReadInt32();
            int   matrixDataOffset     = reader.ReadInt32();
            int   packetLocationOffset = reader.ReadInt32();

            // Batches can have different attributes (ie: some have pos, some have normal, some have texcoords, etc.) they're split by batches,
            // where everything in the batch uses the same set of vertex attributes. Each batch then has several packets, which are a collection
            // of primitives.
            for (int b = 0; b < batchCount; b++)
            {
                MeshBatch meshBatch = new MeshBatch();
                j3dMesh.SubMeshes.Add(meshBatch);
                int overallVertexCount = 0;
                meshBatch.PrimitveType = OpenTK.Graphics.OpenGL.PrimitiveType.TriangleStrip; // HackHack, this varies per primitive.
                // We need to look on each primitive and convert them to trianglestrips, most are TS some are TF's.

                // We re-use the list struct here to dynamically add paired pos/col/tex as we load them
                // then we convert them into arrays for the MeshBatch afterwards.
                MeshVertexAttributeHolder meshVertexData = new MeshVertexAttributeHolder();

                // chunkStart + batchOffset gets you the position where the batches are listed
                // 0x28 * b gives you the right batch - a batch is 0x28 in length
                reader.BaseStream.Position = chunkStart + batchOffset + (0x28 * b);
                long batchStart = reader.BaseStream.Position;

                byte matrixType = reader.ReadByte();
                Trace.Assert(reader.ReadByte() == 0xFF); // Padding
                ushort packetCount          = reader.ReadUInt16();
                ushort batchAttributeOffset = reader.ReadUInt16();
                ushort firstMatrixIndex     = reader.ReadUInt16();
                ushort firstPacketIndex     = reader.ReadUInt16();
                ushort unknownpadding       = reader.ReadUInt16(); Trace.Assert(unknownpadding == 0xFFFF);

                float   boundingSphereDiameter = reader.ReadSingle();
                Vector3 boundingBoxMin         = new Vector3();
                boundingBoxMin.X = reader.ReadSingle();
                boundingBoxMin.Y = reader.ReadSingle();
                boundingBoxMin.Z = reader.ReadSingle();

                Vector3 boundingBoxMax = new Vector3();
                boundingBoxMax.X = reader.ReadSingle();
                boundingBoxMax.Y = reader.ReadSingle();
                boundingBoxMax.Z = reader.ReadSingle();


                // We need to figure out how many primitive attributes there are in the SHP1 section. This can differ from the number of
                // attributes in the VTX1 section, as the SHP1 can also include things like PositionMatrixIndex, so the count can be different.
                // This also varies *per batch* as not all batches will have the things like PositionMatrixIndex.
                reader.BaseStream.Position = chunkStart + attributeOffset + batchAttributeOffset;
                var batchAttributes = new List <ShapeAttribute>();
                do
                {
                    ShapeAttribute attribute = new ShapeAttribute();
                    attribute.ArrayType = (VertexArrayType)reader.ReadInt32();
                    attribute.DataType  = (VertexDataType)reader.ReadInt32();

                    if (attribute.ArrayType == VertexArrayType.NullAttr)
                    {
                        break;
                    }

                    batchAttributes.Add(attribute);
                } while (true);


                for (ushort p = 0; p < packetCount; p++)
                {
                    // Packet Location
                    reader.BaseStream.Position  = chunkStart + packetLocationOffset;
                    reader.BaseStream.Position += (firstPacketIndex + p) * 0x8; // A Packet Location is 0x8 long, so we skip ahead to the right one.

                    int packetSize   = reader.ReadInt32();
                    int packetOffset = reader.ReadInt32();

                    // Read the matrix data for this packet
                    reader.BaseStream.Position = chunkStart + matrixDataOffset + (firstMatrixIndex + p) * 0x08;
                    ushort matrixUnknown0   = reader.ReadUInt16();
                    ushort matrixCount      = reader.ReadUInt16();
                    uint   matrixFirstIndex = reader.ReadUInt32();

                    // Skip ahead to the actual data.
                    reader.BaseStream.Position = chunkStart + matrixTableOffset + (matrixFirstIndex * 0x2);
                    List <ushort> matrixTable = new List <ushort>();
                    for (int m = 0; m < matrixCount; m++)
                    {
                        matrixTable.Add(reader.ReadUInt16());
                    }

                    // Jump the read head to the location of the primitives for this packet.
                    reader.BaseStream.Position = chunkStart + primitiveDataOffset + packetOffset;
                    int numVertexesAtPacketStart = meshVertexData.PositionMatrixIndexes.Count;

                    uint numPrimitiveBytesRead = 0;
                    while (numPrimitiveBytesRead < packetSize)
                    {
                        // Jump to the primitives
                        // Primitives
                        GXPrimitiveType type = (GXPrimitiveType)reader.ReadByte();
                        // Game pads the chunks out with zeros, so this is the signal for an early break;
                        if (type == 0 || numPrimitiveBytesRead >= packetSize)
                        {
                            break;
                        }

                        ushort vertexCount = reader.ReadUInt16();

                        meshBatch.PrimitveType = type == GXPrimitiveType.TriangleStrip ? OpenTK.Graphics.OpenGL.PrimitiveType.TriangleStrip : OpenTK.Graphics.OpenGL.PrimitiveType.TriangleFan;
                        //if (type != GXPrimitiveType.TriangleStrip)
                        //{
                        //    WLog.Warning(LogCategory.ModelLoading, null, "Unsupported GXPrimitiveType {0}", type);
                        //}

                        numPrimitiveBytesRead += 0x3; // Advance us by 3 for the Primitive header.

                        for (int v = 0; v < vertexCount; v++)
                        {
                            meshVertexData.Indexes.Add(overallVertexCount);
                            overallVertexCount++;

                            // Iterate through the attribute types. I think the actual vertices are stored in interleaved format,
                            // ie: there's say 13 vertexes but those 13 vertexes will have a pos/color/tex index listed after it
                            // depending on the overall attributes of the file.
                            for (int attrib = 0; attrib < batchAttributes.Count; attrib++)
                            {
                                // Jump to primitive location
                                //reader.BaseStream.Position = chunkStart + primitiveDataOffset + numPrimitiveBytesRead + packetOffset;

                                // Now that we know how big the vertex type is stored in (either a Signed8 or a Signed16) we can read that much data
                                // and then we can use that index and index into
                                int  val          = 0;
                                uint numBytesRead = 0;
                                switch (batchAttributes[attrib].DataType)
                                {
                                case VertexDataType.Signed8:
                                    val          = reader.ReadByte();
                                    numBytesRead = 1;
                                    break;

                                case VertexDataType.Signed16:
                                    val          = reader.ReadInt16();
                                    numBytesRead = 2;
                                    break;

                                default:
                                    WLog.Warning(LogCategory.ModelLoading, null, "Unknown Batch Index Type: {0}", batchAttributes[attrib].DataType);
                                    break;
                                }

                                // Now that we know what the index is, we can retrieve it from the appropriate array
                                // and stick it into our vertex. The J3D format removes all duplicate vertex attributes
                                // so we need to re-duplicate them here so that we can feed them to a PC GPU in a normal fashion.
                                switch (batchAttributes[attrib].ArrayType)
                                {
                                case VertexArrayType.Position:
                                    meshVertexData.Position.Add(vertexData.Position[val]);
                                    break;

                                case VertexArrayType.PositionMatrixIndex:
                                    meshVertexData.PositionMatrixIndexes.Add(val);
                                    break;

                                case VertexArrayType.Normal:
                                    meshVertexData.Normal.Add(vertexData.Normal[val]);
                                    break;

                                case VertexArrayType.Color0:
                                    meshVertexData.Color0.Add(vertexData.Color0[val]);
                                    break;

                                case VertexArrayType.Color1:
                                    meshVertexData.Color1.Add(vertexData.Color1[val]);
                                    break;

                                case VertexArrayType.Tex0:
                                    meshVertexData.Tex0.Add(vertexData.Tex0[val]);
                                    break;

                                case VertexArrayType.Tex1:
                                    meshVertexData.Tex1.Add(vertexData.Tex1[val]);
                                    break;

                                case VertexArrayType.Tex2:
                                    meshVertexData.Tex2.Add(vertexData.Tex2[val]);
                                    break;

                                case VertexArrayType.Tex3:
                                    meshVertexData.Tex3.Add(vertexData.Tex3[val]);
                                    break;

                                case VertexArrayType.Tex4:
                                    meshVertexData.Tex4.Add(vertexData.Tex4[val]);
                                    break;

                                case VertexArrayType.Tex5:
                                    meshVertexData.Tex5.Add(vertexData.Tex5[val]);
                                    break;

                                case VertexArrayType.Tex6:
                                    meshVertexData.Tex6.Add(vertexData.Tex6[val]);
                                    break;

                                case VertexArrayType.Tex7:
                                    meshVertexData.Tex7.Add(vertexData.Tex7[val]);
                                    break;

                                default:
                                    WLog.Warning(LogCategory.ModelLoading, null, "Unsupported attribType {0}", batchAttributes[attrib].ArrayType);
                                    break;
                                }

                                numPrimitiveBytesRead += numBytesRead;
                            }

                            // Gonna try a weird hack, where if the mesh doesn't have PMI values, we're going to use just use the packet index into the matrixtable
                            // so that all meshes always have PMI values, to abstract out the ones that don't seem to (but still have matrixtable) junk. It's a guess
                            // here.
                            if (batchAttributes.Find(x => x.ArrayType == VertexArrayType.PositionMatrixIndex) == null)
                            {
                                meshVertexData.PositionMatrixIndexes.Add(p);
                            }
                        }

                        // After we write a primitive, write a special null-terminator which signifies the GPU to do a primitive restart for the next tri-strip.
                        meshVertexData.Indexes.Add(0xFFFF);
                    }

                    // The Matrix Table is per-packet, so we need to reach into the the matrix table after processing each packet
                    // and transform the indexes. Yuck. Yay.
                    for (int j = numVertexesAtPacketStart; j < meshVertexData.PositionMatrixIndexes.Count; j++)
                    {
                        // Yes you divide this by 3. No, no one knows why. $20 to the person who figures out why.
                        meshBatch.drawIndexes.Add(matrixTable[meshVertexData.PositionMatrixIndexes[j] / 3]);
                    }
                }

                meshBatch.Vertices             = meshVertexData.Position.ToArray();
                meshBatch.Color0               = meshVertexData.Color0.ToArray();
                meshBatch.Color1               = meshVertexData.Color1.ToArray();
                meshBatch.TexCoord0            = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord1            = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord2            = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord3            = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord4            = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord5            = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord6            = meshVertexData.Tex0.ToArray();
                meshBatch.TexCoord7            = meshVertexData.Tex0.ToArray();
                meshBatch.Indexes              = meshVertexData.Indexes.ToArray();
                meshBatch.PositionMatrixIndexs = meshVertexData.PositionMatrixIndexes; // This should be obsolete as they should be transformed already.
            }
        }
Ejemplo n.º 21
0
        public Mesh LoadFromStream(EndianBinaryReader reader)
        {
            MeshVertexAttributeHolder vertexData = null;
            SceneNode        rootNode            = new SceneNode();
            List <Texture2D> textureList         = new List <Texture2D>();
            List <WEditor.Common.Nintendo.J3D.Material> materialList = null;
            List <SkeletonBone> joints    = new List <SkeletonBone>();
            DrawInfo            drawInfo  = null;
            Envelopes           envelopes = null;

            Mesh j3dMesh = new Mesh();

            // Read the Header
            int magic = reader.ReadInt32(); // J3D1, J3D2, etc

            if (magic != 1244873778)
            {
                WLog.Warning(LogCategory.ModelLoading, null, "Attempted to load model with invalid magic, ignoring!");
                return(null);
            }

            int j3dType       = reader.ReadInt32(); // BMD3 (models) BDL4 (models), jpa1 (particles), bck1 (animations), etc.
            int totalFileSize = reader.ReadInt32();
            int chunkCount    = reader.ReadInt32();

            // Skip over an unused tag (consistent in all files) and some padding.
            reader.ReadBytes(16);

            for (int i = 0; i < chunkCount; i++)
            {
                long chunkStart = reader.BaseStream.Position;

                string tagName   = reader.ReadString(4);
                int    chunkSize = reader.ReadInt32();

                switch (tagName)
                {
                // INFO - Vertex Count, Scene Hierarchy
                case "INF1":
                    rootNode = LoadINF1FromFile(rootNode, reader, chunkStart);
                    break;

                // VERTEX - Stores vertex arrays for pos/normal/color0/tex0 etc. Contains VertexAttributes which describe
                // how this data is stored/laid out.
                case "VTX1":
                    vertexData = LoadVTX1FromFile(reader, chunkStart, chunkSize);
                    break;

                // ENVELOPES - Defines vertex weights for skinning.
                case "EVP1":
                    envelopes = LoadEVP1FromStream(reader, chunkStart);
                    break;

                // DRAW (Skeletal Animation Data) - Stores which matrices are weighted, and which are used directly.
                case "DRW1":
                    drawInfo = LoadDRW1FromStream(reader, chunkStart);
                    break;

                // JOINTS - Stores the skeletal joints (position, rotation, scale, etc.)
                case "JNT1":
                    joints = LoadJNT1SectionFromStream(reader, chunkStart);
                    break;

                // SHAPE - Face/Triangle information for model.
                case "SHP1":
                    LoadSHP1SectionFromFile(vertexData, j3dMesh, reader, chunkStart);
                    break;

                // MATERIAL - Stores materials (which describes how textures, etc. are drawn)
                case "MAT3":
                    materialList = LoadMAT3SectionFromStream(reader, chunkStart, chunkSize);
                    break;

                // TEXTURES - Stores binary texture images.
                case "TEX1":
                    textureList = LoadTEX1FromFile(reader, chunkStart);
                    break;

                // MODEL - Seems to be bypass commands for Materials and invokes GX registers directly.
                case "MDL3":
                    break;
                }

                reader.BaseStream.Position = chunkStart + chunkSize;
            }

            // Resolve the texture indexes into actual textures now that we've loaded the TEX1 section.
            foreach (Material mat in materialList)
            {
                for (int i = 0; i < mat.TextureIndexes.Length; i++)
                {
                    short index = mat.TextureIndexes[i];
                    if (index < 0)
                    {
                        continue;
                    }

                    mat.Textures[i] = textureList[index];
                }
            }

            // loltests
            for (int i = 0; i < materialList.Count; i++)
            {
                materialList[i].VtxDesc = j3dMesh.SubMeshes[0].GetVertexDescription();
                Shader shader = TEVShaderGenerator.GenerateShader(materialList[i]);
                materialList[i].Shader = shader;
            }

            // We're going to do something a little crazy - we're going to read the scene view and apply textures to meshes (for now)
            Material curMat = null;

            AssignMaterialsToMeshRecursive(rootNode, j3dMesh, ref curMat, materialList);


            List <SkeletonBone> skeleton = new List <SkeletonBone>();

            BuildSkeletonRecursive(rootNode, skeleton, joints, 0);

            j3dMesh.Skeleton  = skeleton;
            j3dMesh.BindPoses = envelopes.inverseBindPose;

            // Let's do some ugly post-processing here to see if we can't resolve all of the cross-references and turn it into
            // a normal computer-readable format that we can digest in our RenderSytem.
            {
                for (int i = 0; i < j3dMesh.SubMeshes.Count; i++)
                {
                    MeshBatch batch = j3dMesh.SubMeshes[i];
                    batch.BoneWeights = new BoneWeight[batch.Vertices.Length];

                    for (int j = 0; j < batch.PositionMatrixIndexs.Count; j++)
                    {
                        // Okay so this is where it gets more complicated. The PMI gives us an index into the MatrixTable for the packet, which we
                        // resolve and call "drawIndexes" - however we have to divide the number they give us by three for some reason, so that is
                        // already done and now our drawIndexes array should be one-index-for-every-vertex-in-batch and it should be the index into
                        // the draw section we need.
                        ushort drw1Index = batch.drawIndexes[j];

                        // The drw1Index can be set as 0xFFFF - if so, this means that you need to use the dr1Index of the previous one.
                        // until it is no longer 0xFFFF.
                        int counter = 0;
                        while (drw1Index == 0xFFFF)
                        {
                            drw1Index = batch.drawIndexes[j - counter];
                            counter++;
                        }


                        bool       isWeighted = drawInfo.IsWeighted[drw1Index];
                        BoneWeight weight     = new BoneWeight();

                        if (isWeighted)
                        {
                            // Something on this doesn't work for models that actually specify a PositionMatrixIndex.
                            // So... some math is off somewhere and I don't know where for the moment.
                            ushort numBonesAffecting = envelopes.numBonesAffecting[drw1Index];
                            weight.BoneIndexes = new ushort[numBonesAffecting];
                            weight.BoneWeights = new float[numBonesAffecting];

                            // "Much WTFs"
                            ushort offset = 0;
                            for (ushort e = 0; e < envelopes.indexRemap[drw1Index]; e++)
                            {
                                offset += envelopes.numBonesAffecting[e];
                            }

                            offset *= 2;
                            Matrix4 finalTransform = Matrix4.Identity;
                            for (ushort k = 0; k < numBonesAffecting; k++)
                            {
                                ushort boneIndex  = envelopes.indexRemap[offset + (k * 0x2)];
                                float  boneWeight = envelopes.weights[(offset / 2) + k];

                                weight.BoneIndexes[k] = boneIndex;
                                weight.BoneWeights[k] = boneWeight;

                                // This was apaprently a partial thought I never finished or got working in the old one? :S
                            }
                        }
                        else
                        {
                            // If the vertex isn't weighted, we just use the position from the bone matrix.
                            SkeletonBone joint       = skeleton[drawInfo.Indexes[drw1Index]];
                            Matrix4      translation = Matrix4.CreateTranslation(joint.Translation);
                            Matrix4      rotation    = Matrix4.CreateFromQuaternion(joint.Rotation);
                            Matrix4      finalMatrix = rotation * translation;

                            // Move the mesh by transforming the position by this much.

                            // I think we can just assign full weight to the first bone index and call it good.
                            weight.BoneIndexes = new[] { drawInfo.Indexes[drw1Index] };
                            weight.BoneWeights = new[] { 1f };
                        }

                        batch.BoneWeights[j] = weight;
                    }
                }
            }

            return(j3dMesh);
        }
Ejemplo n.º 22
0
        private static List <T> LoadVertexAttribute <T>(EndianBinaryReader reader, int totalAttributeDataLength, byte decimalPoint, VertexArrayType arrayType, VertexDataType dataType, VertexColorType colorType) where T : new()
        {
            int componentCount = 0;

            switch (arrayType)
            {
            case VertexArrayType.Position:
            case VertexArrayType.Normal:
                componentCount = 3;
                break;

            case VertexArrayType.Color0:
            case VertexArrayType.Color1:
                componentCount = 4;
                break;

            case VertexArrayType.Tex0:
            case VertexArrayType.Tex1:
            case VertexArrayType.Tex2:
            case VertexArrayType.Tex3:
            case VertexArrayType.Tex4:
            case VertexArrayType.Tex5:
            case VertexArrayType.Tex6:
            case VertexArrayType.Tex7:
                componentCount = 2;
                break;

            default:
                WLog.Warning(LogCategory.ModelLoading, null, "Unsupported ArrayType \"{0}\" found while loading VTX1!", arrayType);
                break;
            }


            // We need to know the length of each 'vertex' (which can vary based on how many attributes and what types there are)
            int vertexSize = 0;

            switch (dataType)
            {
            case VertexDataType.Float32:
                vertexSize = componentCount * 4;
                break;

            case VertexDataType.Unsigned16:
            case VertexDataType.Signed16:
                vertexSize = componentCount * 2;
                break;

            case VertexDataType.Signed8:
            case VertexDataType.Unsigned8:
                vertexSize = componentCount * 1;
                break;

            case VertexDataType.None:
                break;

            default:
                WLog.Warning(LogCategory.ModelLoading, null, "Unsupported DataType \"{0}\" found while loading VTX1!", dataType);
                break;
            }

            switch (colorType)
            {
            case VertexColorType.RGB8:
                vertexSize = 3;
                break;

            case VertexColorType.RGBX8:
            case VertexColorType.RGBA8:
                vertexSize = 4;
                break;

            case VertexColorType.None:
                break;

            case VertexColorType.RGB565:
            case VertexColorType.RGBA4:
            case VertexColorType.RGBA6:
            default:
                WLog.Warning(LogCategory.ModelLoading, null, "Unsupported Color Data Type: {0}!", colorType);
                break;
            }


            int      sectionSize = totalAttributeDataLength / vertexSize;
            List <T> values      = new List <T>(sectionSize);
            float    scaleFactor = (float)Math.Pow(0.5, decimalPoint);

            for (int v = 0; v < sectionSize; v++)
            {
                // Create a default version of the object and then fill it up depending on our component count and its data type...
                dynamic value = new T();

                for (int i = 0; i < componentCount; i++)
                {
                    switch (dataType)
                    {
                    case VertexDataType.Float32:
                        value[i] = reader.ReadSingle() * scaleFactor;
                        break;

                    case VertexDataType.Unsigned16:
                        value[i] = (float)reader.ReadUInt16() * scaleFactor;
                        break;

                    case VertexDataType.Signed16:
                        value[i] = (float)reader.ReadInt16() * scaleFactor;
                        break;

                    case VertexDataType.Unsigned8:
                        value[i] = (float)reader.ReadByte() * scaleFactor;
                        break;

                    case VertexDataType.Signed8:
                        value[i] = (float)reader.ReadSByte() * scaleFactor;
                        break;

                    case VertexDataType.None:
                        // Let the next switch statement get it.
                        break;

                    default:
                        WLog.Warning(LogCategory.ModelLoading, null, "Unsupported Data Type: {0}!", dataType);
                        break;
                    }


                    switch (colorType)
                    {
                    case VertexColorType.RGBX8:
                    case VertexColorType.RGB8:
                    case VertexColorType.RGBA8:
                        value[i] = reader.ReadByte() / 255f;
                        break;

                    case VertexColorType.None:
                        break;

                    case VertexColorType.RGB565:
                    case VertexColorType.RGBA4:
                    case VertexColorType.RGBA6:
                    default:
                        WLog.Warning(LogCategory.ModelLoading, null, "Unsupported Color Data Type: {0}!", colorType);
                        break;
                    }
                }
                values.Add(value);
            }

            return(values);
        }
Ejemplo n.º 23
0
        public bool LinkShader()
        {
            if (m_programAddress >= 0)
            {
                WLog.Warning(LogCategory.ShaderCompiler, this, "Shader \"{0}\" called LinkShader for already linked shader! Disposing old program.", Name);
                GL.DeleteProgram(m_programAddress);
            }

            if (m_fragmentAddress < 0 || m_vertexAddress < 0)
            {
                throw new Exception("Shader does not have both a Vertex and Fragment shader!");
            }

            // Initialize a program and link the already compiled shaders
            m_programAddress = GL.CreateProgram();
            GL.AttachShader(m_programAddress, m_vertexAddress);
            GL.AttachShader(m_programAddress, m_fragmentAddress);

            // Bind our Attribute locations before we link the program.
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Position, "RawPosition");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Normal, "RawNormal");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Color0, "RawColor0");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Color1, "RawColor1");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Tex0, "RawTex0");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Tex1, "RawTex1");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Tex2, "RawTex2");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Tex3, "RawTex3");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Tex4, "RawTex4");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Tex5, "RawTex5");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Tex6, "RawTex6");
            GL.BindAttribLocation(m_programAddress, (int)ShaderAttributeIds.Tex7, "RawTex7");

            GL.LinkProgram(m_programAddress);

            int linkStatus;

            GL.GetProgram(m_programAddress, GetProgramParameterName.LinkStatus, out linkStatus);
            if (linkStatus != 1)
            {
                WLog.Warning(LogCategory.ShaderCompiler, this, "Error linking shader. Result: {0}", GL.GetProgramInfoLog(m_programAddress));
                return(false);
            }

            // Now that the program is linked, bind to our uniform locations.
            UniformModelMtx = GL.GetUniformLocation(m_programAddress, "ModelMtx");
            UniformViewMtx  = GL.GetUniformLocation(m_programAddress, "ViewMtx");
            UniformProjMtx  = GL.GetUniformLocation(m_programAddress, "ProjMtx");

            UniformTexMtx    = GL.GetUniformLocation(m_programAddress, "TexMtx");
            UniformPostMtx   = GL.GetUniformLocation(m_programAddress, "PostMtx");
            UniformColor0Amb = GL.GetUniformLocation(m_programAddress, "COLOR0_Amb");
            UniformColor0Mat = GL.GetUniformLocation(m_programAddress, "COLOR0_Mat");
            UniformColor1Amb = GL.GetUniformLocation(m_programAddress, "COLOR1_Amb");
            UniformColor1Mat = GL.GetUniformLocation(m_programAddress, "COLOR1_Mat");

            UniformLightBlock = GL.GetUniformLocation(m_programAddress, "Lights");
            UniformNumLights  = GL.GetUniformLocation(m_programAddress, "NumLights");

            // Now that we've (presumably) set both a vertex and a fragment shader and linked them to the program,
            // we're going to clean up the reference to the shaders as the Program now keeps its own reference.
            GL.DeleteShader(m_vertexAddress);
            GL.DeleteShader(m_fragmentAddress);
            m_vertexAddress   = -1;
            m_fragmentAddress = -1;
            return(true);
        }
Ejemplo n.º 24
0
        public static bool GenerateVertexShader(Shader shader, Material mat)
        {
            StringBuilder stream = new StringBuilder();

            // Shader Header
            stream.AppendLine("#version 330 core");
            stream.AppendLine();

            // Input Format
            stream.AppendLine("// Input");
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Position))
            {
                stream.AppendLine("in vec3 RawPosition;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("in vec3 RawNormal;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color0))
            {
                stream.AppendLine("in vec4 RawColor0;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color1))
            {
                stream.AppendLine("in vec4 RawColor1;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex0))
            {
                stream.AppendLine("in vec2 RawTex0;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex1))
            {
                stream.AppendLine("in vec2 RawTex1;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex2))
            {
                stream.AppendLine("in vec2 RawTex2;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex3))
            {
                stream.AppendLine("in vec2 RawTex3;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex4))
            {
                stream.AppendLine("in vec2 RawTex4;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex5))
            {
                stream.AppendLine("in vec2 RawTex5;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex6))
            {
                stream.AppendLine("in vec2 RawTex6;");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Tex7))
            {
                stream.AppendLine("in vec2 RawTex7;");
            }

            stream.AppendLine();

            // Output Format
            stream.AppendLine("// Output");
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("out vec3 Normal;");
            }

            for (int i = 0; i < mat.NumChannelControls; i++)
            {
                stream.AppendLine(string.Format("out vec4 Color{0};", i));
            }

            for (int texGen = 0; texGen < mat.NumTexGens; texGen++)
            {
                if (mat.TexGenInfos[texGen] != null)
                {
                    stream.AppendLine(string.Format("out vec3 Tex{0};", texGen));
                }
            }

            // Uniforms
            stream.AppendLine();
            stream.AppendLine("// Uniforms");
            stream.AppendLine(
                "   uniform mat4 ModelMtx;\n" +
                "   uniform mat4 ViewMtx;\n" +
                "   uniform mat4 ProjMtx;\n" +
                "\n" +

                "   uniform mat4 TexMtx[10];\n" +
                "   uniform mat4 PostMtx[20];\n" +
                "   uniform vec4 COLOR0_Amb;\n" +
                "   uniform vec4 COLOR0_Mat;\n" +
                "   uniform vec4 COLOR1_Amb;\n" +
                "   uniform vec4 COLOR1_Mat;\n" +
                "\n" +
                "struct GXLight\n" +
                "{\n" +
                "   vec4 Position;\n" +
                "   vec4 Direction;\n" +
                "   vec4 Color;\n" +
                "   vec4 DistAtten;\n" +
                "   vec4 AngleAtten;\n" +
                "};\n" +
                "\n" +

                "   GXLight Lights[8];\n" +
                "\n" +
                "uniform int NumLights;\n" +
                "uniform vec4 ambLightColor;\n");

            // Main Shader Code
            stream.AppendLine("// Main");
            stream.AppendLine("void main()");
            stream.AppendLine("{");
            stream.AppendLine("    mat4 MVP = ProjMtx * ViewMtx * ModelMtx;");
            stream.AppendLine("    mat4 MV = ViewMtx * ModelMtx;");

            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Position))
            {
                stream.AppendLine("    gl_Position = MVP * vec4(RawPosition, 1);");
            }
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("    Normal = normalize(RawNormal.xyz * inverse(transpose(mat3(MV))));");
            }
            //if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color0))
            //  stream.AppendLine("    Color0 = RawColor0;");
            //if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color1))
            //stream.AppendLine("    Color1 = RawColor1;");

            stream.AppendLine();
            stream.AppendLine("    // Ambient Colors & Material Colors");
            // Add the Ambient Colors for the Material
            for (int a = 0; a < mat.AmbientColors.Length; a++)
            {
                stream.AppendLine(string.Format("    vec4 ambColor{0} = vec4({1}, {2}, {3}, {4});", a, mat.AmbientColors[a].R, mat.AmbientColors[a].G, mat.AmbientColors[a].B, mat.AmbientColors[a].A));
            }

            // Add in the Material Colors
            for (int m = 0; m < mat.MaterialColors.Length; m++)
            {
                stream.AppendLine(string.Format("    vec4 matColor{0} = vec4({1}, {2}, {3}, {4});", m, mat.MaterialColors[m].R, mat.MaterialColors[m].G, mat.MaterialColors[m].B, mat.MaterialColors[m].A));
            }

            stream.AppendLine();
            stream.AppendLine(string.Format("    // ChanCtrl's - {0} count", mat.NumChannelControls));

            // Channel Controllers
            // A vertex can have up to two color channels (RGBA each) which gives us four possible channels:
            // color0, color1, alpha0, alpha1
            // Each channel has an associated ambient color/alpha and a material color/alpha. These can come
            // from vertex colors or existing amb/mat registers.
            for (int chanSel = 0; chanSel < mat.NumChannelControls; chanSel++)
            {
                ChanCtrl chanInfo = mat.ChannelControls[chanSel];
                string   chanTarget, ambColor, matColor, ambLight, diffLight;
                string   swizzle, chan;
                bool     alpha;

                // Todo: Is this really a fixed order?
                switch (chanSel)
                {
                case /* Color0 */ 0: chan = "0"; swizzle = ".rgb"; alpha = false; break;

                case /* Alpha0 */ 1: chan = "0"; swizzle = ".a"; alpha = true; break;

                case /* Color1 */ 2: chan = "1"; swizzle = ".rgb"; alpha = false; break;

                case /* Alpha1 */ 3: chan = "1"; swizzle = ".a"; alpha = true; break;

                default:
                    WLog.Warning(LogCategory.TEVShaderGenerator, shader, "Unknown vertex output color channel {0}, skipping.", chanSel);
                    continue;
                }

                chanTarget = string.Format("Color{0}{1}", chan, swizzle);
                ambColor   = (chanInfo.AmbientSrc == GXColorSrc.Vertex ? "RawColor" : "ambColor") + chan + swizzle;
                matColor   = (chanInfo.MaterialSrc == GXColorSrc.Vertex ? "RawColor" : "matColor") + chan + swizzle;
                ambLight   = "ambLightColor" + swizzle;
                diffLight  = GetLightCalcString(chanInfo, alpha);

                //Color{0}.rgb = ambient * ambLightColor * light
                stream.AppendLine(string.Format("    Color{0} = vec4(1, 1, 1, 1);", chan));
                if (chanInfo.Enable)
                {
                    stream.AppendLine(string.Format("    {0} = {1} * {2} + {3} * {4};", chanTarget, ambColor, ambLight, matColor, diffLight));
                }
                else
                {
                    stream.AppendLine(string.Format("    {0} = {1};", chanTarget, matColor));
                }

                stream.AppendLine();
                stream.AppendLine();
            }


            // Texture Coordinate Generation
            stream.AppendLine(string.Format("    // TexGen - {0} count", mat.NumTexGens));
            for (int i = 0; i < mat.NumTexGens; i++)
            {
                if (mat.TexGenInfos[i] == null)
                {
                    continue;
                }

                TexCoordGen texGen = mat.TexGenInfos[i];
                string      texGenSrc;

                switch (texGen.Source)
                {
                case GXTexGenSrc.Position: texGenSrc = "RawPosition"; break;

                case GXTexGenSrc.Normal: texGenSrc = "RawNormal"; break;

                case GXTexGenSrc.Color0: texGenSrc = "Color0"; break;

                case GXTexGenSrc.Color1: texGenSrc = "Color1"; break;

                case GXTexGenSrc.Tex0: texGenSrc = "RawTex0"; break;     // Should Tex0 be TEXTURE 0? Or is it TEX0 = Input TEX0, while TEXCOORD0 = Output TEX0?

                case GXTexGenSrc.Tex1: texGenSrc = "RawTex1"; break;

                case GXTexGenSrc.Tex2: texGenSrc = "RawTex2"; break;

                case GXTexGenSrc.Tex3: texGenSrc = "RawTex3"; break;

                case GXTexGenSrc.Tex4: texGenSrc = "RawTex4"; break;

                case GXTexGenSrc.Tex5: texGenSrc = "RawTex5"; break;

                case GXTexGenSrc.Tex6: texGenSrc = "RawTex6"; break;

                case GXTexGenSrc.Tex7: texGenSrc = "RawTex7"; break;

                case GXTexGenSrc.TexCoord0: texGenSrc = "Tex0"; break;

                case GXTexGenSrc.TexCoord1: texGenSrc = "Tex1"; break;

                case GXTexGenSrc.TexCoord2: texGenSrc = "Tex2"; break;

                case GXTexGenSrc.TexCoord3: texGenSrc = "Tex3"; break;

                case GXTexGenSrc.TexCoord4: texGenSrc = "Tex4"; break;

                case GXTexGenSrc.TexCoord5: texGenSrc = "Tex5"; break;

                case GXTexGenSrc.TexCoord6: texGenSrc = "Tex6"; break;

                case GXTexGenSrc.Tangent:
                case GXTexGenSrc.Binormal:
                default:
                    WLog.Warning(LogCategory.TEVShaderGenerator, shader, "Unsupported TexGenSrc: {0}, defaulting to TEXCOORD0.", texGen.Source);
                    texGenSrc = "Tex0";
                    break;
                }

                if (texGen.TexMatrixSource == GXTexMatrix.Identity)
                {
                    switch (texGen.Type)
                    {
                    case GXTexGenType.Matrix2x4:
                        stream.AppendLine(string.Format("    Tex{0} = vec3({1}.xy, 0);", i, texGenSrc));
                        break;

                    case GXTexGenType.Matrix3x4:
                        stream.AppendLine(string.Format("    float3 uvw = {0}.xyz;", texGenSrc));
                        stream.AppendLine(string.Format("    Tex{0} = vec3((uvw / uvw.z).xy,0);", i));
                        break;

                    case GXTexGenType.SRTG:
                        stream.AppendLine(string.Format("    Tex{0} = vec3({1}.rg, 0);", i, texGenSrc));
                        break;

                    case GXTexGenType.Bump0:
                    case GXTexGenType.Bump1:
                    case GXTexGenType.Bump2:
                    case GXTexGenType.Bump3:
                    case GXTexGenType.Bump4:
                    case GXTexGenType.Bump5:
                    case GXTexGenType.Bump6:
                    case GXTexGenType.Bump7:
                    default:
                        WLog.Warning(LogCategory.TEVShaderGenerator, shader, "Unsupported TexMatrixSource: {0}, Defaulting to Matrix2x4", texGen.TexMatrixSource);
                        stream.AppendLine(string.Format("    Tex{0} = vec3({1}.xy, 0);", i, texGenSrc));
                        break;
                    }
                }
                else
                {
                    // Convert to TexMtx0 to TexMtx9
                    int matIndex = ((int)texGen.TexMatrixSource - 30) / 3;
                    switch (texGen.Type)
                    {
                    default:
                        WLog.Warning(LogCategory.TEVShaderGenerator, shader, "Unsupported TexMatrixSource");
                        break;
                    }
                }
            }

            stream.AppendLine("}");
            stream.AppendLine();

            // Compile the Vertex Shader and return whether it compiled sucesfully or not.
            Directory.CreateDirectory("ShaderDump");
            System.IO.File.WriteAllText("ShaderDump/" + mat.Name + "_vert_output", stream.ToString());
            return(shader.CompileSource(stream.ToString(), OpenTK.Graphics.OpenGL.ShaderType.VertexShader));
        }
Ejemplo n.º 25
0
        private static bool GenerateFragmentShader(Shader shader, Material mat)
        {
            StringBuilder stream = new StringBuilder();

            // Shader Header
            stream.AppendLine("#version 330 core");
            stream.AppendLine();

            // Configure inputs to match our outputs from VS
            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Position))
            {
                stream.AppendLine("in vec3 Position;");
            }

            if (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Normal))
            {
                stream.AppendLine("in vec3 Normal;");
            }

            for (int i = 0; i < mat.NumChannelControls; i++)
            {
                stream.AppendLine(string.Format("in vec4 Color{0};", i));
            }

            for (int texGen = 0; texGen < mat.NumTexGens; texGen++)
            {
                stream.AppendLine(string.Format("in vec3 Tex{0};", texGen));
            }

            stream.AppendLine();

            // Final Output
            stream.AppendLine("// Final Output");
            stream.AppendLine("out vec4 PixelColor;");

            // Texture Inputs
            for (int i = 0; i < 8; i++)
            {
                if (mat.Textures[i] == null)
                {
                    continue;
                }

                stream.AppendLine(string.Format("uniform sampler2D Texture{0};", i));
            }

            // Main Function
            stream.AppendLine("void main()");
            stream.AppendLine("{");

            // Default initial values of the TEV registers.
            // ToDo: Does this need swizzling? themikelester has it marked as mat.registerColor[i==0?3:i-1]]
            stream.AppendLine("    // Initial TEV Register Values");
            for (int i = 0; i < 4; i++)
            {
                stream.AppendLine(string.Format("    vec4 {0} = vec4({1}, {2}, {3}, {4});", m_tevOutputRegs[i], mat.TevColor[i].R, mat.TevColor[i].G, mat.TevColor[i].B, mat.TevColor[i].A));
            }
            stream.AppendLine();

            // Constant Color Registers
            stream.AppendLine("    // Konst TEV Colors");
            for (int i = 0; i < 4; i++)
            {
                stream.AppendLine(string.Format("    vec4 konst{0} = vec4({1}, {2}, {3}, {4});", i, mat.TevKonstColors[i].R, mat.TevKonstColors[i].G, mat.TevKonstColors[i].B, mat.TevKonstColors[i].A));
            }
            stream.AppendLine();

            // Texture Samples
            bool[] oldCombos = new bool[256];
            for (int i = 0; i < mat.NumTevStages; i++)
            {
                TevOrder       order = mat.TevOrderInfos[i];
                int            tex   = order.TexMap;
                GXTexCoordSlot coord = order.TexCoordId;

                // This TEV probably doesn't use textures.
                if (tex == 0xFF || coord == GXTexCoordSlot.Null)
                {
                    continue;
                }

                if (IsNewTexCombo(tex, (int)coord, oldCombos))
                {
                    string swizzle = ""; // Uhh I don't know if we need to swizzle since everyone's been converted into ARGB
                    stream.AppendLine(string.Format("    vec4 texCol{0} = texture(Texture{0}, Tex{1}.xy){2};", tex, (int)coord, swizzle));
                }
            }
            stream.AppendLine();

            // ToDo: Implement indirect texturing.
            stream.AppendLine("    // TEV Stages");
            stream.AppendLine();
            stream.AppendLine();

            for (int i = 0; i < mat.NumTevStages; i++)
            {
                stream.AppendLine(string.Format("    // TEV Stage {0}", i));
                TevOrder order = mat.TevOrderInfos[i];
                TevStage stage = mat.TevStageInfos[i];

                TevSwapMode      swap     = mat.TevSwapModes[i];
                TevSwapModeTable rasTable = mat.TevSwapModeTables[swap.RasSel];
                TevSwapModeTable texTable = mat.TevSwapModeTables[swap.TexSel];

                // There's swapping involved in the ras table.
                stream.AppendLine(string.Format("    // Rasterization Swap Table: {0}", rasTable));
                if (!(rasTable.R == 0 && rasTable.G == 1 && rasTable.B == 2 && rasTable.A == 3))
                {
                    stream.AppendLine(string.Format("    {0} = {1}{2};", GetVertColorString(order), GetVertColorString(order), GetSwapModeSwizzleString(rasTable)));
                }
                stream.AppendLine();


                // There's swapping involved in the texture table.
                stream.AppendLine(string.Format("    // Texture Swap Table: {0}", texTable));
                if (!(texTable.R == 0 && texTable.G == 1 && texTable.B == 2 && texTable.A == 3))
                {
                    stream.AppendLine(string.Format("    {0} = {1}{2};", GetTexTapString(order), GetTexTapString(order), GetSwapModeSwizzleString(rasTable)));
                }
                stream.AppendLine();

                string[] colorInputs = new string[4];
                colorInputs[0] = GetColorInString(stage.ColorIn[0], mat.KonstColorSels[i], order);
                colorInputs[1] = GetColorInString(stage.ColorIn[1], mat.KonstColorSels[i], order);
                colorInputs[2] = GetColorInString(stage.ColorIn[2], mat.KonstColorSels[i], order);
                colorInputs[3] = GetColorInString(stage.ColorIn[3], mat.KonstColorSels[i], order);

                stream.AppendLine("    // Color and Alpha Operations");
                stream.AppendLine(string.Format("    {0}", GetColorOpString(stage.ColorOp, stage.ColorBias, stage.ColorScale, stage.ColorClamp, stage.ColorRegId, colorInputs)));

                string[] alphaInputs = new string[4];
                alphaInputs[0] = GetAlphaInString(stage.AlphaIn[0], mat.KonstAlphaSels[i], order);
                alphaInputs[1] = GetAlphaInString(stage.AlphaIn[1], mat.KonstAlphaSels[i], order);
                alphaInputs[2] = GetAlphaInString(stage.AlphaIn[2], mat.KonstAlphaSels[i], order);
                alphaInputs[3] = GetAlphaInString(stage.AlphaIn[3], mat.KonstAlphaSels[i], order);

                stream.AppendLine(string.Format("    {0}", GetAlphaOpString(stage.AlphaOp, stage.AlphaBias, stage.AlphaScale, stage.AlphaClamp, stage.AlphaRegId, alphaInputs)));
                stream.AppendLine();
            }
            stream.AppendLine();

            // Alpha Compare
            stream.AppendLine("    // Alpha Compare Test");
            AlphaCompare alphaCompare = mat.AlphaCompare;
            string       alphaOp;

            switch (alphaCompare.Operation)
            {
            case GXAlphaOp.And: alphaOp = "&&"; break;

            case GXAlphaOp.Or: alphaOp = "||"; break;

            case GXAlphaOp.XOR: alphaOp = "^"; break;     // Not really tested, unsupported in some examples but I don't see why.

            case GXAlphaOp.XNOR: alphaOp = "=="; break;   // Not really tested. ^

            default:
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Unsupported alpha compare operation: {0}", alphaCompare.Operation);
                alphaOp = "||";
                break;
            }

            // clip(result.a < 0.5 && result a > 0.2 ? -1 : 1)
            string ifContents = string.Format("(!({0} {1} {2}))",
                                              GetCompareString(alphaCompare.Comp0, m_tevOutputRegs[0] + ".a", alphaCompare.Reference0),
                                              alphaOp,
                                              GetCompareString(alphaCompare.Comp1, m_tevOutputRegs[0] + ".a", alphaCompare.Reference1));

            // clip equivelent
            stream.AppendLine("    // Alpha Compare (Clip)");
            stream.AppendLine(string.Format("    if{0}\n\t\tdiscard;", ifContents));

            //string output = "PixelColor = texCol0" + (mat.VtxDesc.AttributeIsEnabled(ShaderAttributeIds.Color0) ? " * Color0;" : ";");
            //stream.AppendLine(output);
            stream.AppendLine(string.Format("    PixelColor = {0};", m_tevOutputRegs[0]));

            stream.AppendLine("}");
            stream.AppendLine();

            // Compile the Fragment Shader and return whether it compiled sucesfully or not.
            Directory.CreateDirectory("ShaderDump");
            System.IO.File.WriteAllText("ShaderDump/" + mat.Name + "_frag_output", stream.ToString());
            return(shader.CompileSource(stream.ToString(), OpenTK.Graphics.OpenGL.ShaderType.FragmentShader));
        }
Ejemplo n.º 26
0
        private static string GetColorOpString(GXTevOp op, GXTevBias bias, GXTevScale scale, bool clamp, byte outputRegIndex, string[] colorInputs)
        {
            string        channelSelect = ".rgb";
            string        dest          = m_tevOutputRegs[outputRegIndex] + channelSelect;
            StringBuilder sb            = new StringBuilder();

            switch (op)
            {
            case GXTevOp.Add:
            case GXTevOp.Sub:
            {
                // out_color = (d + lerp(a, b, c)); - Add
                // out_color = (d - lerp(a, b, c)); - Sub
                string compareOp = (op == GXTevOp.Add) ? "+" : "-";
                sb.AppendLine(string.Format("{0} = ({1} {5} mix({2}, {3}, {4}));", dest, colorInputs[3], colorInputs[0], colorInputs[2], colorInputs[1], compareOp));
                sb.AppendLine(GetModString(outputRegIndex, bias, scale, clamp, false));
            }
            break;

            case GXTevOp.Comp_R8_GT:
            case GXTevOp.Comp_R8_EQ:
            {
                // out_color = (d + ((a.r > b.r) ? c : 0));
                string compareOp = (op == GXTevOp.Comp_R8_GT) ? ">" : "==";
                sb.AppendLine(string.Format("{0} = ({1} + (({2}.r {5} {3}.r) ? {4} : 0))", dest, colorInputs[3], colorInputs[0], colorInputs[1], colorInputs[2], compareOp));
            }
            break;

            case GXTevOp.Comp_GR16_GT:
            case GXTevOp.Comp_GR16_EQ:
            {
                // out_color = (d + (dot(a.gr, rgTo16Bit) > dot(b.gr, rgTo16Bit) ? c : 0));
                string compareOp = (op == GXTevOp.Comp_GR16_GT) ? ">" : "==";
                string rgTo16Bit = "vec2(255.0/65535.6, 255.0 * 256.0/65535.0)";
                sb.AppendLine(string.Format("{0} = ({1} + (dot({2}.gr, {3}) {4} dot({5}.gr, {3}) ? {6} : 0));",
                                            dest, colorInputs[3], colorInputs[0], rgTo16Bit, compareOp, colorInputs[1], colorInputs[2]));
            }
            break;

            case GXTevOp.Comp_BGR24_GT:
            case GXTevOp.Comp_BGR24_EQ:
            {
                // out_color = (d + (dot(a.bgr, bgrTo24Bit) > dot(b.bgr, bgrTo24Bit) ? c : 0));
                string compareOp  = (op == GXTevOp.Comp_BGR24_GT) ? ">" : "==";
                string bgrTo24Bit = "vec3(255.0/16777215.0, 255.0 * 256.0/16777215.0, 255.0*65536.0/16777215.0)";
                sb.AppendLine(string.Format("{0} = ({1} + (dot({2}.bgr, {5}) {6} dot({3}.bgr, {5}) ? {4} : 0));",
                                            dest, colorInputs[3], colorInputs[0], colorInputs[1], colorInputs[2], bgrTo24Bit, compareOp));
            }
            break;

            case GXTevOp.Comp_RGB8_GT:
            case GXTevOp.Comp_RGB8_EQ:
            {
                // out_color.r = d.r + ((a.r > b.r) ? c.r : 0);
                // out_color.g = d.g + ((a.g > b.g) ? c.g : 0);
                // out_color.b = d.b + ((a.b > b.b) ? c.b : 0);
                string compareOp = (op == GXTevOp.Comp_RGB8_GT) ? ">" : "==";
                string format    = "{0}.{6} = {1}.{6} + (({2}.{6} {5} {3}.{6}) ? {4}.{6} : 0);";

                sb.AppendLine(string.Format(format, dest, colorInputs[3], colorInputs[0], colorInputs[1], colorInputs[2], compareOp, "r"));
                sb.AppendLine(string.Format(format, dest, colorInputs[3], colorInputs[0], colorInputs[1], colorInputs[2], compareOp, "g"));
                sb.AppendLine(string.Format(format, dest, colorInputs[3], colorInputs[0], colorInputs[1], colorInputs[2], compareOp, "b"));
            }
            break;

            default:
                WLog.Warning(LogCategory.TEVShaderGenerator, null, "Unsupported Color Op: {0}!", op);
                sb.AppendLine("// Invalid Color op for TEV broke here.");
                break;
            }

            if (op > GXTevOp.Sub)
            {
                //if(bias != 3 || scale != 0 || clamp != 1)
                // warn(unexpected bias, scale, clamp)...?
            }

            return(sb.ToString());
        }