BatchInfo GetCreateBatchInfo(ResourceHandle <Material> materialHandle) { if (!batches.ContainsKey(materialHandle.Id)) { var batch = new RenderBatch { GeometryBuffer = gb, RenderLayer = RenderLayer.Overlays, PrimitiveType = PrimitiveType.Quads, Material = materialHandle }; var batchInfo = new BatchInfo { Batch = batch, Ranges = new List <int>() }; batches[materialHandle.Id] = batchInfo; } return(batches[materialHandle.Id]); }
public void Update(RenderBatch batch) { for (var i = 0; i < batch.UpdatedComponents.Count; i++) { var diff = batch.UpdatedComponents.Array[i]; var componentId = diff.ComponentId; var edits = diff.Edits; UpdateComponent(batch, componentId, edits); } for (var i = 0; i < batch.DisposedComponentIDs.Count; i++) { DisposeComponent(batch.DisposedComponentIDs.Array[i]); } for (var i = 0; i < batch.DisposedEventHandlerIDs.Count; i++) { DisposeEventHandler(batch.DisposedEventHandlerIDs.Array[i]); } }
protected override void OnLoad(EventArgs e) { Events.EventHandler.RegisterEvents(this); Logger.Name = "GSharp"; GL.ClearColor(0.1f, 0.2f, 0.5f, 0.0f); GL.Enable(EnableCap.ScissorTest); Atlas = new TextureAtlas("atlas.png", "atlas.desc", TextureFilter.Nearest); Shader shader = new Shader("Graphics/OpenGL/Shaders/vertex.glsl", "Graphics/OpenGL/Shaders/fragment.glsl"); Shader textureShader = new Shader("Graphics/OpenGL/Shaders/vertexTex.glsl", "Graphics/OpenGL/Shaders/fragmentTex.glsl"); Shader atlasShader = new Shader("Graphics/OpenGL/Shaders/vertexAtlas.glsl", "Graphics/OpenGL/Shaders/fragmentTex.glsl"); Batch = new RenderBatch(new VertexComponent[] { VertexComponent.Coord, VertexComponent.Color }, shader, false); TextureBatch = new RenderBatch(new VertexComponent[] { VertexComponent.Coord, VertexComponent.TexCoord }, textureShader, false); AtlasBatch = new RenderBatch(new VertexComponent[] { VertexComponent.Coord, VertexComponent.TexCoord, VertexComponent.TexLocation }, atlasShader, false); AtlasBatch.SetAtlas(Atlas); LoadGeometry(); base.OnLoad(e); }
public override void Load() { // Engine components. RessourceManager ressourceManager = Engine.GetComponent <RessourceManager>(); // Setup the scene Entities = new List <Entity>(); camera = new OrbitalCamera(Engine.GraphicDevice.GetBufferSize().X / Engine.GraphicDevice.GetBufferSize().Y, 90); render = new RenderBatch(); testSun = new Sun(new Point3D(-150f, 150f, -150f), new Color3(255, 255, 255)); testScene = new Scene(camera, testSun); testScene.Fog.Density = 0f; // Dragon Model dragonModel = ressourceManager.ImportRessource <Model>("model:dragon.obj"); Material dragonMaterial = new Material(ressourceManager.ImportRessource <Texture2D>("texture2D:blue.png")); dragonMaterial.Reflectivity = 1f; dragonMaterial.ShineDamper = 10f; ressourceManager.ImportRessource <ShaderProgram>("shader:material.json"); Entities.Add(new Entity(new Transform(new Vector3(0, 0, 0), new Vector3(), 0.1f), dragonModel, dragonMaterial)); // Terrain Material GrassMaterial = new Material(ressourceManager.ImportRessource <Texture2D>("texture2D:grass.png")) { Reflectivity = 0f, ShineDamper = 10f }; terrain = new Entity(new Transform(0, -10f, 0), ModelFactorie.GeneratePlane(640f, 256, 64, new PerlinHeightMap()), GrassMaterial); water = new Entity(new Transform(0, 0, 0), ModelFactorie.GeneratePlane(640f, 16, 64, new FlatHeightMap()), dragonMaterial); // Show the inspector. new Inspector.InspectorUI(Engine, testScene).ShowInspector(); }
protected override void OnResize(EventArgs e) { float aspect = (float)VirtualWidth / VirtualHeight; int vpWidth = Width; int vpHeight = (int)(Width / aspect + 0.5f); if (vpHeight > Height) { vpHeight = Height; vpWidth = (int)(Height * aspect + 0.5f); } int vpX = (Width / 2) - (vpWidth / 2); int vpY = (Height / 2) - (vpHeight / 2); GL.Viewport(vpX, vpY, vpWidth, vpHeight); GL.Scissor(vpX, vpY, vpWidth, vpHeight); Matrix4 projection = Matrix4.CreateOrthographicOffCenter(0f, VirtualWidth, VirtualHeight, 0f, 0f, 1f); RenderBatch.SetProjectionMatrix(projection); base.OnResize(e); }
private void InsertElement(RenderBatch batch, ContainerNode parent, int childIndex, ArraySegment <RenderTreeFrame> frames, RenderTreeFrame frame, int frameIndex) { // Note: we don't handle SVG here var newElement = new ElementNode(frame.ElementName); parent.InsertLogicalChild(newElement, childIndex); // Apply attributes for (var i = frameIndex + 1; i < frameIndex + frame.ElementSubtreeLength; i++) { var descendantFrame = batch.ReferenceFrames.Array[i]; if (descendantFrame.FrameType == RenderTreeFrameType.Attribute) { ApplyAttribute(batch, newElement, descendantFrame); } else { // As soon as we see a non-attribute child, all the subsequent child frames are // not attributes, so bail out and insert the remnants recursively InsertFrameRange(batch, newElement, 0, frames, i, frameIndex + frame.ElementSubtreeLength); break; } } }
private void UpdateShadowCaster() { if (lookTarget == null) { GameObject go = GameObject.Find("LookTarget"); lookTarget = go != null ? go.transform : null; } if (lookTarget != null) { sceneData.currentEntityPos = lookTarget.position; } else { if (sceneData.CameraRef != null) { sceneData.currentEntityPos = cameraForward * 10 + sceneData.cameraPos; } } shadowCasters.Clear(); if (shadowCasterProxy == null) { shadowCasterProxy = GameObject.Find("ShadowCaster"); } shadowRenderBatchs.Clear(); bool first = true; Bounds shadowBound = new Bounds(Vector3.zero, Vector3.zero); if (shadowCasterProxy != null) { shadowCasterProxy.GetComponentsInChildren <Renderer>(false, shadowCasters); if (shadowCasters.Count > 0) { for (int i = 0; i < shadowCasters.Count; ++i) { Renderer render = shadowCasters[i]; if (render != null && render.enabled && render.shadowCastingMode != ShadowCastingMode.Off && render.sharedMaterial != null) { RenderBatch rb = new RenderBatch(); rb.render = render; rb.mat = render.sharedMaterial; rb.mpbRef = null; rb.passID = 0; shadowRenderBatchs.Add(rb); if (first) { shadowBound = render.bounds; first = false; } else { shadowBound.Encapsulate(render.bounds); } } } } } sceneData.shadowBound = shadowBound; }
protected override void UpdateDisplay(RenderBatch renderBatch) => throw new NotImplementedException();
BatchInfo GetCreateBatchInfo(ResourceHandle<Material> materialHandle) { if (!batches.ContainsKey(materialHandle.Id)) { var batch = new RenderBatch { GeometryBuffer = gb, RenderLayer = RenderLayer.Overlays, PrimitiveType = PrimitiveType.Quads, Material = materialHandle }; var batchInfo = new BatchInfo {Batch = batch, Ranges = new List<int>()}; batches[materialHandle.Id] = batchInfo; } return batches[materialHandle.Id]; }
internal void ApplyEdits(int componentId, ArrayBuilderSegment <RenderTreeEdit> edits, ArrayRange <RenderTreeFrame> referenceFrames, RenderBatch batch) { Renderer.Dispatcher.AssertAccess(); if (edits.Count == 0) { // TODO: Without this check there's a NullRef in ArrayBuilderSegment? Possibly a Blazor bug? return; } foreach (var edit in edits) { switch (edit.Type) { case RenderTreeEditType.PrependFrame: ApplyPrependFrame(batch, componentId, edit.SiblingIndex, referenceFrames.Array, edit.ReferenceFrameIndex); break; case RenderTreeEditType.RemoveFrame: ApplyRemoveFrame(edit.SiblingIndex); break; case RenderTreeEditType.SetAttribute: ApplySetAttribute(ref referenceFrames.Array[edit.ReferenceFrameIndex]); break; case RenderTreeEditType.RemoveAttribute: // TODO: See whether siblingIndex is needed here ApplyRemoveAttribute(edit.RemovedAttributeName); break; case RenderTreeEditType.UpdateText: { var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; if (_targetElement is IHandleChildContentText handleChildContentText) { handleChildContentText.HandleText(edit.SiblingIndex, frame.TextContent); } else { throw new Exception("Cannot set text content on child that doesn't handle inner text content."); } break; } case RenderTreeEditType.StepIn: { // TODO: Need to implement this. For now it seems safe to ignore. break; } case RenderTreeEditType.StepOut: { // TODO: Need to implement this. For now it seems safe to ignore. break; } case RenderTreeEditType.UpdateMarkup: { var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; if (_targetElement is IHandleChildContentText handleChildContentText) { handleChildContentText.HandleText(edit.SiblingIndex, frame.MarkupContent); } else { throw new Exception("Cannot set markup content on child that doesn't handle inner text content."); } break; } case RenderTreeEditType.PermutationListEntry: throw new NotImplementedException($"Not supported edit type: {edit.Type}"); case RenderTreeEditType.PermutationListEnd: throw new NotImplementedException($"Not supported edit type: {edit.Type}"); default: throw new NotImplementedException($"Invalid edit type: {edit.Type}"); } } }
private void LoadMap(string map, int centerx, int centery, int distance) { float TileSize = 1600.0f / 3.0f; //533.333 float ChunkSize = TileSize / 16.0f; //33.333 float UnitSize = ChunkSize / 8.0f; //4.166666 // ~~fun fact time with marlamin~~ this times 0.5 ends up being pixelspercoord on minimap float MapMidPoint = 32.0f / ChunkSize; GL.EnableClientState(ArrayCap.VertexArray); GL.EnableClientState(ArrayCap.NormalArray); List<Vertex> verticelist = new List<Vertex>(); List<Int32> indicelist = new List<Int32>(); GL.Enable(EnableCap.Texture2D); for (int x = centerx; x < centerx + distance; x++) { for (int y = centery; y < centery + distance; y++) { string filename = "World/Maps/" + map + "/" + map + "_" + y + "_" + x + ".adt"; if (WoWFormatLib.Utils.CASC.FileExists(filename)) { ADTReader reader = new ADTReader(); reader.LoadADT(filename); Terrain adt = new Terrain(); adt.vertexBuffer = GL.GenBuffer(); adt.indiceBuffer = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, adt.vertexBuffer); GL.BindBuffer(BufferTarget.ElementArrayBuffer, adt.indiceBuffer); List<Material> materials = new List<Material>(); //Check if textures are already loaded or not, multiple ADTs close together probably use the same ones mostly for (int ti = 0; ti < reader.adtfile.textures.filenames.Count(); ti++) { Material material = new Material(); material.filename = reader.adtfile.textures.filenames[ti]; //if (!WoWFormatLib.Utils.CASC.FileExists(material.filename)) { continue; } material.textureID = BLPLoader.LoadTexture(reader.adtfile.textures.filenames[ti], cache); materials.Add(material); } var initialChunkY = reader.adtfile.chunks[0].header.position.Y; var initialChunkX = reader.adtfile.chunks[0].header.position.X; /* if(firstLocation.X == 0) { firstLocation = new Vector3(initialChunkY, initialChunkX, 1.0f); Console.WriteLine("Setting first location to " + firstLocation.ToString()); } */ List<RenderBatch> renderBatches = new List<RenderBatch>(); for (uint c = 0; c < reader.adtfile.chunks.Count(); c++) { var chunk = reader.adtfile.chunks[c]; int off = verticelist.Count(); RenderBatch batch = new RenderBatch(); for (int i = 0, idx = 0; i < 17; i++) { for (int j = 0; j < (((i % 2) != 0) ? 8 : 9); j++) { //var v = new Vector3(chunk.header.position.Y - (j * UnitSize), chunk.vertices.vertices[idx++] + chunk.header.position.Z, -(chunk.header.position.X - (i * UnitSize * 0.5f))); Vertex v = new Vertex(); v.Normal = new Vector3(chunk.normals.normal_0[idx], chunk.normals.normal_1[idx], chunk.normals.normal_2[idx]); if (chunk.vertexShading.red != null && chunk.vertexShading.red[idx] != 127) { v.Color = new Vector3(chunk.vertexShading.blue[idx] / 255.0f, chunk.vertexShading.green[idx] / 255.0f, chunk.vertexShading.red[idx] / 255.0f); //v.Color = new Vector3(1.0f, 1.0f, 1.0f); } else { v.Color = new Vector3(1.0f, 1.0f, 1.0f); } v.TexCoord = new Vector2(((float)j + (((i % 2) != 0) ? 0.5f : 0f)) / 8f, ((float)i * 0.5f) / 8f); v.Position = new Vector3(chunk.header.position.Y - (j * UnitSize), chunk.vertices.vertices[idx++] + chunk.header.position.Z, chunk.header.position.X - (i * UnitSize * 0.5f)); if ((i % 2) != 0) v.Position.X -= 0.5f * UnitSize; verticelist.Add(v); } } batch.firstFace = (uint)indicelist.Count(); for (int j = 9; j < 145; j++) { indicelist.AddRange(new Int32[] { off + j + 8, off + j - 9, off + j }); indicelist.AddRange(new Int32[] { off + j - 9, off + j - 8, off + j }); indicelist.AddRange(new Int32[] { off + j - 8, off + j + 9, off + j }); indicelist.AddRange(new Int32[] { off + j + 9, off + j + 8, off + j }); if ((j + 1) % (9 + 8) == 0) j += 9; } batch.numFaces = (uint)(indicelist.Count()) - batch.firstFace; if (!cache.materials.ContainsKey(reader.adtfile.textures.filenames[reader.adtfile.texChunks[c].layers[0].textureId].ToLower())) { throw new Exception("MaterialCache does not have texture " + reader.adtfile.textures.filenames[reader.adtfile.texChunks[c].layers[0].textureId].ToLower()); } var layermats = new List<uint>(); var alphalayermats = new List<int>(); for (int li = 0; li < reader.adtfile.texChunks[c].layers.Count(); li++) { if(reader.adtfile.texChunks[c].alphaLayer != null){ alphalayermats.Add(BLPLoader.GenerateAlphaTexture(reader.adtfile.texChunks[c].alphaLayer[li].layer)); } layermats.Add((uint)cache.materials[reader.adtfile.textures.filenames[reader.adtfile.texChunks[c].layers[li].textureId].ToLower()]); } batch.materialID = layermats.ToArray(); batch.alphaMaterialID = alphalayermats.ToArray(); renderBatches.Add(batch); } List<Doodad> doodads = new List<Doodad>(); for (int mi = 0; mi < reader.adtfile.objects.models.entries.Count(); mi++) { Console.WriteLine("Loading model #" + mi); var modelentry = reader.adtfile.objects.models.entries[mi]; var mmid = reader.adtfile.objects.m2NameOffsets.offsets[modelentry.mmidEntry]; var modelfilename = ""; for (int mmi = 0; mmi < reader.adtfile.objects.m2Names.offsets.Count(); mmi++) { if (reader.adtfile.objects.m2Names.offsets[mmi] == mmid) { modelfilename = reader.adtfile.objects.m2Names.filenames[mmi].ToLower(); } } var doodad = new Doodad(); doodad.filename = modelfilename; doodad.position = new Vector3(-(modelentry.position.X - 17066), modelentry.position.Y, -(modelentry.position.Z - 17066)); doodad.rotation = new Vector3(modelentry.rotation.X, modelentry.rotation.Y, modelentry.rotation.Z); doodad.scale = modelentry.scale; doodads.Add(doodad); if (cache.doodadBatches.ContainsKey(modelfilename)) { continue; } M2Loader.LoadM2(modelfilename, cache); } List<WorldModelBatch> worldModelBatches = new List<WorldModelBatch>(); // WMO loading goes here for (int wmi = 0; wmi < reader.adtfile.objects.worldModels.entries.Count(); wmi++) { Console.WriteLine("Loading WMO #" + wmi); string wmofilename = ""; var wmodelentry = reader.adtfile.objects.worldModels.entries[wmi]; var mwid = reader.adtfile.objects.wmoNameOffsets.offsets[wmodelentry.mwidEntry]; for (int wmfi = 0; wmfi < reader.adtfile.objects.wmoNames.offsets.Count(); wmfi++) { if (reader.adtfile.objects.wmoNames.offsets[wmfi] == mwid) { wmofilename = reader.adtfile.objects.wmoNames.filenames[wmfi].ToLower(); } } if (wmofilename.Length == 0) { throw new Exception("Unable to find filename for WMO!"); } WorldModelBatch wmobatch = new WorldModelBatch(); wmobatch.position = new Vector3(-(wmodelentry.position.X - 17066), wmodelentry.position.Y, -(wmodelentry.position.Z - 17066)); wmobatch.rotation = new Vector3(wmodelentry.rotation.X, wmodelentry.rotation.Y, wmodelentry.rotation.Z); wmobatch.worldModel = WMOLoader.LoadWMO(wmofilename, cache); worldModelBatches.Add(wmobatch); } adt.renderBatches = renderBatches.ToArray(); adt.doodads = doodads.ToArray(); adt.worldModelBatches = worldModelBatches.ToArray(); int[] indices = indicelist.ToArray(); Vertex[] vertices = verticelist.ToArray(); Console.WriteLine("Vertices in array: " + vertices.Count()); //37120, correct //indices = indicelist.ToArray(); Console.WriteLine("Indices in array: " + indices.Count()); //196608, should be 65.5k which is 196608 / 3. in triangles so its correct? GL.BindBuffer(BufferTarget.ArrayBuffer, adt.vertexBuffer); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Count() * 11 * sizeof(float)), vertices, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ElementArrayBuffer, adt.indiceBuffer); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Length * sizeof(int)), indices, BufferUsageHint.StaticDraw); int verticeBufferSize = 0; int indiceBufferSize = 0; GL.BindBuffer(BufferTarget.ArrayBuffer, adt.vertexBuffer); GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out verticeBufferSize); GL.BindBuffer(BufferTarget.ArrayBuffer, adt.indiceBuffer); GL.GetBufferParameter(BufferTarget.ElementArrayBuffer, BufferParameterName.BufferSize, out indiceBufferSize); Console.WriteLine("Vertices in buffer: " + verticeBufferSize / 11 / sizeof(float)); Console.WriteLine("Indices in buffer: " + indiceBufferSize / sizeof(int)); adts.Add(adt); } } } }
private List<J3DRenderer.VertexFormatLayout> BuildVertexArraysFromFile() { List<J3DRenderer.VertexFormatLayout> finalData = new List<J3DRenderer.VertexFormatLayout>(); //Now, let's try to get our data. for (uint i = 0; i < _file.Shapes.GetBatchCount(); i++) { J3DFormat.Batch batch = _file.Shapes.GetBatch(i); RenderBatch renderBatch = new RenderBatch(); _renderList.Add(renderBatch); //Console.WriteLine("[{0}] Unk0: {5}, Attb: {6} Mtx Type: {1} #Packets {2}[{3}] Matrix Index: {4}", i, batch.MatrixType, batch.PacketCount, batch.PacketIndex, batch.FirstMatrixIndex, batch.Unknown0, batch.AttribOffset); uint attributeCount = 0; for (uint attribIndex = 0; attribIndex < 13; attribIndex++) { J3DFormat.BatchAttribute attrib = _file.Shapes.GetAttribute(attribIndex, batch.AttribOffset); if (attrib.AttribType == J3DFormat.ArrayTypes.NullAttr) break; attributeCount++; } for (ushort p = 0; p < batch.PacketCount; p++) { RenderPacket renderPacket = new RenderPacket(); renderBatch.Packets.Add(renderPacket); //Matrix Data J3DFormat.PacketMatrixData pmd = _file.Shapes.GetPacketMatrixData((ushort)(batch.FirstMatrixIndex + p)); renderPacket.DrawIndexes = new ushort[pmd.Count]; for (ushort mtx = 0; mtx < pmd.Count; mtx++) { //Console.WriteLine("{4} {0} Packet: {1} Index: {2} PMD Unknown: {3}", i, p, _file.Shapes.GetMatrixTableIndex((ushort) (pmd.FirstIndex + mtx)), pmd.Unknown, mtx); renderPacket.DrawIndexes[mtx] = _file.Shapes.GetMatrixTableIndex((ushort)(pmd.FirstIndex + mtx)); } J3DFormat.BatchPacketLocation packetLoc = _file.Shapes.GetBatchPacketLocation((ushort)(batch.PacketIndex + p)); uint numPrimitiveBytesRead = packetLoc.Offset; while (numPrimitiveBytesRead < packetLoc.Offset + packetLoc.PacketSize) { J3DFormat.BatchPrimitive primitive = _file.Shapes.GetPrimitive(numPrimitiveBytesRead); numPrimitiveBytesRead += J3DFormat.BatchPrimitive.Size; //Game pads the chunks out with zeros, so this is signal for early break. if (primitive.Type == 0) { break; } var primList = new PrimitiveList(); primList.VertexCount = primitive.VertexCount; primList.VertexStart = finalData.Count; primList.DrawType = primitive.Type == J3DFormat.PrimitiveTypes.TriangleStrip ? PrimitiveType.TriangleStrip : PrimitiveType.TriangleFan; //Todo: More support renderPacket.PrimList.Add(primList); for (int vert = 0; vert < primitive.VertexCount; vert++) { J3DRenderer.VertexFormatLayout newVertex = new J3DRenderer.VertexFormatLayout(); for (uint vertIndex = 0; vertIndex < attributeCount; vertIndex++) { var batchAttrib = _file.Shapes.GetAttribute(vertIndex, batch.AttribOffset); ushort curIndex = _file.Shapes.GetPrimitiveIndex(numPrimitiveBytesRead, batchAttrib); switch (batchAttrib.AttribType) { case J3DFormat.ArrayTypes.Position: newVertex.Position = _file.Vertexes.GetPosition(curIndex); break; case J3DFormat.ArrayTypes.Normal: newVertex.Color = new Vector4(_file.Vertexes.GetNormal(curIndex, 14), 1); //temp break; case J3DFormat.ArrayTypes.Color0: newVertex.Color = _file.Vertexes.GetColor0(curIndex); break; case J3DFormat.ArrayTypes.Tex0: newVertex.TexCoord = _file.Vertexes.GetTex0(curIndex, 8); break; case J3DFormat.ArrayTypes.PositionMatrixIndex: //Console.WriteLine("B: {0} P: {1} Prim: {2} Vert{3} Index: {4}", i, p, renderPacket.PrimList.Count, vert, curIndex); primList.PosMatrixIndex.Add(curIndex); break; default: Console.WriteLine("Unknown AttribType {0}, Index: {1}", batchAttrib.AttribType, curIndex); break; } numPrimitiveBytesRead += GetAttribElementSize(batchAttrib.DataType); } //Add our vertex to our list of Vertexes finalData.Add(newVertex); } //Console.WriteLine("Batch {0} Prim {1} #Vertices with PosMtxIndex: {2}", i, p, primList.PosMatrixIndex.Count); } } //Console.WriteLine("Finished batch {0}, triangleStrip count: {1}", i, _renderList.Count); } return finalData; }
private void LoadMap(string map, int centerx, int centery, int distance) { float TileSize = 1600.0f / 3.0f; //533.333 float ChunkSize = TileSize / 16.0f; //33.333 float UnitSize = ChunkSize / 8.0f; //4.166666 // ~~fun fact time with marlamin~~ this times 0.5 ends up being pixelspercoord on minimap float MapMidPoint = 32.0f / ChunkSize; GL.EnableClientState(ArrayCap.VertexArray); GL.EnableClientState(ArrayCap.NormalArray); List <Vertex> verticelist = new List <Vertex>(); List <Int32> indicelist = new List <Int32>(); GL.Enable(EnableCap.Texture2D); worker.ReportProgress(0, "Loading ADT.."); for (int x = centerx; x < centerx + distance; x++) { for (int y = centery; y < centery + distance; y++) { string filename = "world\\maps\\" + map + "\\" + map + "_" + y + "_" + x + ".adt"; if (WoWFormatLib.Utils.CASC.FileExists(filename)) { ADTReader reader = new ADTReader(); reader.LoadADT(filename); Terrain adt = new Terrain(); adt.vertexBuffer = GL.GenBuffer(); adt.indiceBuffer = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, adt.vertexBuffer); GL.BindBuffer(BufferTarget.ElementArrayBuffer, adt.indiceBuffer); List <Material> materials = new List <Material>(); //Check if textures are already loaded or not, multiple ADTs close together probably use the same ones mostly //for (int ti = 0; ti < reader.adtfile.textures.filenames.Count(); ti++) //{ /* * Material material = new Material(); * material.filename = reader.adtfile.textures.filenames[ti]; * material.textureID = BLPLoader.LoadTexture(reader.adtfile.textures.filenames[ti], cache);*/ /* MAPTEXTURE TEXTURE HACKFIX STUFF STARTS HERE */ Material material = new Material(); material.filename = filename.Replace("maps", "maptextures").Replace(".adt", ".blp"); material.textureID = BLPLoader.LoadTexture(filename.Replace("maps", "maptextures").Replace(".adt", ".blp"), cache); /* MAPTEXTURE TEXTURE HACKFIX STUFF STOPS HERE */ materials.Add(material); //} var initialChunkY = reader.adtfile.chunks[0].header.position.Y; var initialChunkX = reader.adtfile.chunks[0].header.position.X; List <RenderBatch> renderBatches = new List <RenderBatch>(); for (uint c = 0; c < reader.adtfile.chunks.Count(); c++) { var chunk = reader.adtfile.chunks[c]; int off = verticelist.Count(); RenderBatch batch = new RenderBatch(); for (int i = 0, idx = 0; i < 17; i++) { for (int j = 0; j < (((i % 2) != 0) ? 8 : 9); j++) { //var v = new Vector3(chunk.header.position.Y - (j * UnitSize), chunk.vertices.vertices[idx++] + chunk.header.position.Z, -(chunk.header.position.X - (i * UnitSize * 0.5f))); Vertex v = new Vertex(); v.Normal = new Vector3(chunk.normals.normal_0[idx], chunk.normals.normal_1[idx], chunk.normals.normal_2[idx]); if (chunk.vertexShading.red != null && chunk.vertexShading.red[idx] != 127) { v.Color = new Vector3(chunk.vertexShading.blue[idx] / 255.0f, chunk.vertexShading.green[idx] / 255.0f, chunk.vertexShading.red[idx] / 255.0f); //v.Color = new Vector3(1.0f, 1.0f, 1.0f); } else { v.Color = new Vector3(1.0f, 1.0f, 1.0f); } // Commented out for maptexture hack //v.TexCoord = new Vector2(((float)j + (((i % 2) != 0) ? 0.5f : 0f)) / 8f, ((float)i * 0.5f) / 8f); v.Position = new Vector3(chunk.header.position.X - (i * UnitSize * 0.5f), chunk.header.position.Y - (j * UnitSize), chunk.vertices.vertices[idx++] + chunk.header.position.Z); if ((i % 2) != 0) { v.Position.Y -= 0.5f * UnitSize; } //Maptexture hackfix v.TexCoord = new Vector2(-(v.Position.Y - initialChunkX) / TileSize, -(v.Position.X - initialChunkY) / TileSize); verticelist.Add(v); } } batch.firstFace = (uint)indicelist.Count(); for (int j = 9; j < 145; j++) { indicelist.AddRange(new Int32[] { off + j + 8, off + j - 9, off + j }); indicelist.AddRange(new Int32[] { off + j - 9, off + j - 8, off + j }); indicelist.AddRange(new Int32[] { off + j - 8, off + j + 9, off + j }); indicelist.AddRange(new Int32[] { off + j + 9, off + j + 8, off + j }); if ((j + 1) % (9 + 8) == 0) { j += 9; } } batch.numFaces = (uint)(indicelist.Count()) - batch.firstFace; //if (!cache.materials.ContainsKey(reader.adtfile.textures.filenames[reader.adtfile.texChunks[c].layers[0].textureId].ToLower())) //{ // throw new Exception("MaterialCache does not have texture " + reader.adtfile.textures.filenames[reader.adtfile.texChunks[c].layers[0].textureId].ToLower()); //} //Commented out for maptexture hackfix /* * var layermats = new List<uint>(); * var alphalayermats = new List<int>(); * * for (int li = 0; li < reader.adtfile.texChunks[c].layers.Count(); li++) * { * if(reader.adtfile.texChunks[c].alphaLayer != null){ * alphalayermats.Add(BLPLoader.GenerateAlphaTexture(reader.adtfile.texChunks[c].alphaLayer[li].layer)); * } * layermats.Add((uint)cache.materials[reader.adtfile.textures.filenames[reader.adtfile.texChunks[c].layers[li].textureId].ToLower()]); * } * * batch.materialID = layermats.ToArray(); * batch.alphaMaterialID = alphalayermats.ToArray(); * */ var layermats = new List <uint>(); layermats.Add((uint)material.textureID); batch.materialID = layermats.ToArray(); renderBatches.Add(batch); } List <Doodad> doodads = new List <Doodad>(); for (int mi = 0; mi < reader.adtfile.objects.models.entries.Count(); mi++) { Console.WriteLine("Loading model #" + mi); var modelentry = reader.adtfile.objects.models.entries[mi]; var mmid = reader.adtfile.objects.m2NameOffsets.offsets[modelentry.mmidEntry]; var modelfilename = ""; for (int mmi = 0; mmi < reader.adtfile.objects.m2Names.offsets.Count(); mmi++) { if (reader.adtfile.objects.m2Names.offsets[mmi] == mmid) { modelfilename = reader.adtfile.objects.m2Names.filenames[mmi].ToLower(); } } var doodad = new Doodad(); doodad.filename = modelfilename; doodad.position = new Vector3(-(modelentry.position.X - 17066), modelentry.position.Y, -(modelentry.position.Z - 17066)); doodad.rotation = new Vector3(modelentry.rotation.X, modelentry.rotation.Y, modelentry.rotation.Z); doodad.scale = modelentry.scale; doodads.Add(doodad); if (cache.doodadBatches.ContainsKey(modelfilename)) { continue; } M2Loader.LoadM2(modelfilename, cache); } List <WorldModelBatch> worldModelBatches = new List <WorldModelBatch>(); // WMO loading goes here for (int wmi = 0; wmi < reader.adtfile.objects.worldModels.entries.Count(); wmi++) { Console.WriteLine("Loading WMO #" + wmi); string wmofilename = ""; var wmodelentry = reader.adtfile.objects.worldModels.entries[wmi]; var mwid = reader.adtfile.objects.wmoNameOffsets.offsets[wmodelentry.mwidEntry]; for (int wmfi = 0; wmfi < reader.adtfile.objects.wmoNames.offsets.Count(); wmfi++) { if (reader.adtfile.objects.wmoNames.offsets[wmfi] == mwid) { wmofilename = reader.adtfile.objects.wmoNames.filenames[wmfi].ToLower(); } } if (wmofilename.Length == 0) { throw new Exception("Unable to find filename for WMO!"); } WorldModelBatch wmobatch = new WorldModelBatch(); wmobatch.position = new Vector3(-(wmodelentry.position.X - 17066.666f), wmodelentry.position.Y, -(wmodelentry.position.Z - 17066.666f)); wmobatch.rotation = new Vector3(wmodelentry.rotation.X, wmodelentry.rotation.Y, wmodelentry.rotation.Z); wmobatch.worldModel = WMOLoader.LoadWMO(wmofilename, cache); worldModelBatches.Add(wmobatch); } adt.renderBatches = renderBatches.ToArray(); adt.doodads = doodads.ToArray(); adt.worldModelBatches = worldModelBatches.ToArray(); int[] indices = indicelist.ToArray(); Vertex[] vertices = verticelist.ToArray(); Console.WriteLine("Vertices in array: " + vertices.Count()); //37120, correct //indices = indicelist.ToArray(); Console.WriteLine("Indices in array: " + indices.Count()); //196608, should be 65.5k which is 196608 / 3. in triangles so its correct? GL.BindBuffer(BufferTarget.ArrayBuffer, adt.vertexBuffer); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Count() * 11 * sizeof(float)), vertices, BufferUsageHint.StaticDraw); GL.BindBuffer(BufferTarget.ElementArrayBuffer, adt.indiceBuffer); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Length * sizeof(int)), indices, BufferUsageHint.StaticDraw); int verticeBufferSize = 0; int indiceBufferSize = 0; GL.BindBuffer(BufferTarget.ArrayBuffer, adt.vertexBuffer); GL.GetBufferParameter(BufferTarget.ArrayBuffer, BufferParameterName.BufferSize, out verticeBufferSize); GL.BindBuffer(BufferTarget.ArrayBuffer, adt.indiceBuffer); GL.GetBufferParameter(BufferTarget.ElementArrayBuffer, BufferParameterName.BufferSize, out indiceBufferSize); Console.WriteLine("Vertices in buffer: " + verticeBufferSize / 11 / sizeof(float)); Console.WriteLine("Indices in buffer: " + indiceBufferSize / sizeof(int)); adts.Add(adt); } } } }
public static Terrain LoadADT(string filename, CacheStorage cache, int shaderProgram, bool loadModels = false) { var adt = new WoWFormatLib.Structs.ADT.ADT(); var result = new Terrain(); //Load ADT from file if (WoWFormatLib.Utils.CASC.FileExists(filename)) { var adtreader = new ADTReader(); adtreader.LoadADT(filename); adt = adtreader.adtfile; } else { throw new Exception("ADT " + filename + " does not exist!"); } var TileSize = 1600.0f / 3.0f; //533.333 var ChunkSize = TileSize / 16.0f; //33.333 var UnitSize = ChunkSize / 8.0f; //4.166666 var MapMidPoint = 32.0f / ChunkSize; var verticelist = new List <Vertex>(); var indicelist = new List <int>(); result.vao = GL.GenVertexArray(); GL.BindVertexArray(result.vao); result.vertexBuffer = GL.GenBuffer(); result.indiceBuffer = GL.GenBuffer(); var materials = new List <Material>(); if (adt.textures.filenames == null) { for (var ti = 0; ti < adt.diffuseTextureFileDataIDs.Count(); ti++) { var material = new Material(); material.filename = adt.diffuseTextureFileDataIDs[ti].ToString(); material.textureID = BLPLoader.LoadTexture(adt.diffuseTextureFileDataIDs[ti], cache); if (adt.texParams != null && adt.texParams.Count() >= ti) { material.scale = (float)Math.Pow(2, (adt.texParams[ti].flags & 0xF0) >> 4); if (adt.texParams[ti].height != 0.0 || adt.texParams[ti].offset != 1.0) { material.heightScale = adt.texParams[ti].height; material.heightOffset = adt.texParams[ti].offset; if (!WoWFormatLib.Utils.CASC.FileExists(adt.heightTextureFileDataIDs[ti])) { Console.WriteLine("Height texture: " + adt.heightTextureFileDataIDs[ti] + " does not exist! Falling back to original texture (hack).."); material.heightTexture = BLPLoader.LoadTexture(adt.diffuseTextureFileDataIDs[ti], cache); } else { material.heightTexture = BLPLoader.LoadTexture(adt.heightTextureFileDataIDs[ti], cache); } } else { material.heightScale = 0.0f; material.heightOffset = 1.0f; } } else { material.heightScale = 0.0f; material.heightOffset = 1.0f; material.scale = 1.0f; } materials.Add(material); } } else { for (var ti = 0; ti < adt.textures.filenames.Count(); ti++) { var material = new Material(); material.filename = adt.textures.filenames[ti]; material.textureID = BLPLoader.LoadTexture(adt.textures.filenames[ti], cache); if (adt.texParams != null && adt.texParams.Count() >= ti) { material.scale = (float)Math.Pow(2, (adt.texParams[ti].flags & 0xF0) >> 4); if (adt.texParams[ti].height != 0.0 || adt.texParams[ti].offset != 1.0) { material.heightScale = adt.texParams[ti].height; material.heightOffset = adt.texParams[ti].offset; var heightName = adt.textures.filenames[ti].Replace(".blp", "_h.blp"); if (!WoWFormatLib.Utils.CASC.FileExists(heightName)) { Console.WriteLine("Height texture: " + heightName + " does not exist! Falling back to original texture (hack).."); material.heightTexture = BLPLoader.LoadTexture(adt.textures.filenames[ti], cache); } else { material.heightTexture = BLPLoader.LoadTexture(heightName, cache); } } else { material.heightScale = 0.0f; material.heightOffset = 1.0f; } } else { material.heightScale = 0.0f; material.heightOffset = 1.0f; material.scale = 1.0f; } materials.Add(material); } } var initialChunkY = adt.chunks[0].header.position.Y; var initialChunkX = adt.chunks[0].header.position.X; var renderBatches = new List <RenderBatch>(); for (uint c = 0; c < adt.chunks.Count(); c++) { var chunk = adt.chunks[c]; var off = verticelist.Count(); var batch = new RenderBatch(); batch.groupID = c; for (int i = 0, idx = 0; i < 17; i++) { for (var j = 0; j < (((i % 2) != 0) ? 8 : 9); j++) { var v = new Vertex(); v.Normal = new Vector3(chunk.normals.normal_0[idx], chunk.normals.normal_1[idx], chunk.normals.normal_2[idx]); if (chunk.vertexShading.red != null) { v.Color = new Vector4(chunk.vertexShading.blue[idx] / 255.0f, chunk.vertexShading.green[idx] / 255.0f, chunk.vertexShading.red[idx] / 255.0f, chunk.vertexShading.alpha[idx] / 255.0f); } else { v.Color = new Vector4(0.5f, 0.5f, 0.5f, 1.0f); } v.TexCoord = new Vector2((j + (((i % 2) != 0) ? 0.5f : 0f)) / 8f, (i * 0.5f) / 8f); v.Position = new Vector3(chunk.header.position.X - (i * UnitSize * 0.5f), chunk.header.position.Y - (j * UnitSize), chunk.vertices.vertices[idx++] + chunk.header.position.Z); if ((i % 2) != 0) { v.Position.Y -= 0.5f * UnitSize; } verticelist.Add(v); } } result.startPos = verticelist[0]; batch.firstFace = (uint)indicelist.Count(); for (var j = 9; j < 145; j++) { indicelist.AddRange(new int[] { off + j + 8, off + j - 9, off + j }); indicelist.AddRange(new int[] { off + j - 9, off + j - 8, off + j }); indicelist.AddRange(new int[] { off + j - 8, off + j + 9, off + j }); indicelist.AddRange(new int[] { off + j + 9, off + j + 8, off + j }); if ((j + 1) % (9 + 8) == 0) { j += 9; } } batch.numFaces = (uint)(indicelist.Count()) - batch.firstFace; var layermats = new List <uint>(); var alphalayermats = new List <int>(); var layerscales = new List <float>(); var layerheights = new List <int>(); batch.heightScales = new Vector4(); batch.heightOffsets = new Vector4(); for (var li = 0; li < adt.texChunks[c].layers.Count(); li++) { if (adt.texChunks[c].alphaLayer != null) { alphalayermats.Add(BLPLoader.GenerateAlphaTexture(adt.texChunks[c].alphaLayer[li].layer)); } layermats.Add((uint)cache.materials[adt.diffuseTextureFileDataIDs[adt.texChunks[c].layers[li].textureId]]); var curMat = materials.Where(material => material.filename == adt.diffuseTextureFileDataIDs[adt.texChunks[c].layers[li].textureId].ToString()).Single(); layerscales.Add(curMat.scale); layerheights.Add(curMat.heightTexture); batch.heightScales[li] = curMat.heightScale; batch.heightOffsets[li] = curMat.heightOffset; } batch.materialID = layermats.ToArray(); batch.alphaMaterialID = alphalayermats.ToArray(); batch.scales = layerscales.ToArray(); batch.heightMaterialIDs = layerheights.ToArray(); var indices = indicelist.ToArray(); var vertices = verticelist.ToArray(); GL.BindBuffer(BufferTarget.ArrayBuffer, result.vertexBuffer); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Count() * 12 * sizeof(float)), vertices, BufferUsageHint.StaticDraw); //var normalAttrib = GL.GetAttribLocation(shaderProgram, "normal"); //GL.EnableVertexAttribArray(normalAttrib); //GL.VertexAttribPointer(normalAttrib, 3, VertexAttribPointerType.Float, false, sizeof(float) * 11, sizeof(float) * 0); var colorAttrib = GL.GetAttribLocation(shaderProgram, "color"); GL.EnableVertexAttribArray(colorAttrib); GL.VertexAttribPointer(colorAttrib, 4, VertexAttribPointerType.Float, false, sizeof(float) * 12, sizeof(float) * 3); var texCoordAttrib = GL.GetAttribLocation(shaderProgram, "texCoord"); GL.EnableVertexAttribArray(texCoordAttrib); GL.VertexAttribPointer(texCoordAttrib, 2, VertexAttribPointerType.Float, false, sizeof(float) * 12, sizeof(float) * 7); var posAttrib = GL.GetAttribLocation(shaderProgram, "position"); GL.EnableVertexAttribArray(posAttrib); GL.VertexAttribPointer(posAttrib, 3, VertexAttribPointerType.Float, false, sizeof(float) * 12, sizeof(float) * 9); GL.BindBuffer(BufferTarget.ElementArrayBuffer, result.indiceBuffer); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Length * sizeof(int)), indices, BufferUsageHint.StaticDraw); renderBatches.Add(batch); } var doodads = new List <Doodad>(); var worldModelBatches = new List <WorldModelBatch>(); if (loadModels) { for (var mi = 0; mi < adt.objects.models.entries.Count(); mi++) { Console.WriteLine("Loading model #" + mi); var modelentry = adt.objects.models.entries[mi]; var mmid = adt.objects.m2NameOffsets.offsets[modelentry.mmidEntry]; var modelfilename = ""; for (var mmi = 0; mmi < adt.objects.m2Names.offsets.Count(); mmi++) { if (adt.objects.m2Names.offsets[mmi] == mmid) { modelfilename = adt.objects.m2Names.filenames[mmi].ToLower(); break; } } doodads.Add(new Doodad { filename = modelfilename, position = new Vector3(-(modelentry.position.X - 17066), modelentry.position.Y, -(modelentry.position.Z - 17066)), rotation = new Vector3(modelentry.rotation.X, modelentry.rotation.Y, modelentry.rotation.Z), scale = modelentry.scale }); if (!cache.doodadBatches.ContainsKey(modelfilename)) { M2Loader.LoadM2(modelfilename, cache, shaderProgram); } } for (var wmi = 0; wmi < adt.objects.worldModels.entries.Count(); wmi++) { var wmofilename = ""; var wmodelentry = adt.objects.worldModels.entries[wmi]; var mwid = adt.objects.wmoNameOffsets.offsets[wmodelentry.mwidEntry]; for (var wmfi = 0; wmfi < adt.objects.wmoNames.offsets.Count(); wmfi++) { if (adt.objects.wmoNames.offsets[wmfi] == mwid) { wmofilename = adt.objects.wmoNames.filenames[wmfi].ToLower(); break; } } if (wmofilename.Length == 0) { throw new Exception("Unable to find filename for WMO!"); } if (!cache.worldModelBatches.ContainsKey(wmofilename)) { WMOLoader.LoadWMO(wmofilename, cache, shaderProgram); } worldModelBatches.Add(new WorldModelBatch { position = new Vector3(-(wmodelentry.position.X - 17066.666f), wmodelentry.position.Y, -(wmodelentry.position.Z - 17066.666f)), rotation = new Vector3(wmodelentry.rotation.X, wmodelentry.rotation.Y, wmodelentry.rotation.Z), worldModel = cache.worldModelBatches[wmofilename] }); } } result.renderBatches = renderBatches.ToArray(); result.doodads = doodads.ToArray(); result.worldModelBatches = worldModelBatches.ToArray(); cache.terrain.Add(filename, result); return(result); }
private List <J3DRenderer.VertexFormatLayout> BuildVertexArraysFromFile() { List <J3DRenderer.VertexFormatLayout> finalData = new List <J3DRenderer.VertexFormatLayout>(); //Now, let's try to get our data. for (uint i = 0; i < _file.Shapes.GetBatchCount(); i++) { J3DFormat.Batch batch = _file.Shapes.GetBatch(i); RenderBatch renderBatch = new RenderBatch(); _renderList.Add(renderBatch); //Console.WriteLine("[{0}] Unk0: {5}, Attb: {6} Mtx Type: {1} #Packets {2}[{3}] Matrix Index: {4}", i, batch.MatrixType, batch.PacketCount, batch.PacketIndex, batch.FirstMatrixIndex, batch.Unknown0, batch.AttribOffset); uint attributeCount = 0; for (uint attribIndex = 0; attribIndex < 13; attribIndex++) { J3DFormat.BatchAttribute attrib = _file.Shapes.GetAttribute(attribIndex, batch.AttribOffset); if (attrib.AttribType == J3DFormat.ArrayTypes.NullAttr) { break; } attributeCount++; } for (ushort p = 0; p < batch.PacketCount; p++) { RenderPacket renderPacket = new RenderPacket(); renderBatch.Packets.Add(renderPacket); //Matrix Data J3DFormat.PacketMatrixData pmd = _file.Shapes.GetPacketMatrixData((ushort)(batch.FirstMatrixIndex + p)); renderPacket.DrawIndexes = new ushort[pmd.Count]; for (ushort mtx = 0; mtx < pmd.Count; mtx++) { //Console.WriteLine("{4} {0} Packet: {1} Index: {2} PMD Unknown: {3}", i, p, _file.Shapes.GetMatrixTableIndex((ushort) (pmd.FirstIndex + mtx)), pmd.Unknown, mtx); renderPacket.DrawIndexes[mtx] = _file.Shapes.GetMatrixTableIndex((ushort)(pmd.FirstIndex + mtx)); } J3DFormat.BatchPacketLocation packetLoc = _file.Shapes.GetBatchPacketLocation((ushort)(batch.PacketIndex + p)); uint numPrimitiveBytesRead = packetLoc.Offset; while (numPrimitiveBytesRead < packetLoc.Offset + packetLoc.PacketSize) { J3DFormat.BatchPrimitive primitive = _file.Shapes.GetPrimitive(numPrimitiveBytesRead); numPrimitiveBytesRead += J3DFormat.BatchPrimitive.Size; //Game pads the chunks out with zeros, so this is signal for early break. if (primitive.Type == 0) { break; } var primList = new PrimitiveList(); primList.VertexCount = primitive.VertexCount; primList.VertexStart = finalData.Count; primList.DrawType = primitive.Type == J3DFormat.PrimitiveTypes.TriangleStrip ? PrimitiveType.TriangleStrip : PrimitiveType.TriangleFan; //Todo: More support renderPacket.PrimList.Add(primList); for (int vert = 0; vert < primitive.VertexCount; vert++) { J3DRenderer.VertexFormatLayout newVertex = new J3DRenderer.VertexFormatLayout(); for (uint vertIndex = 0; vertIndex < attributeCount; vertIndex++) { var batchAttrib = _file.Shapes.GetAttribute(vertIndex, batch.AttribOffset); ushort curIndex = _file.Shapes.GetPrimitiveIndex(numPrimitiveBytesRead, batchAttrib); switch (batchAttrib.AttribType) { case J3DFormat.ArrayTypes.Position: newVertex.Position = _file.Vertexes.GetPosition(curIndex); break; case J3DFormat.ArrayTypes.Normal: newVertex.Color = new Vector4(_file.Vertexes.GetNormal(curIndex, 14), 1); //temp break; case J3DFormat.ArrayTypes.Color0: newVertex.Color = _file.Vertexes.GetColor0(curIndex); break; case J3DFormat.ArrayTypes.Tex0: newVertex.TexCoord = _file.Vertexes.GetTex0(curIndex, 8); break; case J3DFormat.ArrayTypes.PositionMatrixIndex: //Console.WriteLine("B: {0} P: {1} Prim: {2} Vert{3} Index: {4}", i, p, renderPacket.PrimList.Count, vert, curIndex); primList.PosMatrixIndex.Add(curIndex); break; default: Console.WriteLine("Unknown AttribType {0}, Index: {1}", batchAttrib.AttribType, curIndex); break; } numPrimitiveBytesRead += GetAttribElementSize(batchAttrib.DataType); } //Add our vertex to our list of Vertexes finalData.Add(newVertex); } //Console.WriteLine("Batch {0} Prim {1} #Vertices with PosMtxIndex: {2}", i, p, primList.PosMatrixIndex.Count); } } //Console.WriteLine("Finished batch {0}, triangleStrip count: {1}", i, _renderList.Count); } return(finalData); }
public static CnkLOD LoadFromStream(string name, string displayName, MemoryStream stream) { CnkLOD chunk = new CnkLOD(); BinaryReader binaryReader = new BinaryReader(stream); chunk.Name = name; chunk.DisplayName = displayName; //Header byte[] magic = binaryReader.ReadBytes(4); if (magic[0] != 'C' || magic[1] != 'N' || magic[2] != 'K' /* || * magic[3] != '1'*/) { return(null); } chunk.Version = binaryReader.ReadUInt32(); if (!Enum.IsDefined(typeof(ChunkType), (int)chunk.Version)) { Debug.LogWarning("Could not decode chunk " + name + ". Unknown cnk version " + chunk.Version); return(null); } chunk.ChunkType = (ChunkType)chunk.Version; chunk.DecompressedSize = binaryReader.ReadUInt32(); chunk.CompressedSize = binaryReader.ReadUInt32(); //Decompression byte[] compressedBuffer = binaryReader.ReadBytes((int)chunk.CompressedSize); byte[] decompressedBuffer = new byte[chunk.DecompressedSize]; InflateReturnCode result = LzhamInterop.DecompressForgelightData(compressedBuffer, chunk.CompressedSize, decompressedBuffer, chunk.DecompressedSize); if (result != InflateReturnCode.LZHAM_Z_STREAM_END && result != InflateReturnCode.LZHAM_Z_OK) { //This chunk is invalid. return(null); } using (MemoryStream decompressedStream = new MemoryStream(decompressedBuffer)) { binaryReader = new BinaryReader(decompressedStream); //Textures uint textureCount = binaryReader.ReadUInt32(); chunk.Textures = new List <Texture>((int)textureCount); for (int i = 0; i < textureCount; i++) { Texture texture = new Texture(); uint colorNxMapSize = binaryReader.ReadUInt32(); if (colorNxMapSize > 0) { texture.ColorNXMap = binaryReader.ReadBytes((int)colorNxMapSize).ToList(); } uint specNyMapSize = binaryReader.ReadUInt32(); if (specNyMapSize > 0) { texture.SpecNyMap = binaryReader.ReadBytes((int)specNyMapSize).ToList(); } uint extraData1Size = binaryReader.ReadUInt32(); if (extraData1Size > 0) { texture.ExtraData1 = binaryReader.ReadBytes((int)extraData1Size).ToList(); } uint extraData2Size = binaryReader.ReadUInt32(); if (extraData2Size > 0) { texture.ExtraData2 = binaryReader.ReadBytes((int)extraData2Size).ToList(); } uint extraData3Size = binaryReader.ReadUInt32(); if (extraData3Size > 0) { texture.ExtraData3 = binaryReader.ReadBytes((int)extraData3Size).ToList(); } uint extraData4Size = binaryReader.ReadUInt32(); if (extraData4Size > 0) { texture.ExtraData4 = binaryReader.ReadBytes((int)extraData4Size).ToList(); } chunk.Textures.Add(texture); } //Verts Per Side chunk.VertsPerSide = binaryReader.ReadUInt32(); //Height Maps uint heightMapCount = binaryReader.ReadUInt32(); int n = (int)(heightMapCount / 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < n; j++) { Dictionary <int, HeightMap> entry; if (!chunk.HeightMaps.ContainsKey(i)) { entry = new Dictionary <int, HeightMap>(); chunk.HeightMaps[i] = entry; } else { entry = chunk.HeightMaps[i]; } HeightMap heightMapData = new HeightMap(); heightMapData.Val1 = binaryReader.ReadInt16(); heightMapData.Val2 = binaryReader.ReadByte(); heightMapData.Val3 = binaryReader.ReadByte(); entry[j] = heightMapData; } } //Indices uint indexCount = binaryReader.ReadUInt32(); chunk.Indices = new List <ushort>((int)indexCount); for (int i = 0; i < indexCount; i++) { chunk.Indices.Add(binaryReader.ReadUInt16()); } //Verts uint vertCount = binaryReader.ReadUInt32(); chunk.Vertices = new List <Vertex>((int)vertCount); for (int i = 0; i < vertCount; i++) { Vertex vertex = new Vertex(); vertex.X = binaryReader.ReadInt16(); vertex.Y = binaryReader.ReadInt16(); vertex.HeightFar = binaryReader.ReadInt16(); vertex.HeightNear = binaryReader.ReadInt16(); vertex.Color = binaryReader.ReadUInt32(); chunk.Vertices.Add(vertex); } //TODO HACK - Daybreak, why are some chunks (that have a version 2 header) actually version 1? long offset = binaryReader.BaseStream.Position; try { //Render Batches uint renderBatchCount = binaryReader.ReadUInt32(); chunk.RenderBatches = new List <RenderBatch>((int)renderBatchCount); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); if (chunk.ChunkType == ChunkType.H1Z1_Planetside2V2) { renderBatch.Unknown = binaryReader.ReadUInt32(); } renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); chunk.RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = binaryReader.ReadUInt32(); chunk.OptimizedDraws = new List <OptimizedDraw>((int)optimizedDrawCount); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = binaryReader.ReadBytes(320).ToList(); chunk.OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = binaryReader.ReadUInt32(); chunk.UnknownShorts1 = new List <ushort>((int)unknownShort1Count); for (int i = 0; i < unknownShort1Count; i++) { chunk.UnknownShorts1.Add(binaryReader.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = binaryReader.ReadUInt32(); chunk.UnknownVectors1 = new List <Vector3>((int)unknownVectors1Count); for (int i = 0; i < unknownVectors1Count; i++) { chunk.UnknownVectors1.Add(new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = binaryReader.ReadUInt32(); chunk.TileOccluderInfos = new List <TileOccluderInfo>((int)tileOccluderCount); for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = binaryReader.ReadBytes(64).ToList(); chunk.TileOccluderInfos.Add(tileOccluderInfo); } } catch (Exception) { binaryReader.BaseStream.Position = offset; //Render Batches uint renderBatchCount = binaryReader.ReadUInt32(); chunk.RenderBatches = new List <RenderBatch>((int)renderBatchCount); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); chunk.RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = binaryReader.ReadUInt32(); chunk.OptimizedDraws = new List <OptimizedDraw>((int)optimizedDrawCount); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = binaryReader.ReadBytes(320).ToList(); chunk.OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = binaryReader.ReadUInt32(); chunk.UnknownShorts1 = new List <ushort>((int)unknownShort1Count); for (int i = 0; i < unknownShort1Count; i++) { chunk.UnknownShorts1.Add(binaryReader.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = binaryReader.ReadUInt32(); chunk.UnknownVectors1 = new List <Vector3>((int)unknownVectors1Count); for (int i = 0; i < unknownVectors1Count; i++) { chunk.UnknownVectors1.Add(new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = binaryReader.ReadUInt32(); chunk.TileOccluderInfos = new List <TileOccluderInfo>((int)tileOccluderCount); for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = binaryReader.ReadBytes(64).ToList(); chunk.TileOccluderInfos.Add(tileOccluderInfo); } } } return(chunk); }
static void ReadMOBA(BinaryReader br, WMOGroup group, uint size) { // Render batches. Records of 24 bytes. group.Batches = new RenderBatch[size/24]; for (int i = 0; i < group.Batches.Length; i++) { var batch = new RenderBatch { BottomX = br.ReadInt16(), BottomY = br.ReadInt16(), BottomZ = br.ReadInt16(), TopX = br.ReadInt16(), TopY = br.ReadInt16(), TopZ = br.ReadInt16(), StartIndex = br.ReadInt32(), IndexCount = br.ReadUInt16(), VertexStart = br.ReadUInt16(), VertexEnd = br.ReadUInt16(), Byte_13 = br.ReadByte(), TextureIndex = br.ReadByte() }; group.Batches[i] = batch; } }
/// <summary> /// Initializes a new instance of the <see cref="OcclusionBuffer"/> class with the specified /// buffer size. /// </summary> /// <param name="graphicsService">The graphics service.</param> /// <param name="width">The width of the occlusion buffer.</param> /// <param name="height">The height of the occlusion buffer.</param> /// <param name="bufferSize"> /// The size of the internal triangle buffer (= max number of occluder triangles that can be /// rendered in a single draw call). Needs to be large enough to store the most complex /// occluder. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="graphicsService"/> is <see langword="null"/>. /// </exception> public OcclusionBuffer(IGraphicsService graphicsService, int width, int height, int bufferSize) { if (graphicsService == null) throw new ArgumentNullException("graphicsService"); // For simplicity only accept power-of-two formats. if (!MathHelper.IsPowerOf2(width) && !MathHelper.IsPowerOf2(height)) throw new ArgumentException("Width and height of occlusion buffer expected to be a power of two."); // The current texture atlas layout assumes that width ≥ height. if (width < height) throw new ArgumentException("Width expected to be greater than or equal to the height of the occlusion buffer."); var graphicsDevice = graphicsService.GraphicsDevice; if (bufferSize < 1) throw new ArgumentOutOfRangeException("bufferSize", "The buffer size needs to be creater than 1."); if (bufferSize >= graphicsDevice.GetMaxPrimitivesPerCall()) throw new ArgumentOutOfRangeException("bufferSize", "The buffer size exceeds the max number of primitives supported by the current graphics device."); // ----- RenderBatch handles occluders. // bufferSize is the max number of triangles per draw call. // Vertex buffer size: // - In the worst case n triangles need n * 3 vertices. // - The max size is limited to 65536 because 16-bit indices are used. var vertices = new Vector3F[Math.Min(bufferSize * 3, ushort.MaxValue + 1)]; // Index buffer size: number of triangles * 3 var indices = new ushort[bufferSize * 3]; _renderBatch = new RenderBatch<Vector3F, ushort>( graphicsDevice, VertexPosition.VertexDeclaration, vertices, true, indices, true); _effect = graphicsService.Content.Load<Effect>("DigitalRune/OcclusionCulling"); _parameterClampAabbMinimum = _effect.Parameters["ClampAabbMinimum"]; _parameterClampAabbMaximum = _effect.Parameters["ClampAabbMaximum"]; _parameterCameraViewProj = _effect.Parameters["CameraViewProj"]; _parameterCameraNear = _effect.Parameters["CameraNear"]; _parameterCameraFar = _effect.Parameters["CameraFar"]; _parameterCameraPosition = _effect.Parameters["CameraPosition"]; _parameterNormalizationFactor = _effect.Parameters["NormalizationFactor"]; _parameterLightViewProj = _effect.Parameters["LightViewProj"]; _parameterLightToCamera = _effect.Parameters["LightToCamera"]; _parameterHzbSize = _effect.Parameters["HzbSize"]; _parameterTargetSize = _effect.Parameters["TargetSize"]; _parameterAtlasSize = _effect.Parameters["AtlasSize"]; _parameterTexelOffset = _effect.Parameters["TexelOffset"]; _parameterHalfTexelOffset = _effect.Parameters["HalfTexelOffset"]; _parameterMaxLevel = _effect.Parameters["MaxLevel"]; _parameterHzbTexture = _effect.Parameters["HzbTexture"]; _parameterLightHzbTexture = _effect.Parameters["LightHzb"]; _parameterDebugLevel = _effect.Parameters["DebugLevel"]; _parameterDebugMinimum = _effect.Parameters["DebugMinimum"]; _parameterDebugMaximum = _effect.Parameters["DebugMaximum"]; _techniqueOccluder = _effect.Techniques["Occluder"]; _techniqueDownsample = _effect.Techniques["Downsample"]; _techniqueCopy = _effect.Techniques["Copy"]; _techniqueQuery = _effect.Techniques["Query"]; _techniqueVisualize = _effect.Techniques["Visualize"]; _occlusionProxies = new List<IOcclusionProxy>(); _sceneNodes = new List<SceneNode>(); // Store delegate methods to avoid garbage. _updateOcclusionProxies = UpdateOcclusionProxies; _updateOcclusionProxy = UpdateOcclusionProxy; _splitVolume = new PerspectiveViewVolume(); _orthographicCameraNode = new CameraNode(new Camera(new OrthographicProjection())); _shadowCasters = new List<SceneNode>(); /* // By default, enable multithreading on multi-core systems. #if WP7 || UNITY // Cannot access Environment.ProcessorCount in phone app. (Security issue.) EnableMultithreading = false; #else // Enable multithreading by default if the current system has multiple processors. EnableMultithreading = Environment.ProcessorCount > 1; // Multithreading works but Parallel.For of Xamarin.Android/iOS is very inefficient. if (GlobalSettings.PlatformID == PlatformID.Android || GlobalSettings.PlatformID == PlatformID.iOS) EnableMultithreading = false; #endif */ // Disable multithreading by default. Multithreading causes massive lags in the // XNA version, but the MonoGame version is not affected!? EnableMultithreading = false; // For best performance: Enable progressive shadow caster culling. ProgressiveShadowCasterCulling = true; Statistics = new OcclusionCullingStatistics(); InitializeBuffers(graphicsDevice, width, height); }
BatchInfo GetCreateBatchInfo(ResourceHandle<Image> imageHandle) { var hId = imageHandle.Id; if (!batches.ContainsKey(hId)) { var batch = new RenderBatch(); batch.SetGeometryBuffer(gb); batch.SetRenderLayer(RenderLayer.Overlays); batch.SetPrimitiveType(PrimitiveType.Quads); var mat = GetCreateMaterial(imageHandle); batch.SetMaterial(mat); var bInfo = new BatchInfo {Batch = batch}; batches[hId] = bInfo; } return batches[hId]; }
public static LoadError LoadFromStream(Stream stream, out RenderBatch renderBatch) { BinaryReader binaryReader = new BinaryReader(stream, Encoding.Default, true); renderBatch = new RenderBatch(); renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); return LoadError.None; }
public bool InitializeFromStream(string name, string displayName, MemoryStream stream) { using (BinaryReader binaryReader = new BinaryReader(stream)) { Name = name; DisplayName = displayName; //Header byte[] magic = binaryReader.ReadBytes(4); if (magic[0] != 'C' || magic[1] != 'N' || magic[2] != 'K' /* || * magic[3] != '1'*/) { return(false); } Version = binaryReader.ReadUInt32(); if (!Enum.IsDefined(typeof(ChunkType), (int)Version)) { Debug.LogWarning("Could not decode chunk " + name + ". Unknown cnk version " + Version); return(false); } ChunkType = (ChunkType)Version; DecompressedSize = binaryReader.ReadUInt32(); CompressedSize = binaryReader.ReadUInt32(); // Decompression // Make sure our buffers are large enough. if (CompressedBuffer.Length < CompressedSize) { Array.Resize(ref CompressedBuffer, (int)CompressedSize); } if (DecompressedBuffer.Length < DecompressedSize) { Array.Resize(ref DecompressedBuffer, (int)DecompressedSize); } // Read the compressed buffer. binaryReader.Read(CompressedBuffer, 0, (int)CompressedSize); // Perform decompression using Lzham. InflateReturnCode result = LzhamInterop.DecompressForgelightData(CompressedBuffer, CompressedSize, DecompressedBuffer, DecompressedSize); if (result != InflateReturnCode.LZHAM_Z_STREAM_END && result != InflateReturnCode.LZHAM_Z_OK) { //This chunk is invalid, or something went wrong. return(false); } } using (MemoryStream decompressedStream = new MemoryStream(DecompressedBuffer, 0, (int)DecompressedSize)) { using (BinaryReader binaryReader = new BinaryReader(decompressedStream)) { //Textures uint textureCount = binaryReader.ReadUInt32(); for (int i = 0; i < textureCount; i++) { Texture texture = new Texture(); uint colorNxMapSize = binaryReader.ReadUInt32(); if (colorNxMapSize > 0) { texture.ColorNXMap = binaryReader.ReadBytes((int)colorNxMapSize).ToList(); } uint specNyMapSize = binaryReader.ReadUInt32(); if (specNyMapSize > 0) { texture.SpecNyMap = binaryReader.ReadBytes((int)specNyMapSize).ToList(); } uint extraData1Size = binaryReader.ReadUInt32(); if (extraData1Size > 0) { texture.ExtraData1 = binaryReader.ReadBytes((int)extraData1Size).ToList(); } uint extraData2Size = binaryReader.ReadUInt32(); if (extraData2Size > 0) { texture.ExtraData2 = binaryReader.ReadBytes((int)extraData2Size).ToList(); } uint extraData3Size = binaryReader.ReadUInt32(); if (extraData3Size > 0) { texture.ExtraData3 = binaryReader.ReadBytes((int)extraData3Size).ToList(); } uint extraData4Size = binaryReader.ReadUInt32(); if (extraData4Size > 0) { texture.ExtraData4 = binaryReader.ReadBytes((int)extraData4Size).ToList(); } Textures.Add(texture); } //Verts Per Side VertsPerSide = binaryReader.ReadUInt32(); //Height Maps uint heightMapCount = binaryReader.ReadUInt32(); int n = (int)(heightMapCount / 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < n; j++) { Dictionary <int, HeightMap> entry; if (!HeightMaps.ContainsKey(i)) { entry = new Dictionary <int, HeightMap>(); HeightMaps[i] = entry; } else { entry = HeightMaps[i]; } HeightMap heightMapData = new HeightMap(); heightMapData.Val1 = binaryReader.ReadInt16(); heightMapData.Val2 = binaryReader.ReadByte(); heightMapData.Val3 = binaryReader.ReadByte(); entry[j] = heightMapData; } } //Indices uint indexCount = binaryReader.ReadUInt32(); for (int i = 0; i < indexCount; i++) { Indices.Add(binaryReader.ReadUInt16()); } //Verts uint vertCount = binaryReader.ReadUInt32(); for (int i = 0; i < vertCount; i++) { Vertex vertex = new Vertex(); vertex.X = binaryReader.ReadInt16(); vertex.Y = binaryReader.ReadInt16(); vertex.HeightFar = binaryReader.ReadInt16(); vertex.HeightNear = binaryReader.ReadInt16(); vertex.Color = binaryReader.ReadUInt32(); Vertices.Add(vertex); } //TODO HACK - Daybreak, why are some chunks (that have a version 2 header) actually version 1? long offset = binaryReader.BaseStream.Position; try { //Render Batches uint renderBatchCount = binaryReader.ReadUInt32(); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); if (ChunkType == ChunkType.H1Z1_Planetside2V2) { renderBatch.Unknown = binaryReader.ReadUInt32(); } renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = binaryReader.ReadUInt32(); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = binaryReader.ReadBytes(320).ToList(); OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = binaryReader.ReadUInt32(); for (int i = 0; i < unknownShort1Count; i++) { UnknownShorts1.Add(binaryReader.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = binaryReader.ReadUInt32(); for (int i = 0; i < unknownVectors1Count; i++) { UnknownVectors1.Add(new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = binaryReader.ReadUInt32(); if (tileOccluderCount > 16) { throw new ArgumentOutOfRangeException(); } for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = binaryReader.ReadBytes(64).ToList(); TileOccluderInfos.Add(tileOccluderInfo); } } catch (Exception) { // Some of these may have been populated from the "try". RenderBatches.Clear(); OptimizedDraws.Clear(); UnknownShorts1.Clear(); UnknownVectors1.Clear(); TileOccluderInfos.Clear(); binaryReader.BaseStream.Position = offset; //Render Batches uint renderBatchCount = binaryReader.ReadUInt32(); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = binaryReader.ReadUInt32(); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = binaryReader.ReadBytes(320).ToList(); OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = binaryReader.ReadUInt32(); for (int i = 0; i < unknownShort1Count; i++) { UnknownShorts1.Add(binaryReader.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = binaryReader.ReadUInt32(); for (int i = 0; i < unknownVectors1Count; i++) { UnknownVectors1.Add(new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = binaryReader.ReadUInt32(); if (tileOccluderCount > 16) { return(false); } for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = binaryReader.ReadBytes(64).ToList(); TileOccluderInfos.Add(tileOccluderInfo); } } } } return(true); }
public static void ExportADT(uint wdtFileDataID, byte tileX, byte tileY, BackgroundWorker exportworker = null) { if (exportworker == null) { exportworker = new BackgroundWorker(); exportworker.WorkerReportsProgress = true; } var outdir = "export"; var customCulture = (System.Globalization.CultureInfo)System.Threading.Thread.CurrentThread.CurrentCulture.Clone(); customCulture.NumberFormat.NumberDecimalSeparator = "."; System.Threading.Thread.CurrentThread.CurrentCulture = customCulture; var MaxSize = 51200 / 3.0; var TileSize = MaxSize / 32.0; var ChunkSize = TileSize / 16.0; var UnitSize = ChunkSize / 8.0; var UnitSizeHalf = UnitSize / 2.0; var wdtFilename = "world/maps/azeroth/azeroth.wdt"; var mapName = Path.GetFileNameWithoutExtension(wdtFilename); var file = "world/maps/" + mapName + "/" + mapName + "_" + tileX.ToString() + "_" + tileY.ToString() + ".adt"; var reader = new ADTReader(); reader.LoadADT(wdtFileDataID, tileX, tileY, true, wdtFilename); if (reader.adtfile.chunks == null) { Logger.WriteLine("ADT OBJ Exporter: File {0} has no chunks, skipping export!", file); return; } Logger.WriteLine("ADT OBJ Exporter: Starting export of {0}..", file); Directory.CreateDirectory(Path.Combine(outdir, Path.GetDirectoryName(file))); exportworker.ReportProgress(0, "Loading ADT " + file); var renderBatches = new List <RenderBatch>(); var verticelist = new List <Vertex>(); var indicelist = new List <int>(); var materials = new Dictionary <int, string>(); var bakeQuality = "none"; // Calculate ADT offset in world coordinates var adtStartX = ((reader.adtfile.x - 32) * TileSize) * -1; var adtStartY = ((reader.adtfile.y - 32) * TileSize) * -1; // Calculate first chunk offset in world coordinates var initialChunkX = adtStartY + (reader.adtfile.chunks[0].header.indexX * ChunkSize) * -1; var initialChunkY = adtStartX + (reader.adtfile.chunks[0].header.indexY * ChunkSize) * -1; uint ci = 0; for (var x = 0; x < 16; x++) { double xOfs = x / 16d; for (var y = 0; y < 16; y++) { double yOfs = y / 16d; var genx = (initialChunkX + (ChunkSize * x) * -1); var geny = (initialChunkY + (ChunkSize * y) * -1); var chunk = reader.adtfile.chunks[ci]; var off = verticelist.Count(); var batch = new RenderBatch(); for (int i = 0, idx = 0; i < 17; i++) { bool isSmallRow = (i % 2) != 0; int rowLength = isSmallRow ? 8 : 9; for (var j = 0; j < rowLength; j++) { var v = new Vertex(); v.Normal = new Vector3D { X = (double)chunk.normals.normal_0[idx] / 127, Y = (double)chunk.normals.normal_2[idx] / 127, Z = (double)chunk.normals.normal_1[idx] / 127 }; var px = geny - (j * UnitSize); var py = chunk.vertices.vertices[idx++] + chunk.header.position.Z; var pz = genx - (i * UnitSizeHalf); v.Position = new Vector3D { X = px, Y = py, Z = pz }; if ((i % 2) != 0) { v.Position.X = (px - UnitSizeHalf); } double ofs = j; if (isSmallRow) { ofs += 0.5; } if (bakeQuality == "high") { double tx = ofs / 8d; double ty = 1 - (i / 16d); v.TexCoord = new Vector2D { X = tx, Y = ty }; } else { double tx = -(v.Position.X - initialChunkY) / TileSize; double ty = (v.Position.Z - initialChunkX) / TileSize; v.TexCoord = new Vector2D { X = tx, Y = ty }; } verticelist.Add(v); } } batch.firstFace = (uint)indicelist.Count(); // Stupid C# and its structs var holesHighRes = new byte[8]; holesHighRes[0] = chunk.header.holesHighRes_0; holesHighRes[1] = chunk.header.holesHighRes_1; holesHighRes[2] = chunk.header.holesHighRes_2; holesHighRes[3] = chunk.header.holesHighRes_3; holesHighRes[4] = chunk.header.holesHighRes_4; holesHighRes[5] = chunk.header.holesHighRes_5; holesHighRes[6] = chunk.header.holesHighRes_6; holesHighRes[7] = chunk.header.holesHighRes_7; for (int j = 9, xx = 0, yy = 0; j < 145; j++, xx++) { if (xx >= 8) { xx = 0; ++yy; } var isHole = true; // Check if chunk is using low-res holes if ((chunk.header.flags & 0x10000) == 0) { // Calculate current hole number var currentHole = (int)Math.Pow(2, Math.Floor(xx / 2f) * 1f + Math.Floor(yy / 2f) * 4f); // Check if current hole number should be a hole if ((chunk.header.holesLowRes & currentHole) == 0) { isHole = false; } } else { // Check if current section is a hole if (((holesHighRes[yy] >> xx) & 1) == 0) { isHole = false; } } if (!isHole) { indicelist.AddRange(new int[] { off + j + 8, off + j - 9, off + j }); indicelist.AddRange(new int[] { off + j - 9, off + j - 8, off + j }); indicelist.AddRange(new int[] { off + j - 8, off + j + 9, off + j }); indicelist.AddRange(new int[] { off + j + 9, off + j + 8, off + j }); // Generates quads instead of 4x triangles //indicelist.AddRange(new int[] { off + j + 8, off + j - 9, off + j - 8 }); //indicelist.AddRange(new int[] { off + j - 8, off + j + 9, off + j + 8 }); } if ((j + 1) % (9 + 8) == 0) { j += 9; } } if (bakeQuality == "high") { materials.Add((int)ci + 1, Path.GetFileNameWithoutExtension(file).Replace(" ", "") + "_" + ci); batch.materialID = ci + 1; } else { if (!materials.ContainsKey(1)) { materials.Add(1, Path.GetFileNameWithoutExtension(file).Replace(" ", "")); } batch.materialID = (uint)materials.Count(); } batch.numFaces = (uint)(indicelist.Count()) - batch.firstFace; var layermats = new List <uint>(); renderBatches.Add(batch); ci++; } } exportworker.ReportProgress(75, "Exporting terrain textures.."); if (bakeQuality != "none") { var mtlsw = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file).Replace(" ", "") + ".mtl")); //No idea how MTL files really work yet. Needs more investigation. foreach (var material in materials) { mtlsw.WriteLine("newmtl " + material.Value.Replace(" ", "")); mtlsw.WriteLine("Ka 1.000000 1.000000 1.000000"); mtlsw.WriteLine("Kd 0.640000 0.640000 0.640000"); mtlsw.WriteLine("map_Ka " + material.Value.Replace(" ", "") + ".png"); mtlsw.WriteLine("map_Kd " + material.Value.Replace(" ", "") + ".png"); } mtlsw.Close(); } exportworker.ReportProgress(85, "Exporting terrain geometry.."); var indices = indicelist.ToArray(); var adtname = Path.GetFileNameWithoutExtension(file); var objsw = new StreamWriter(Path.Combine(outdir, Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file).Replace(" ", "") + ".obj")); objsw.WriteLine("# Written by Marlamin's WoW OBJExporter. Original file: " + file); if (bakeQuality != "none") { objsw.WriteLine("mtllib " + Path.GetFileNameWithoutExtension(file).Replace(" ", "") + ".mtl"); } var verticeCounter = 1; var chunkCounter = 1; foreach (var vertex in verticelist) { //objsw.WriteLine("# C" + chunkCounter + ".V" + verticeCounter); objsw.WriteLine("v " + vertex.Position.X.ToString("R") + " " + vertex.Position.Y.ToString("R") + " " + vertex.Position.Z.ToString("R")); objsw.WriteLine("vt " + vertex.TexCoord.X + " " + vertex.TexCoord.Y); objsw.WriteLine("vn " + vertex.Normal.X.ToString("R") + " " + vertex.Normal.Y.ToString("R") + " " + vertex.Normal.Z.ToString("R")); verticeCounter++; if (verticeCounter == 146) { chunkCounter++; verticeCounter = 1; } } if (bakeQuality != "high") { objsw.WriteLine("g " + adtname.Replace(" ", "")); objsw.WriteLine("usemtl " + materials[1]); objsw.WriteLine("s 1"); } for (int rbi = 0; rbi < renderBatches.Count(); rbi++) { var renderBatch = renderBatches[rbi]; var i = renderBatch.firstFace; if (bakeQuality == "high" && materials.ContainsKey((int)renderBatch.materialID)) { objsw.WriteLine("g " + adtname.Replace(" ", "") + "_" + rbi); objsw.WriteLine("usemtl " + materials[(int)renderBatch.materialID]); } while (i < (renderBatch.firstFace + renderBatch.numFaces)) { objsw.WriteLine("f " + (indices[i + 2] + 1) + "/" + (indices[i + 2] + 1) + "/" + (indices[i + 2] + 1) + " " + (indices[i + 1] + 1) + "/" + (indices[i + 1] + 1) + "/" + (indices[i + 1] + 1) + " " + (indices[i] + 1) + "/" + (indices[i] + 1) + "/" + (indices[i] + 1)); i = i + 3; } } objsw.Close(); Logger.WriteLine("ADT OBJ Exporter: Finished with export of {0}..", file); }
public void Apply(RenderTreeDiff tree, RenderBatch batch) { //List<int> removedIndex = new List<int>(); //List<View> //List<StyleSheet> deferedStyleSheet = new List<StyleSheet>(); CurrentNode = InitialNode; foreach (var edit in tree.Edits) { var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; ProcessTree(edit, batch, edit.ReferenceFrameIndex, edit.Type == RenderTreeEditType.PrependFrame ? (frame.ElementSubtreeLength == 0 ? 1 : frame.ElementSubtreeLength) :1); //ProcessTree(edit, batch, edit.ReferenceFrameIndex, frame.ElementSubtreeLength == 0 ? 1 : frame.ElementSubtreeLength); //int subtreeIndex = 0; //do //{ // switch (edit.Type) // { // case RenderTreeEditType.PrependFrame: // { // switch (frame.FrameType) // { // case RenderTreeFrameType.Component: // { // var childRenderer = new ComponentRenderer(frame.Component, WebViewRenderer, this); // WebViewRenderer.Renderers[frame.ComponentId] = childRenderer; // } // break; // case RenderTreeFrameType.Element: // { // WebViewRenderer.DOMManager.CreateElement(Sequences.ToArray(), frame.Sequence, frame.ElementName); // Sequences.Push(frame.Sequence); // } // break; // case RenderTreeFrameType.Attribute: // { // WebViewRenderer.DOMManager.SetAttribute(Sequences.ToArray(), frame.AttributeName, frame.AttributeValue); // } // break; // case RenderTreeFrameType.Text: // WebViewRenderer.DOMManager.InsertText(Sequences.ToArray(), frame.Sequence, frame.TextContent); // break; // case RenderTreeFrameType.Markup: // WebViewRenderer.DOMManager.InsertMarkup(Sequences.ToArray(), frame.Sequence, frame.MarkupContent); // break; // case RenderTreeFrameType.Region: // Sequences.Push(frame.Sequence); // int sequenceSubTrees = frame.RegionSubtreeLength; // break; // default: // throw new NotImplementedException($"Invalid Frame type: {frame.FrameType}"); // } // } // break; // case RenderTreeEditType.UpdateText: // { // WebViewRenderer.DOMManager.InsertText(Sequences.ToArray(), frame.Sequence, frame.TextContent); // } // break; // case RenderTreeEditType.RemoveFrame: // { // WebViewRenderer.DOMManager.RemoveAt(Sequences.ToArray(), edit.SiblingIndex); // } // break; // case RenderTreeEditType.UpdateMarkup: // { // WebViewRenderer.DOMManager.InsertText(Sequences.ToArray(), frame.Sequence, frame.TextContent); // } // break; // case RenderTreeEditType.SetAttribute: // { // WebViewRenderer.DOMManager.SetAttribute(Sequences.ToArray(), frame.AttributeName, frame.AttributeValue); // } // break; // case RenderTreeEditType.RemoveAttribute: // { // WebViewRenderer.DOMManager.RemoveAttribute(Sequences.ToArray(), frame.AttributeName); // } // break; // case RenderTreeEditType.StepIn: // break; // case RenderTreeEditType.StepOut: // break; // case RenderTreeEditType.PermutationListEntry: // case RenderTreeEditType.PermutationListEnd: // default: // throw new NotImplementedException($"Invalid edit type: {edit.Type}"); // } // subtreeIndex++; // if (batch.ReferenceFrames.Array[edit.ReferenceFrameIndex].ElementSubtreeLength > subtreeIndex) // continue; // break; //} while (true); } }
private int ApplyPrependFrame(RenderBatch batch, int componentId, int siblingIndex, RenderTreeFrame[] frames, int frameIndex) { ref var frame = ref frames[frameIndex];
void ProcessTree(RenderTreeEdit edit, RenderBatch batch, int startIndex, int subLength) { for (int i = 0; i < subLength; i++) { int currentIndex = startIndex + i; var frame = batch.ReferenceFrames.Array[currentIndex]; switch (edit.Type) { case RenderTreeEditType.PrependFrame: { switch (frame.FrameType) { case RenderTreeFrameType.Component: { CurrentNode = WebViewRenderer.DOMBuilder.CreateMarkerElement(CurrentNode, frame.Sequence, frame.Component.GetType().Name); //Sequences.Push(frame.Sequence); var childRenderer = new ComponentRenderer(frame.Component, WebViewRenderer, this); WebViewRenderer.Renderers[frame.ComponentId] = childRenderer; //we dont need to process the subtree of components as the Renderer will process it again //ProcessTree(edit, batch, currentIndex + 1, frame.ElementSubtreeLength - 1); i += frame.ComponentSubtreeLength - 1; //Sequences.Pop(); CurrentNode = WebViewRenderer.DOMBuilder.Parent(CurrentNode); } break; case RenderTreeFrameType.Element: { CurrentNode = WebViewRenderer.DOMBuilder.CreateElement(CurrentNode, frame.Sequence, frame.ElementName); //Sequences.Push(frame.Sequence); ProcessTree(edit, batch, currentIndex + 1, frame.ElementSubtreeLength - 1); i += frame.ElementSubtreeLength - 1; //Sequences.Pop(); CurrentNode = WebViewRenderer.DOMBuilder.Parent(CurrentNode); } break; case RenderTreeFrameType.Attribute: { if (frame.AttributeValue is EventCallback callback) { WebViewRenderer.DOMBuilder.SetEvent(CurrentNode, frame.Sequence, frame.AttributeName, callback, frame.AttributeEventUpdatesAttributeName); } else { WebViewRenderer.DOMBuilder.SetAttribute(CurrentNode, frame.Sequence, frame.AttributeName, frame.AttributeValue); } } break; case RenderTreeFrameType.Text: WebViewRenderer.DOMBuilder.InsertText(CurrentNode, frame.Sequence, frame.TextContent); break; case RenderTreeFrameType.Markup: { WebViewRenderer.DOMBuilder.InsertMarkup(CurrentNode, frame.Sequence, frame.MarkupContent); } break; case RenderTreeFrameType.Region: { CurrentNode = WebViewRenderer.DOMBuilder.CreateMarkerElement(CurrentNode, frame.Sequence, frame.AttributeName); //Sequences.Push(frame.Sequence); ProcessTree(edit, batch, currentIndex + 1, frame.RegionSubtreeLength - 1); i += frame.RegionSubtreeLength - 1; //Sequences.Pop(); CurrentNode = WebViewRenderer.DOMBuilder.Parent(CurrentNode); } break; case RenderTreeFrameType.ElementReferenceCapture: ElementReference reference = new ElementReference(CurrentNode.ToString()); //WebViewRenderer.DOMBuilder.Reference(); frame.ElementReferenceCaptureAction(reference); break; case RenderTreeFrameType.None: break; default: throw new NotImplementedException($"Invalid Frame type: {frame.FrameType}"); } } break; case RenderTreeEditType.UpdateText: { WebViewRenderer.DOMBuilder.UpdateText(CurrentNode, frame.Sequence, frame.TextContent); } break; case RenderTreeEditType.RemoveFrame: { WebViewRenderer.DOMBuilder.RemoveAt(CurrentNode, edit.SiblingIndex); } break; case RenderTreeEditType.UpdateMarkup: { WebViewRenderer.DOMBuilder.UpdateMarkup(CurrentNode, frame.Sequence, frame.TextContent); } break; case RenderTreeEditType.SetAttribute: { var node = WebViewRenderer.DOMBuilder.Child(CurrentNode, edit.SiblingIndex); if (frame.AttributeValue is EventCallback callback) { WebViewRenderer.DOMBuilder.SetEvent(node, frame.Sequence, frame.AttributeName, callback, frame.AttributeEventUpdatesAttributeName); } else { WebViewRenderer.DOMBuilder.SetAttribute(node, frame.Sequence, frame.AttributeName, frame.AttributeValue); } //WebViewRenderer.DOMManager.SetAttribute(CurrentNode, frame.Sequence, frame.AttributeName, frame.AttributeValue); } break; case RenderTreeEditType.RemoveAttribute: { WebViewRenderer.DOMBuilder.RemoveAttribute(CurrentNode, frame.Sequence, frame.AttributeName); } break; case RenderTreeEditType.StepIn: CurrentNode = WebViewRenderer.DOMBuilder.Child(CurrentNode, edit.SiblingIndex); break; case RenderTreeEditType.StepOut: CurrentNode = WebViewRenderer.DOMBuilder.Parent(CurrentNode); break; case RenderTreeEditType.PermutationListEntry: case RenderTreeEditType.PermutationListEnd: default: throw new NotImplementedException($"Invalid edit type: {edit.Type}"); } } }
protected override void UpdateDisplay(RenderBatch renderBatch) { LatestBatchReferenceFrames = renderBatch.ReferenceFrames.ToArray(); }
private int ApplyPrependFrame(RenderBatch batch, int componentId, int siblingIndex, RenderTreeFrame[] frames, int frameIndex, HashSet <int> processedComponentIds) { ref var frame = ref frames[frameIndex];
private void ApplyEdits(RenderBatch batch, ContainerNode parent, int childIndex, ArrayBuilderSegment <RenderTreeEdit> edits) { var currentDepth = 0; var childIndexAtCurrentDepth = childIndex; var permutations = new List <PermutationListEntry>(); for (var editIndex = edits.Offset; editIndex < edits.Offset + edits.Count; editIndex++) { var edit = edits.Array[editIndex]; switch (edit.Type) { case RenderTreeEditType.PrependFrame: { var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; var siblingIndex = edit.SiblingIndex; InsertFrame(batch, parent, childIndexAtCurrentDepth + siblingIndex, batch.ReferenceFrames.Array, frame, edit.ReferenceFrameIndex); break; } case RenderTreeEditType.RemoveFrame: { var siblingIndex = edit.SiblingIndex; parent.RemoveLogicalChild(childIndexAtCurrentDepth + siblingIndex); break; } case RenderTreeEditType.SetAttribute: { var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; var siblingIndex = edit.SiblingIndex; var node = parent.Children[childIndexAtCurrentDepth + siblingIndex]; if (node is ElementNode element) { ApplyAttribute(batch, element, frame); } else { throw new Exception("Cannot set attribute on non-element child"); } break; } case RenderTreeEditType.RemoveAttribute: { // Note that we don't have to dispose the info we track about event handlers here, because the // disposed event handler IDs are delivered separately (in the 'disposedEventHandlerIds' array) var siblingIndex = edit.SiblingIndex; var node = parent.Children[childIndexAtCurrentDepth + siblingIndex]; if (node is ElementNode element) { var attributeName = edit.RemovedAttributeName; // First try to remove any special property we use for this attribute if (!TryApplySpecialProperty(batch, element, attributeName, default)) { // If that's not applicable, it's a regular DOM attribute so remove that element.RemoveAttribute(attributeName); } } else { throw new Exception("Cannot remove attribute from non-element child"); } break; } case RenderTreeEditType.UpdateText: { var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; var siblingIndex = edit.SiblingIndex; var node = parent.Children[childIndexAtCurrentDepth + siblingIndex]; if (node is TextNode textNode) { textNode.TextContent = frame.TextContent; } else { throw new Exception("Cannot set text content on non-text child"); } break; } case RenderTreeEditType.UpdateMarkup: { var frame = batch.ReferenceFrames.Array[edit.ReferenceFrameIndex]; var siblingIndex = edit.SiblingIndex; parent.RemoveLogicalChild(childIndexAtCurrentDepth + siblingIndex); InsertMarkup(parent, childIndexAtCurrentDepth + siblingIndex, frame); break; } case RenderTreeEditType.StepIn: { var siblingIndex = edit.SiblingIndex; parent = (ContainerNode)parent.Children[childIndexAtCurrentDepth + siblingIndex]; currentDepth++; childIndexAtCurrentDepth = 0; break; } case RenderTreeEditType.StepOut: { parent = parent.Parent; currentDepth--; childIndexAtCurrentDepth = currentDepth == 0 ? childIndex : 0; // The childIndex is only ever nonzero at zero depth break; } case RenderTreeEditType.PermutationListEntry: { permutations.Add(new PermutationListEntry(childIndexAtCurrentDepth + edit.SiblingIndex, childIndexAtCurrentDepth + edit.MoveToSiblingIndex)); break; } case RenderTreeEditType.PermutationListEnd: { throw new NotSupportedException(); //permuteLogicalChildren(parent, permutations!); //permutations.Clear(); //break; } default: { throw new Exception($"Unknown edit type: '{edit.Type}'"); } } } }
public static Cnk0 LoadFromStream(string name, string displayName, MemoryStream stream) { Cnk0 chunk = new Cnk0(); BinaryReader binaryReader = new BinaryReader(stream); chunk.Name = name; chunk.DisplayName = displayName; //Header byte[] magic = binaryReader.ReadBytes(4); if (magic[0] != 'C' || magic[1] != 'N' || magic[2] != 'K' || magic[3] != '0') { return(null); } chunk.Version = binaryReader.ReadUInt32(); if (!Enum.IsDefined(typeof(ChunkType), (int)chunk.Version)) { Debug.LogWarning("Could not decode chunk " + name + ". Unknown cnk version " + chunk.Version); return(null); } chunk.ChunkType = (ChunkType)chunk.Version; chunk.DecompressedSize = binaryReader.ReadUInt32(); chunk.CompressedSize = binaryReader.ReadUInt32(); //Decompression byte[] compressedBuffer = binaryReader.ReadBytes((int)chunk.CompressedSize); byte[] decompressedBuffer = new byte[chunk.DecompressedSize]; InflateReturnCode result = LzhamInterop.DecompressForgelightData(compressedBuffer, chunk.CompressedSize, decompressedBuffer, chunk.DecompressedSize); if (result != InflateReturnCode.LZHAM_Z_STREAM_END && result != InflateReturnCode.LZHAM_Z_OK) { //This chunk is invalid. return(null); } using (MemoryStream decompressedStream = new MemoryStream(decompressedBuffer)) { binaryReader = new BinaryReader(decompressedStream); //Tiles uint tileCount = binaryReader.ReadUInt32(); chunk.Tiles = new List <Tile>((int)tileCount); for (int i = 0; i < tileCount; i++) { Tile tile = new Tile(); tile.X = binaryReader.ReadInt32(); tile.Y = binaryReader.ReadInt32(); tile.UnknownInt1 = binaryReader.ReadInt32(); tile.UnknownInt2 = binaryReader.ReadInt32(); uint ecosCount = binaryReader.ReadUInt32(); if (ecosCount > 0) { tile.Ecos = new List <Tile.Eco>((int)ecosCount); for (int j = 0; j < ecosCount; j++) { Tile.Eco eco = new Tile.Eco(); eco.ID = binaryReader.ReadUInt32(); uint florasCount = binaryReader.ReadUInt32(); eco.Floras = new List <Tile.Eco.Flora>((int)florasCount); for (int k = 0; k < florasCount; k++) { Tile.Eco.Flora flora = new Tile.Eco.Flora(); uint layersCount = binaryReader.ReadUInt32(); flora.Layers = new List <Tile.Eco.Flora.Layer>((int)layersCount); for (int l = 0; l < layersCount; l++) { Tile.Eco.Flora.Layer layer = new Tile.Eco.Flora.Layer(); layer.UnknownUint1 = binaryReader.ReadUInt32(); layer.UnknownUint2 = binaryReader.ReadUInt32(); flora.Layers.Add(layer); } eco.Floras.Add(flora); } tile.Ecos.Add(eco); } } tile.Index = binaryReader.ReadUInt32(); tile.UnknownInt3 = binaryReader.ReadUInt32(); uint imageSize = binaryReader.ReadUInt32(); if (imageSize > 0) { tile.ImageData = binaryReader.ReadBytes((int)imageSize).ToList(); } uint layerTexturesCount = binaryReader.ReadUInt32(); if (layerTexturesCount > 0) { tile.LayerTextures = binaryReader.ReadBytes((int)layerTexturesCount).ToList(); } chunk.Tiles.Add(tile); } //Unknown Data chunk.UnknownInt1 = binaryReader.ReadInt32(); uint unknownCount = binaryReader.ReadUInt32(); chunk.UnknownArray1 = new List <Unknown1>((int)unknownCount); for (int i = 0; i < unknownCount; i++) { Unknown1 unknown1 = new Unknown1(); unknown1.Height = binaryReader.ReadInt16(); unknown1.UnknownByte1 = binaryReader.ReadByte(); unknown1.UnknownByte2 = binaryReader.ReadByte(); chunk.UnknownArray1.Add(unknown1); } //Indices uint indexCount = binaryReader.ReadUInt32(); chunk.Indices = new List <ushort>((int)indexCount); for (int i = 0; i < indexCount; i++) { chunk.Indices.Add(binaryReader.ReadUInt16()); } //Verts uint vertCount = binaryReader.ReadUInt32(); chunk.Vertices = new List <Vertex>((int)vertCount); for (int i = 0; i < vertCount; i++) { Vertex vertex = new Vertex(); vertex.X = binaryReader.ReadInt16(); vertex.Y = binaryReader.ReadInt16(); vertex.HeightFar = binaryReader.ReadInt16(); vertex.HeightNear = binaryReader.ReadInt16(); vertex.Color1 = binaryReader.ReadUInt32(); vertex.Color2 = binaryReader.ReadUInt32(); chunk.Vertices.Add(vertex); } //TODO HACK - Daybreak, why are some chunks (that have a version 2 header) actually version 1? long offset = binaryReader.BaseStream.Position; try { //Render Batches uint renderBatchCount = binaryReader.ReadUInt32(); chunk.RenderBatches = new List <RenderBatch>((int)renderBatchCount); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); if (chunk.ChunkType == ChunkType.H1Z1_Planetside2V2) { renderBatch.Unknown = binaryReader.ReadUInt32(); } renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); chunk.RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = binaryReader.ReadUInt32(); chunk.OptimizedDraws = new List <OptimizedDraw>((int)optimizedDrawCount); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = binaryReader.ReadBytes(320).ToList(); chunk.OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = binaryReader.ReadUInt32(); chunk.UnknownShorts1 = new List <ushort>((int)unknownShort1Count); for (int i = 0; i < unknownShort1Count; i++) { chunk.UnknownShorts1.Add(binaryReader.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = binaryReader.ReadUInt32(); chunk.UnknownVectors1 = new List <Vector3>((int)unknownVectors1Count); for (int i = 0; i < unknownVectors1Count; i++) { chunk.UnknownVectors1.Add(new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = binaryReader.ReadUInt32(); chunk.TileOccluderInfos = new List <TileOccluderInfo>((int)tileOccluderCount); for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = binaryReader.ReadBytes(64).ToList(); chunk.TileOccluderInfos.Add(tileOccluderInfo); } } catch (EndOfStreamException) { binaryReader.BaseStream.Position = offset; //Render Batches uint renderBatchCount = binaryReader.ReadUInt32(); chunk.RenderBatches = new List <RenderBatch>((int)renderBatchCount); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); renderBatch.IndexOffset = binaryReader.ReadUInt32(); renderBatch.IndexCount = binaryReader.ReadUInt32(); renderBatch.VertexOffset = binaryReader.ReadUInt32(); renderBatch.VertexCount = binaryReader.ReadUInt32(); chunk.RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = binaryReader.ReadUInt32(); chunk.OptimizedDraws = new List <OptimizedDraw>((int)optimizedDrawCount); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = binaryReader.ReadBytes(320).ToList(); chunk.OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = binaryReader.ReadUInt32(); chunk.UnknownShorts1 = new List <ushort>((int)unknownShort1Count); for (int i = 0; i < unknownShort1Count; i++) { chunk.UnknownShorts1.Add(binaryReader.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = binaryReader.ReadUInt32(); chunk.UnknownVectors1 = new List <Vector3>((int)unknownVectors1Count); for (int i = 0; i < unknownVectors1Count; i++) { chunk.UnknownVectors1.Add(new Vector3(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = binaryReader.ReadUInt32(); chunk.TileOccluderInfos = new List <TileOccluderInfo>((int)tileOccluderCount); for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = binaryReader.ReadBytes(64).ToList(); chunk.TileOccluderInfos.Add(tileOccluderInfo); } } } return(chunk); }
public bool Deserialize(BinaryStream stream, AssetManager assetManager) { // Header string magic = stream.ReadString(3); Assert.AreEqual(MAGIC, magic, "Chunk header mismatch!"); int lodLevel = Convert.ToInt32(stream.ReadString(1)); Assert.AreNotEqual(0, lodLevel, "Use the CNK0 serializer for LOD0 terrain chunks."); Version = stream.ReadUInt32(); if (!Enum.IsDefined(typeof(ChunkType), (int)Version)) { Debug.LogWarning("Could not decode chunk " + Name + ". Unknown cnk version " + Version); return(false); } ChunkType = (ChunkType)Version; DecompressedSize = stream.ReadUInt32(); CompressedSize = stream.ReadUInt32(); // Read the compressed buffer. stream.ReadBytes(CompressedBuffer, (int)CompressedSize); // Decompression // Make sure our buffer is large enough. DecompressedBuffer.PrepareBuffer((int)DecompressedSize); // Perform decompression using Lzham. InflateReturnCode result = LzhamInterop.DecompressForgelightData(CompressedBuffer.Data, CompressedSize, DecompressedBuffer.Data, DecompressedSize); if (result != InflateReturnCode.LZHAM_Z_STREAM_END && result != InflateReturnCode.LZHAM_Z_OK) { //This chunk is invalid, or something went wrong. return(false); } using (MemoryStream decompressedStream = new MemoryStream(DecompressedBuffer.Data, 0, (int)DecompressedSize)) { //Textures uint textureCount = decompressedStream.ReadUInt32(); Textures.PrepareBuffer((int)textureCount); for (int i = 0; i < textureCount; i++) { Texture texture = Textures[i]; if (texture == null) { texture = new Texture(); Textures[i] = texture; } uint colorNxMapSize = decompressedStream.ReadUInt32(); texture.ColorNXMap = assetManager.CreateAsset <Dds>(decompressedStream.ReadBytes((int)colorNxMapSize)); uint specNyMapSize = decompressedStream.ReadUInt32(); texture.SpecNyMap = assetManager.CreateAsset <Dds>(decompressedStream.ReadBytes((int)specNyMapSize)); uint extraData1Size = decompressedStream.ReadUInt32(); decompressedStream.ReadBytes(texture.ExtraData1, (int)extraData1Size); uint extraData2Size = decompressedStream.ReadUInt32(); decompressedStream.ReadBytes(texture.ExtraData2, (int)extraData2Size); uint extraData3Size = decompressedStream.ReadUInt32(); decompressedStream.ReadBytes(texture.ExtraData3, (int)extraData3Size); uint extraData4Size = decompressedStream.ReadUInt32(); decompressedStream.ReadBytes(texture.ExtraData4, (int)extraData4Size); } //Verts Per Side VertsPerSide = decompressedStream.ReadUInt32(); //Height Maps uint heightMapCount = decompressedStream.ReadUInt32(); int n = (int)(heightMapCount / 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < n; j++) { Dictionary <int, HeightMap> entry; if (!HeightMaps.ContainsKey(i)) { entry = new Dictionary <int, HeightMap>(); HeightMaps[i] = entry; } else { entry = HeightMaps[i]; } HeightMap heightMapData = new HeightMap(); heightMapData.Val1 = decompressedStream.ReadInt16(); heightMapData.Val2 = decompressedStream.Read1Byte(); heightMapData.Val3 = decompressedStream.Read1Byte(); entry[j] = heightMapData; } } //Indices uint indexCount = decompressedStream.ReadUInt32(); for (int i = 0; i < indexCount; i++) { Indices.Add(decompressedStream.ReadUInt16()); } //Verts uint vertCount = decompressedStream.ReadUInt32(); for (int i = 0; i < vertCount; i++) { Vertex vertex = new Vertex(); vertex.X = decompressedStream.ReadInt16(); vertex.Y = decompressedStream.ReadInt16(); vertex.HeightFar = decompressedStream.ReadInt16(); vertex.HeightNear = decompressedStream.ReadInt16(); vertex.Color = decompressedStream.ReadUInt32(); Vertices.Add(vertex); } //TODO HACK - Daybreak, why are some chunks (that have a version 2 header) actually version 1? long offset = decompressedStream.Position; try { //Render Batches uint renderBatchCount = decompressedStream.ReadUInt32(); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); if (ChunkType == ChunkType.H1Z1_Planetside2V2) { renderBatch.Unknown = decompressedStream.ReadUInt32(); } renderBatch.IndexOffset = decompressedStream.ReadUInt32(); renderBatch.IndexCount = decompressedStream.ReadUInt32(); renderBatch.VertexOffset = decompressedStream.ReadUInt32(); renderBatch.VertexCount = decompressedStream.ReadUInt32(); RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = decompressedStream.ReadUInt32(); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = decompressedStream.ReadBytes(320).ToList(); OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = decompressedStream.ReadUInt32(); for (int i = 0; i < unknownShort1Count; i++) { UnknownShorts1.Add(decompressedStream.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = decompressedStream.ReadUInt32(); for (int i = 0; i < unknownVectors1Count; i++) { UnknownVectors1.Add(new Vector3(decompressedStream.ReadSingle(), decompressedStream.ReadSingle(), decompressedStream.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = decompressedStream.ReadUInt32(); if (tileOccluderCount > 16) { throw new ArgumentOutOfRangeException(); } for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = decompressedStream.ReadBytes(64).ToList(); TileOccluderInfos.Add(tileOccluderInfo); } } catch (Exception) { // Some of these may have been populated from the "try". RenderBatches.Clear(); OptimizedDraws.Clear(); UnknownShorts1.Clear(); UnknownVectors1.Clear(); TileOccluderInfos.Clear(); decompressedStream.Position = offset; //Render Batches uint renderBatchCount = decompressedStream.ReadUInt32(); for (int i = 0; i < renderBatchCount; i++) { RenderBatch renderBatch = new RenderBatch(); renderBatch.IndexOffset = decompressedStream.ReadUInt32(); renderBatch.IndexCount = decompressedStream.ReadUInt32(); renderBatch.VertexOffset = decompressedStream.ReadUInt32(); renderBatch.VertexCount = decompressedStream.ReadUInt32(); RenderBatches.Add(renderBatch); } //Optimized Draw uint optimizedDrawCount = decompressedStream.ReadUInt32(); for (int i = 0; i < optimizedDrawCount; i++) { OptimizedDraw optimizedDraw = new OptimizedDraw(); optimizedDraw.Data = decompressedStream.ReadBytes(320).ToList(); OptimizedDraws.Add(optimizedDraw); } //Unknown Data uint unknownShort1Count = decompressedStream.ReadUInt32(); for (int i = 0; i < unknownShort1Count; i++) { UnknownShorts1.Add(decompressedStream.ReadUInt16()); } //Unknown Data uint unknownVectors1Count = decompressedStream.ReadUInt32(); for (int i = 0; i < unknownVectors1Count; i++) { UnknownVectors1.Add(new Vector3(decompressedStream.ReadSingle(), decompressedStream.ReadSingle(), decompressedStream.ReadSingle())); } //Tile Occluder Info uint tileOccluderCount = decompressedStream.ReadUInt32(); if (tileOccluderCount > 16) { return(false); } for (int i = 0; i < tileOccluderCount; i++) { TileOccluderInfo tileOccluderInfo = new TileOccluderInfo(); tileOccluderInfo.Data = decompressedStream.ReadBytes(64).ToList(); TileOccluderInfos.Add(tileOccluderInfo); } } } return(true); }
public static LoadError LoadFromStream(Stream stream, out Cnk0 cnk0) { if (stream == null) { cnk0 = null; return(LoadError.NullStream); } BinaryReader binaryReader = new BinaryReader(stream); //header char[] magic = binaryReader.ReadChars(4); if (magic[0] != 'C' || magic[1] != 'N' || magic[2] != 'K' || magic[3] != '0') { cnk0 = null; return(LoadError.BadHeader); } int version = binaryReader.ReadInt32(); if (version != VERSION) { cnk0 = null; return(LoadError.VersionMismatch); } uint uncompressedSize = binaryReader.ReadUInt32(); uint compressedSize = binaryReader.ReadUInt32(); byte[] inputBuffer = binaryReader.ReadBytes((int)compressedSize); binaryReader.Close(); byte[] outputBuffer = new byte[uncompressedSize]; Lzham.ZStream zStream = new Lzham.ZStream(); Lzham.ZInflateInit2(zStream, 20); zStream.AvailableInputBytes = compressedSize; zStream.AvailableOutputBytes = uncompressedSize; GCHandle inputBufferGCHandle = GCHandle.Alloc(inputBuffer, GCHandleType.Pinned); GCHandle outputBufferGCHandle = GCHandle.Alloc(outputBuffer, GCHandleType.Pinned); zStream.NextInputByte = inputBufferGCHandle.AddrOfPinnedObject(); zStream.NextOutputByte = outputBufferGCHandle.AddrOfPinnedObject(); Lzham.ZInflate(zStream, (int)Lzham.ZFlush.Finish); Lzham.ZInflateEnd(zStream); inputBufferGCHandle.Free(); outputBufferGCHandle.Free(); MemoryStream memoryStream = new MemoryStream(outputBuffer); binaryReader = new BinaryReader(memoryStream); cnk0 = new Cnk0(); //tiles uint tileCount = binaryReader.ReadUInt32(); cnk0.Tiles = new Tile[tileCount]; for (uint i = 0; i < tileCount; ++i) { Tile tile; if (Tile.LoadFromStream(memoryStream, out tile) != Tile.LoadError.None) { cnk0 = null; return(LoadError.BadTile); } cnk0.Tiles[i] = tile; } //unknown block uint unknown0 = binaryReader.ReadUInt32(); uint unknown1 = binaryReader.ReadUInt32(); binaryReader.BaseStream.Seek(unknown1 * 4, SeekOrigin.Current); //indices uint indexCount = binaryReader.ReadUInt32(); cnk0.Indices = new ushort[indexCount]; for (int i = 0; i < indexCount; ++i) { cnk0.Indices[i] = binaryReader.ReadUInt16(); } //vertices uint vertexCount = binaryReader.ReadUInt32(); cnk0.Vertices = new Vertex[vertexCount]; for (int i = 0; i < vertexCount; ++i) { Vertex vertex; if (Vertex.LoadFromStream(binaryReader.BaseStream, out vertex) != Vertex.LoadError.None) { cnk0 = null; return(LoadError.BadVertex); } cnk0.Vertices[i] = vertex; } //render batches uint renderBatchCount = binaryReader.ReadUInt32(); cnk0.RenderBatches = new RenderBatch[renderBatchCount]; for (uint i = 0; i < renderBatchCount; ++i) { RenderBatch renderBatch; if (RenderBatch.LoadFromStream(binaryReader.BaseStream, out renderBatch) != RenderBatch.LoadError.None) { cnk0 = null; return(LoadError.BadRenderBatch); } cnk0.RenderBatches[i] = renderBatch; } binaryReader.Close(); return(LoadError.None); }
internal protected override void UpdateDisplay(RenderBatch renderBatch) { }
public static Terrain LoadADT(string filename, CacheStorage cache, int shaderProgram) { WoWFormatLib.Structs.ADT.ADT adt = new WoWFormatLib.Structs.ADT.ADT(); Terrain result = new Terrain(); //Load ADT from file if (WoWFormatLib.Utils.CASC.cascHandler.FileExists(filename)) { var adtreader = new ADTReader(); adtreader.LoadADT(filename); adt = adtreader.adtfile; } else { throw new Exception("ADT " + filename + " does not exist!"); } float TileSize = 1600.0f / 3.0f; //533.333 float ChunkSize = TileSize / 16.0f; //33.333 float UnitSize = ChunkSize / 8.0f; //4.166666 float MapMidPoint = 32.0f / ChunkSize; List <Vertex> verticelist = new List <Vertex>(); List <Int32> indicelist = new List <Int32>(); result.vao = GL.GenVertexArray(); GL.BindVertexArray(result.vao); result.vertexBuffer = GL.GenBuffer(); result.indiceBuffer = GL.GenBuffer(); List <Material> materials = new List <Material>(); for (int ti = 0; ti < adt.textures.filenames.Count(); ti++) { Material material = new Material(); material.filename = adt.textures.filenames[ti]; material.textureID = BLPLoader.LoadTexture(adt.textures.filenames[ti], cache); if (adt.texParams != null && adt.texParams.Count() >= ti) { material.scale = (float)Math.Pow(2, (adt.texParams[ti].flags & 0xF0) >> 4); if (adt.texParams[ti].height != 0.0 || adt.texParams[ti].offset != 1.0) { material.heightScale = adt.texParams[ti].height; material.heightOffset = adt.texParams[ti].offset; var heightName = adt.textures.filenames[ti].Replace(".blp", "_h.blp"); if (!WoWFormatLib.Utils.CASC.cascHandler.FileExists(heightName)) { Console.WriteLine("Height texture: " + heightName + " does not exist! Falling back to original texture (hack).."); material.heightTexture = BLPLoader.LoadTexture(adt.textures.filenames[ti], cache); } else { material.heightTexture = BLPLoader.LoadTexture(heightName, cache); } } else { material.heightScale = 0.0f; material.heightOffset = 1.0f; } } else { material.heightScale = 0.0f; material.heightOffset = 1.0f; material.scale = 1.0f; } materials.Add(material); } var initialChunkY = adt.chunks[0].header.position.Y; var initialChunkX = adt.chunks[0].header.position.X; List <RenderBatch> renderBatches = new List <RenderBatch>(); for (uint c = 0; c < adt.chunks.Count(); c++) { var chunk = adt.chunks[c]; int off = verticelist.Count(); RenderBatch batch = new RenderBatch(); batch.groupID = c; for (int i = 0, idx = 0; i < 17; i++) { for (int j = 0; j < (((i % 2) != 0) ? 8 : 9); j++) { Vertex v = new Vertex(); v.Normal = new Vector3(chunk.normals.normal_0[idx], chunk.normals.normal_1[idx], chunk.normals.normal_2[idx]); if (chunk.vertexShading.red != null) { v.Color = new Vector4(chunk.vertexShading.blue[idx] / 255.0f, chunk.vertexShading.green[idx] / 255.0f, chunk.vertexShading.red[idx] / 255.0f, chunk.vertexShading.alpha[idx] / 255.0f); } else { v.Color = new Vector4(0.5f, 0.5f, 0.5f, 1.0f); } v.TexCoord = new Vector2((j + (((i % 2) != 0) ? 0.5f : 0f)) / 8f, (i * 0.5f) / 8f); v.Position = new Vector3(chunk.header.position.X - (i * UnitSize * 0.5f), chunk.header.position.Y - (j * UnitSize), chunk.vertices.vertices[idx++] + chunk.header.position.Z); if ((i % 2) != 0) { v.Position.Y -= 0.5f * UnitSize; } verticelist.Add(v); } } result.startPos = verticelist[0]; batch.firstFace = (uint)indicelist.Count(); for (int j = 9; j < 145; j++) { indicelist.AddRange(new Int32[] { off + j + 8, off + j - 9, off + j }); indicelist.AddRange(new Int32[] { off + j - 9, off + j - 8, off + j }); indicelist.AddRange(new Int32[] { off + j - 8, off + j + 9, off + j }); indicelist.AddRange(new Int32[] { off + j + 9, off + j + 8, off + j }); if ((j + 1) % (9 + 8) == 0) { j += 9; } } batch.numFaces = (uint)(indicelist.Count()) - batch.firstFace; var layermats = new List <uint>(); var alphalayermats = new List <int>(); var layerscales = new List <float>(); var layerheights = new List <int>(); batch.heightScales = new Vector4(); batch.heightOffsets = new Vector4(); for (int li = 0; li < adt.texChunks[c].layers.Count(); li++) { if (adt.texChunks[c].alphaLayer != null) { alphalayermats.Add(BLPLoader.GenerateAlphaTexture(adt.texChunks[c].alphaLayer[li].layer)); } layermats.Add((uint)cache.materials[adt.textures.filenames[adt.texChunks[c].layers[li].textureId].ToLower()]); var curMat = materials.Where(material => material.filename == adt.textures.filenames[adt.texChunks[c].layers[li].textureId]).Single(); layerscales.Add(curMat.scale); layerheights.Add(curMat.heightTexture); batch.heightScales[li] = curMat.heightScale; batch.heightOffsets[li] = curMat.heightOffset; } batch.materialID = layermats.ToArray(); batch.alphaMaterialID = alphalayermats.ToArray(); batch.scales = layerscales.ToArray(); batch.heightMaterialIDs = layerheights.ToArray(); int[] indices = indicelist.ToArray(); Vertex[] vertices = verticelist.ToArray(); GL.BindBuffer(BufferTarget.ArrayBuffer, result.vertexBuffer); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vertices.Count() * 12 * sizeof(float)), vertices, BufferUsageHint.StaticDraw); //var normalAttrib = GL.GetAttribLocation(shaderProgram, "normal"); //GL.EnableVertexAttribArray(normalAttrib); //GL.VertexAttribPointer(normalAttrib, 3, VertexAttribPointerType.Float, false, sizeof(float) * 11, sizeof(float) * 0); var colorAttrib = GL.GetAttribLocation(shaderProgram, "color"); GL.EnableVertexAttribArray(colorAttrib); GL.VertexAttribPointer(colorAttrib, 4, VertexAttribPointerType.Float, false, sizeof(float) * 12, sizeof(float) * 3); var texCoordAttrib = GL.GetAttribLocation(shaderProgram, "texCoord"); GL.EnableVertexAttribArray(texCoordAttrib); GL.VertexAttribPointer(texCoordAttrib, 2, VertexAttribPointerType.Float, false, sizeof(float) * 12, sizeof(float) * 7); var posAttrib = GL.GetAttribLocation(shaderProgram, "position"); GL.EnableVertexAttribArray(posAttrib); GL.VertexAttribPointer(posAttrib, 3, VertexAttribPointerType.Float, false, sizeof(float) * 12, sizeof(float) * 9); GL.BindBuffer(BufferTarget.ElementArrayBuffer, result.indiceBuffer); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(indices.Length * sizeof(int)), indices, BufferUsageHint.StaticDraw); renderBatches.Add(batch); } result.renderBatches = renderBatches.ToArray(); //result.doodads = doodads.ToArray(); //result.worldModelBatches = worldModelBatches.ToArray(); cache.terrain.Add(filename, result); return(result); }