Beispiel #1
0
        private void LoadModels(Dictionary <Scene, VirtualFilesystemDirectory> archiveMap)
        {
            // We're going to search the archives for a specific list of meshes that the game supports and load those.
            List <string> supportedModelPaths = new List <string>(new string[] { "model", "model1", "model2", "model3" });

            foreach (var kvp in archiveMap)
            {
                List <VirtualFilesystemFile> filesByExtension = kvp.Value.FindByExtension(".bmd", ".bdl");
                foreach (var vfsFile in filesByExtension)
                {
                    if (!supportedModelPaths.Contains(vfsFile.Name))
                    {
                        continue;
                    }

                    using (EndianBinaryReader reader = new EndianBinaryReader(new System.IO.MemoryStream(vfsFile.File.GetData()), Endian.Big))
                    {
                        WLog.Info(LogCategory.EntityLoading, null, "Loading {1} (3D Model) for {0}{1}...", vfsFile.Name, vfsFile.Extension);
                        J3DLoader j3dLoader  = new J3DLoader();
                        Mesh      resultMesh = j3dLoader.LoadFromStream(reader);
                        kvp.Key.MeshList.Add(resultMesh);
                        WLog.Info(LogCategory.EntityLoading, null, "Finished loading {1} (3D Model) for {0}{1}.", vfsFile.Name, vfsFile.Extension);
                    }
                }
            }
        }
        public async Task <IActionResult> Edit(int id, [Bind("Id,WLNumber,Hours,DateTimeFrom,DateTimeTo,Subject,WLogStatusId,IncidentId,PersonId")] WLog wLog)
        {
            if (id != wLog.Id)
            {
                return(NotFound());
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(wLog);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!WLogExists(wLog.Id))
                    {
                        return(NotFound());
                    }
                    else
                    {
                        throw;
                    }
                }
                return(RedirectToAction(nameof(IndexSearch)));
            }
            ViewData["IncidentId"]   = new SelectList(_context.Incident, "Id", "IncidentNumber", wLog.IncidentId);
            ViewData["PersonId"]     = new SelectList(_context.Person, "Id", "FullName", wLog.PersonId);
            ViewData["WLogStatusId"] = new SelectList(_context.WLogStatus, "Id", "WLogStatusName", wLog.WLogStatusId);
            return(View(wLog));
        }
        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)");
            }
        }
        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");
            }
        }
        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);
        }
Beispiel #6
0
        public async Task <IActionResult> Edit(int id, [Bind("Id,WLNumber,Hours,DateTimeFrom,DateTimeTo,Subject")] WLog wLog)
        {
            if (id != wLog.Id)
            {
                return(NotFound());
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(wLog);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!WLogExists(wLog.Id))
                    {
                        return(NotFound());
                    }
                    else
                    {
                        throw;
                    }
                }
                return(RedirectToAction(nameof(Index)));
            }
            return(View(wLog));
        }
Beispiel #7
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);
        }
Beispiel #8
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);
            }
        }
Beispiel #9
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);
            }
        }
Beispiel #10
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);
            }
        }
Beispiel #11
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");
            }
        }
Beispiel #12
0
        public async Task <IActionResult> Create([Bind("Id,WLNumber,Hours,DateTimeFrom,DateTimeTo,Subject")] WLog wLog)
        {
            if (ModelState.IsValid)
            {
                _context.Add(wLog);
                await _context.SaveChangesAsync();

                return(RedirectToAction(nameof(Index)));
            }
            return(View(wLog));
        }
Beispiel #13
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);
        }
Beispiel #14
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;
                        }
                    }
                }
            }
        }
Beispiel #15
0
        public void LoadFromStream(Scene parentScene, EndianBinaryReader reader)
        {
            var  mapEntities     = new List <RawMapEntity>();
            long fileOffsetStart = reader.BaseStream.Position;

            // File Header
            int chunkCount = reader.ReadInt32();

            // Read the chunk headers
            List <ChunkHeader> chunks = new List <ChunkHeader>();

            for (int i = 0; i < chunkCount; i++)
            {
                ChunkHeader chunk = new ChunkHeader();
                chunk.FourCC       = reader.ReadString(4);
                chunk.ElementCount = reader.ReadInt32();
                chunk.ChunkOffset  = reader.ReadInt32();

                chunk.Layer  = ResolveChunkFourCCToLayer(chunk.FourCC);
                chunk.FourCC = ResolveFourCCWithLayerToName(chunk.FourCC);

                chunks.Add(chunk);
            }

            // For each chunk, read all elements of that type of chunk.
            for (int i = 0; i < chunks.Count; i++)
            {
                ChunkHeader chunk = chunks[i];

                // Find the appropriate JSON template that describes this chunk.
                MapEntityDataDescriptor template = m_editorCore.Templates.MapEntityDataDescriptors.Find(x => x.FourCC == chunk.FourCC);

                if (template == null)
                {
                    WLog.Error(LogCategory.EntityLoading, null, "Unsupported entity FourCC: {0}. Map will save without this data!", chunk.FourCC);
                    continue;
                }

                reader.BaseStream.Position = chunk.ChunkOffset;

                for (int k = 0; k < chunk.ElementCount; k++)
                {
                    RawMapEntity entityInstance = LoadMapEntityFromStream(chunk.FourCC, reader, template);

                    entityInstance.Layer = chunk.Layer;
                    mapEntities.Add(entityInstance);
                }
            }

            m_entityData[parentScene] = mapEntities;
        }
