internal static void RenderTriangles(F3DEX2Interpreter f3dex2, int[] idx) { GL.Begin(PrimitiveType.Triangles); foreach (int i in idx) { if (i >= f3dex2.VertexBuffer.Length) { continue; } double[] S = new double[2], T = new double[2]; for (int j = 0; j < (OpenGLHelpers.Initialization.SupportsFunction("glActiveTextureARB") ? f3dex2.Textures.Length : 1); j++) { if (f3dex2.Textures[j].MaskS != 0) { S[j] = (f3dex2.VertexBuffer[i].TexCoord.X * f3dex2.Textures[j].ShiftScaleS * f3dex2.ScaleS[j] - (f3dex2.Textures[j].ULS * Fixed2Float[2] % (1 << f3dex2.Textures[j].MaskS))) * f3dex2.Textures[j].ScaleS; } else { S[j] = (f3dex2.VertexBuffer[i].TexCoord.X * f3dex2.Textures[j].ShiftScaleS * f3dex2.ScaleS[j] - (f3dex2.Textures[j].ULS * Fixed2Float[2])) * f3dex2.Textures[j].ScaleS; } if (f3dex2.Textures[j].MaskT != 0) { T[j] = (f3dex2.VertexBuffer[i].TexCoord.Y * f3dex2.Textures[j].ShiftScaleT * f3dex2.ScaleT[j] - (f3dex2.Textures[j].ULT * Fixed2Float[2] % (1 << f3dex2.Textures[j].MaskT))) * f3dex2.Textures[j].ScaleT; } else { T[j] = (f3dex2.VertexBuffer[i].TexCoord.Y * f3dex2.Textures[j].ShiftScaleT * f3dex2.ScaleT[j] - (f3dex2.Textures[j].ULT * Fixed2Float[2])) * f3dex2.Textures[j].ScaleT; } OpenGLHelpers.Initialization.MultiTexCoord2Checked(TextureUnit.Texture0 + j, S[j], T[j]); } if (!Convert.ToBoolean(f3dex2.GeometryMode & (uint)GeometryMode.LIGHTING)) { GL.Color4(f3dex2.VertexBuffer[i].Colors); } GL.Normal3(f3dex2.VertexBuffer[i].Normals); GL.Vertex3(f3dex2.VertexBuffer[i].Position); } GL.End(); }
internal static void PerformModeChanges(F3DEX2Interpreter f3dex2) { /* Textures */ if (Configuration.RenderTextures) { GL.Enable(EnableCap.Texture2D); /* Texgen */ if (Convert.ToBoolean(f3dex2.GeometryMode & (uint)GeometryMode.TEXTURE_GEN)) { GL.TexGen(TextureCoordName.S, TextureGenParameter.TextureGenMode, (int)TextureGenMode.NormalMap); GL.TexGen(TextureCoordName.T, TextureGenParameter.TextureGenMode, (int)TextureGenMode.NormalMap); GL.Enable(EnableCap.TextureGenS); GL.Enable(EnableCap.TextureGenT); } else { GL.Disable(EnableCap.TextureGenS); GL.Disable(EnableCap.TextureGenT); } } else { GL.Disable(EnableCap.Texture2D); } /* Culling */ if (Convert.ToBoolean(f3dex2.GeometryMode & (uint)GeometryMode.CULL_BOTH)) { GL.Enable(EnableCap.CullFace); if (Convert.ToBoolean(f3dex2.GeometryMode & (uint)GeometryMode.CULL_BACK)) { GL.CullFace(CullFaceMode.Back); } else { GL.CullFace(CullFaceMode.Front); } } else { GL.Disable(EnableCap.CullFace); } /* Lighting */ if (Convert.ToBoolean(f3dex2.GeometryMode & (uint)GeometryMode.LIGHTING)) { GL.Enable(EnableCap.Lighting); GL.Enable(EnableCap.Normalize); } else { GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Normalize); } /* Fog */ if (Configuration.EmulateFog) { if (Convert.ToBoolean(f3dex2.GeometryMode & (uint)GeometryMode.FOG)) { GL.Enable(EnableCap.Fog); } else { GL.Disable(EnableCap.Fog); } } else { GL.Disable(EnableCap.Fog); } /* Decal */ if (f3dex2.OtherModeL.ZModeDec) { GL.Enable(EnableCap.PolygonOffsetFill); GL.PolygonOffset(-1.0f, -1.0f); } else { GL.Disable(EnableCap.PolygonOffsetFill); } /* Alpha test */ if (f3dex2.OtherModeL.CvgXAlpha || f3dex2.OtherModeL.AlphaCvgSel) { GL.Enable(EnableCap.AlphaTest); GL.Disable(EnableCap.Blend); if (f3dex2.OtherModeL.AlphaCvgSel) { GL.AlphaFunc(AlphaFunction.Gequal, 0.125f); } else { GL.AlphaFunc(AlphaFunction.Greater, 0.0f); } } else { GL.Disable(EnableCap.AlphaTest); } /* Force blending */ if (f3dex2.OtherModeL.ForceBl) { GL.Disable(EnableCap.AlphaTest); GL.Enable(EnableCap.Blend); } else { GL.Disable(EnableCap.Blend); } /* Z-compare */ if (f3dex2.OtherModeL.ZCmp) { GL.DepthFunc(DepthFunction.Lequal); } else { GL.DepthFunc(DepthFunction.Always); } /* Z-update */ if (f3dex2.OtherModeL.ZUpd) { GL.DepthMask(true); } else { GL.DepthMask(false); } /* Blend modes */ switch (f3dex2.OtherModeL.Data >> 16) { case 0x0448: case 0x055A: GL.BlendFunc(BlendingFactor.One, BlendingFactor.One); break; case 0x0382: case 0x0091: case 0x0C08: case 0x0F0A: case 0x0302: GL.BlendFunc(BlendingFactor.One, BlendingFactor.Zero); break; case 0xAF50: case 0x0F5A: case 0x0FA5: case 0x5055: GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.One); break; case 0x5F50: GL.BlendFunc(BlendingFactor.Zero, BlendingFactor.OneMinusSrcAlpha); break; default: GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); break; } }
public ROMHandler(string fn) { #if !DEBUG try #endif { reload: DMATableAddress = FileNameTableAddress = SceneTableAddress = -1; Filename = fn; /* Initialize segment and rendering systems */ SegmentMapping = new Hashtable(); Renderer = new F3DEX2Interpreter(this); /* Read ROM */ System.IO.BinaryReader br = new System.IO.BinaryReader(System.IO.File.Open(fn, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)); if (br.BaseStream.Length < MinROMSize) throw new ROMHandlerException(string.Format("File size is less than {0}MB; ROM appears to be invalid.", (MinROMSize / 0x100000))); Data = new byte[br.BaseStream.Length]; br.Read(Data, 0, (int)br.BaseStream.Length); br.Close(); /* Detect byte order */ DetectByteOrder(); if (DetectedByteOrder != ByteOrder.BigEndian) { if (MessageBox.Show("The ROM file you have selected uses an incompatible byte order, and needs to be converted to Big Endian format to be used." + Environment.NewLine + Environment.NewLine + "Convert the ROM now? (You will be asked for the target filename; the converted ROM will also be reloaded.)", "Byte Order Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { /* Ask for new filename */ string fnnew = GUIHelpers.ShowSaveFileDialog("Nintendo 64 ROMs (*.z64;*.bin)|*.z64;*.bin|All Files (*.*)|*.*"); if (fnnew != string.Empty) { fn = fnnew; /* Perform byte order conversion */ byte[] datanew = new byte[Data.Length]; byte[] conv = null; for (int i = 0, j = 0; i < Data.Length; i += 4, j += 4) { if (DetectedByteOrder == ByteOrder.MiddleEndian) conv = new byte[4] { Data[i + 1], Data[i], Data[i + 3], Data[i + 2] }; else if (DetectedByteOrder == ByteOrder.LittleEndian) conv = new byte[4] { Data[i + 3], Data[i + 2], Data[i + 1], Data[i] }; Buffer.BlockCopy(conv, 0, datanew, j, conv.Length); } /* Save converted ROM, then reload it */ System.IO.BinaryWriter bw = new System.IO.BinaryWriter(System.IO.File.Create(fn)); bw.Write(datanew); bw.Close(); goto reload; } } else { /* Wrong byte order, no conversion performed */ throw new ByteOrderException(string.Format("Incompatible byte order {0} detected; ROM cannot be used.", DetectedByteOrder)); } } else { /* Read header */ ReadROMHeader(); /* Create XML actor definition reader */ XMLActorDefReader = new XMLActorDefinitionReader(System.IO.Path.Combine("XML", "ActorDefinitions", GameID.Substring(1, 2))); if (XMLActorDefReader.Definitions.Count > 0) { /* Create remaining XML-related objects */ XMLActorNames = new XMLHashTableReader(System.IO.Path.Combine("XML", "GameDataGeneric", GameID.Substring(1, 2)), "ActorNames.xml"); XMLObjectNames = new XMLHashTableReader(System.IO.Path.Combine("XML", "GameDataGeneric", GameID.Substring(1, 2)), "ObjectNames.xml"); XMLSongNames = new XMLHashTableReader(System.IO.Path.Combine("XML", "GameDataGeneric", GameID.Substring(1, 2)), "SongNames.xml"); XMLSceneNames = new XMLHashTableReader(System.IO.Path.Combine("XML", "GameDataSpecific", string.Format("{0}{1:X1}", GameID, Version)), "SceneNames.xml"); XMLRoomNames = new XMLHashTableReader(System.IO.Path.Combine("XML", "GameDataSpecific", string.Format("{0}{1:X1}", GameID, Version)), "RoomNames.xml"); XMLStageDescriptions = new XMLHashTableReader(System.IO.Path.Combine("XML", "GameDataSpecific", string.Format("{0}{1:X1}", GameID, Version)), "StageDescriptions.xml"); /* Determine if ROM uses z64tables hack */ HasZ64TablesHack = (Version == 15 && Endian.SwapUInt32(BitConverter.ToUInt32(Data, 0x1238)) != 0x0C00084C); /* Find and read build information, DMA table, etc. */ FindBuildInfo(); FindFileNameTable(); ReadDMATable(); ReadFileNameTable(); /* Try to identify files */ foreach (DMATableEntry dte in Files) dte.Identify(this); /* Find the code file */ FindCodeFile(); /* Find other Zelda-specific stuff */ FindActorTable(); FindObjectTable(); FindSceneTable(); ReadEntranceTable(); /* Some sanity checking & exception handling*/ if (Scenes == null || Scenes.Count == 0) throw new ROMHandlerException("No valid scenes could be recognized in the ROM."); /* Done */ Loaded = true; } } } #if !DEBUG catch (Exception ex) { Loaded = false; if (MessageBox.Show(ex.Message + "\n\n" + "Show detailed information?", "Exception", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { MessageBox.Show(ex.ToString(), "Exception Details", MessageBoxButtons.OK, MessageBoxIcon.Warning); } } #endif }