Beispiel #16
0
        private static void OnRecieveLoggerMessage(WLog.Entry message)
        {
            string messagePrefix = "";
            if(message.Severity == LogSeverity.Warning)
                messagePrefix = "Warning: ";
            else if (message.Severity == LogSeverity.Error)
                messagePrefix = "Error: ";

            string categoryPrefix = "";
            if (message.Category != LogCategory.None)
                categoryPrefix = string.Format("[{0}] - ", message.Category);

            Console.WriteLine("{0}{1}{2}", messagePrefix, categoryPrefix, message.Message);
        }
Beispiel #17
0
        public async Task <IActionResult> Create([Bind("Id,WLNumber,Hours,DateTimeFrom,DateTimeTo,Subject,WLogStatusId,IncidentId,PersonId")] WLog wLog)
        {
            if (ModelState.IsValid)
            {
                _context.Add(wLog);
                await _context.SaveChangesAsync();

                return(RedirectToAction(nameof(IndexSearch)));
            }
            ViewData["IncidentId"]   = new SelectList(_context.Incident, "Id", "IncidentNumber", wLog.IncidentId);
            ViewData["PersonId"]     = new SelectList(_context.Person, "Id", "FullName", wLog.PersonId);
            ViewData["WLogStatusId"] = new SelectList(_context.WLogStatus, "Id", "WLogStatusName", wLog.WLogStatusId);
            return(View(wLog));
        }
Beispiel #18
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);
        }
Beispiel #19
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);
        }
Beispiel #20
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);
        }
Beispiel #21
0
        private void OnRecieveMessage(WLog.Entry message)
        {
            // Append Warning: or Error: to the messages if they have the right severity.
            string messagePrefix = "";
            if (message.Severity == LogSeverity.Warning)
                messagePrefix = "Warning: ";
            else if (message.Severity == LogSeverity.Error)
                messagePrefix = "Error: ";

            string categoryPrefix = "";
            if (message.Category != LogCategory.None)
                categoryPrefix = string.Format("[{0}] - ", message.Category);

            string finalMessage = string.Format("{0}{1}{2}", messagePrefix, categoryPrefix, message.Message);

            m_messageLog.AppendLine(finalMessage);
            OnPropertyChanged("Messages");
        }
Beispiel #22
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());
        }
Beispiel #23
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));
        }
Beispiel #24
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");
            }
        }
Beispiel #25
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);
        }
Beispiel #26
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);
            }
        }
Beispiel #27
0
        private void LoadEntities(Map newMap, EditorCore core, Dictionary <Scene, VirtualFilesystemDirectory> archiveMap, WWorld world)
        {
            MapEntityLoader entityLoader = new MapEntityLoader(core, newMap);

            // For each room/scene, find the associated dzr/dzs file and load its
            // contents into the entityLoader.
            foreach (var kvp in archiveMap)
            {
                // Check to see if this Archive has stage/room entity data.
                var roomEntData  = kvp.Value.FindByExtension(".dzr");
                var stageEntData = kvp.Value.FindByExtension(".dzs");

                VirtualFilesystemFile vfsFile = null;
                if (roomEntData.Count > 0)
                {
                    vfsFile = roomEntData[0];
                }
                else if (stageEntData.Count > 0)
                {
                    vfsFile = stageEntData[0];
                }
                else
                {
                    continue;
                }

                using (EndianBinaryReader reader = new EndianBinaryReader(new System.IO.MemoryStream(vfsFile.File.GetData()), Endian.Big))
                {
                    WLog.Info(LogCategory.EntityLoading, null, "Loading .dzr/.dzs (Room/Stage Entity Dat) for {0}{1}...", vfsFile.Name, vfsFile.Extension);
                    entityLoader.LoadFromStream(kvp.Key, reader);
                    WLog.Info(LogCategory.EntityLoading, null, "Finished loading .dzr/.dzs (Room/Stage Entity Dat) for {0}{1}.", vfsFile.Name, vfsFile.Extension);
                }
            }

            // Once we've loaded all of the entities from the stream, we're going to
            // post-process them to resolve object references.
            entityLoader.PostProcessEntities();

            // Finally, we can actually convert these into map objects
            foreach (var roomOrStageData in entityLoader.GetData())
            {
                Stage stage = roomOrStageData.Key as Stage;
                Room  room  = roomOrStageData.Key as Room;

                if (stage != null)
                {
                    PostProcessStage(stage, roomOrStageData.Value);
                    foreach (var entity in stage.Entities)
                    {
                        entity.World = world;
                    }
                }
                if (room != null)
                {
                    PostProcessRoom(room, roomOrStageData.Value);
                    foreach (var entity in room.Entities)
                    {
                        entity.World = world;
                    }
                }
            }
        }
Beispiel #28
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));
        }
Beispiel #29
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);
        }
Beispiel #30
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());
        }
Beispiel #31
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);
        }
Beispiel #32
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.
            }
        }