public unsafe Dx11RenderingDrawingRoom(Dx11RenderingDevice device, Description description) { Device = device; TextureView = ((Dx11RenderingTextureAllocator)(description.TextureAllocator)).TextureView; TextureAllocator = description.TextureAllocator; Vector2 textureScaling = new Vector2(16777216.0f) / new Vector2(TextureAllocator.Size.X, TextureAllocator.Size.Y); RoomGeometry roomGeometry = description.Room.RoomGeometry; // Create buffer Vector3 worldPos = description.Room.WorldPos + description.Offset; int singleSidedVertexCount = roomGeometry.VertexPositions.Count; int vertexCount = VertexCount = singleSidedVertexCount + roomGeometry.DoubleSidedTriangleCount * 3; if (vertexCount == 0) { return; } VertexBufferSize = vertexCount * (sizeof(Vector3) + sizeof(uint) + sizeof(uint) + sizeof(ulong) + sizeof(uint)); fixed(byte *data = new byte[VertexBufferSize]) { Vector3 *positions = (Vector3 *)(data); uint * colors = (uint *)(data + vertexCount * sizeof(Vector3)); uint * overlays = (uint *)(data + vertexCount * (sizeof(Vector3) + sizeof(uint))); ulong * uvwAndBlendModes = (ulong *)(data + vertexCount * (sizeof(Vector3) + sizeof(uint) + sizeof(uint))); uint * editorUVAndSectorTexture = (uint *)(data + vertexCount * (sizeof(Vector3) + sizeof(uint) + sizeof(uint) + sizeof(ulong))); // Setup vertices for (int i = 0; i < singleSidedVertexCount; ++i) { positions[i] = roomGeometry.VertexPositions[i] + worldPos; } for (int i = 0; i < singleSidedVertexCount; ++i) { colors[i] = Dx11RenderingDevice.CompressColor(roomGeometry.VertexColors[i]); } for (int i = 0; i < singleSidedVertexCount; ++i) { Vector2 vertexEditorUv = roomGeometry.VertexEditorUVs[i]; uint editorUv = 0; editorUv |= (uint)((int)vertexEditorUv.X) & 3; editorUv |= ((uint)((int)vertexEditorUv.Y) & 3) << 2; editorUVAndSectorTexture[i] = editorUv; } { SectorInfo lastSectorInfo = new SectorInfo(-1, -1, BlockFace.Floor); uint lastSectorTexture = 0; uint overlay = 0; for (int i = 0, triangleCount = singleSidedVertexCount / 3; i < triangleCount; ++i) { SectorInfo currentSectorInfo = roomGeometry.TriangleSectorInfo[i]; if (!lastSectorInfo.Equals(currentSectorInfo)) { SectorTextureResult result = description.SectorTextureGet(description.Room, currentSectorInfo.Pos.X, currentSectorInfo.Pos.Y, currentSectorInfo.Face); lastSectorInfo = currentSectorInfo; lastSectorTexture = 0; if (result.SectorTexture != SectorTexture.None) { // Use sector texture lastSectorTexture = 0x40 | (((uint)result.SectorTexture - 1) << 8); } else { // Use sector color lastSectorTexture = (((uint)(result.Color.X * 255)) << 8) | (((uint)(result.Color.Y * 255)) << 16) | (((uint)(result.Color.Z * 255)) << 24); } // Highlight / dim sectors if (result.Highlighted) { lastSectorTexture |= 0x10; } if (result.Dimmed) { lastSectorTexture |= 0x20; } // Indicate selected textured faces if (result.Selected && roomGeometry.TriangleTextureAreas[i].Texture != null) { lastSectorTexture |= 0x80; } // Assign overlay color which will be used in geometry mode if face has service texture (e.g. arrows) overlay = Dx11RenderingDevice.CompressColor(new Vector3(result.Overlay.X, result.Overlay.Y, result.Overlay.Z), (result.Hidden ? 0.4f : 1.0f), false); } editorUVAndSectorTexture[i * 3 + 0] |= lastSectorTexture; editorUVAndSectorTexture[i * 3 + 1] |= lastSectorTexture; editorUVAndSectorTexture[i * 3 + 2] |= lastSectorTexture; overlays[i * 3 + 0] = overlay; overlays[i * 3 + 1] = overlay; overlays[i * 3 + 2] = overlay; } } RetryTexturing: ; { int doubleSidedVertexIndex = singleSidedVertexCount; for (int i = 0, triangleCount = singleSidedVertexCount / 3; i < triangleCount; ++i) { TextureArea texture = roomGeometry.TriangleTextureAreas[i]; if (texture.Texture == null) { // Render as geometry uvwAndBlendModes[i * 3 + 0] = 1ul << 24; uvwAndBlendModes[i * 3 + 1] = 1ul << 24; uvwAndBlendModes[i * 3 + 2] = 1ul << 24; } else if (texture.Texture is TextureInvisible) { // Render as invisible uvwAndBlendModes[i * 3 + 0] = 0ul << 24; uvwAndBlendModes[i * 3 + 1] = 0ul << 24; uvwAndBlendModes[i * 3 + 2] = 0ul << 24; } else { // Render as textured (the texture may turn out to be unavailable) if (texture.Texture.IsUnavailable) { // Texture is unvailable (i.e. file couldn't be loaded. ImageC image = Dx11RenderingDevice.TextureUnavailable; VectorInt3 position = TextureAllocator.Get(image); uvwAndBlendModes[i * 3 + 0] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 0]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); uvwAndBlendModes[i * 3 + 1] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 1]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); uvwAndBlendModes[i * 3 + 2] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 2]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); } else if (texture.TriangleCoordsOutOfBounds) { // Texture is available but coordinates are ouf of bounds ImageC image = Dx11RenderingDevice.TextureCoordOutOfBounds; VectorInt3 position = TextureAllocator.Get(image); uvwAndBlendModes[i * 3 + 0] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 0]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); uvwAndBlendModes[i * 3 + 1] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 1]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); uvwAndBlendModes[i * 3 + 2] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 2]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); } else if (!texture.ParentArea.IsZero && !texture.ParentArea.Intersects(texture.GetRect())) { // Texture is available but coordinates are ouf of bounds ImageC image = Dx11RenderingDevice.TextureCoordOutOfBounds; VectorInt3 position = TextureAllocator.Get(image); uvwAndBlendModes[i * 3 + 0] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 0]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); uvwAndBlendModes[i * 3 + 1] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 1]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); uvwAndBlendModes[i * 3 + 2] = Dx11RenderingDevice.CompressUvw(position, textureScaling, Vector2.Abs(roomGeometry.VertexEditorUVs[i * 3 + 2]) * (image.Size - VectorInt2.One) + new Vector2(0.5f), (uint)texture.BlendMode); } else { // Texture is available VectorInt3 position = TextureAllocator.GetForTriangle(texture); uvwAndBlendModes[i * 3 + 0] = Dx11RenderingDevice.CompressUvw(position, textureScaling, texture.TexCoord0, (uint)texture.BlendMode); uvwAndBlendModes[i * 3 + 1] = Dx11RenderingDevice.CompressUvw(position, textureScaling, texture.TexCoord1, (uint)texture.BlendMode); uvwAndBlendModes[i * 3 + 2] = Dx11RenderingDevice.CompressUvw(position, textureScaling, texture.TexCoord2, (uint)texture.BlendMode); } // Duplicate double sided triangles if (texture.DoubleSided) { positions[doubleSidedVertexIndex] = positions[i * 3 + 2]; colors[doubleSidedVertexIndex] = colors[i * 3 + 2]; overlays[doubleSidedVertexIndex] = overlays[i * 3 + 2]; uvwAndBlendModes[doubleSidedVertexIndex] = uvwAndBlendModes[i * 3 + 2]; editorUVAndSectorTexture[doubleSidedVertexIndex++] = editorUVAndSectorTexture[i * 3 + 2]; positions[doubleSidedVertexIndex] = positions[i * 3 + 1]; colors[doubleSidedVertexIndex] = colors[i * 3 + 1]; overlays[doubleSidedVertexIndex] = overlays[i * 3 + 1]; uvwAndBlendModes[doubleSidedVertexIndex] = uvwAndBlendModes[i * 3 + 1]; editorUVAndSectorTexture[doubleSidedVertexIndex++] = editorUVAndSectorTexture[i * 3 + 1]; positions[doubleSidedVertexIndex] = positions[i * 3 + 0]; colors[doubleSidedVertexIndex] = colors[i * 3 + 0]; overlays[doubleSidedVertexIndex] = overlays[i * 3 + 0]; uvwAndBlendModes[doubleSidedVertexIndex] = uvwAndBlendModes[i * 3 + 0]; editorUVAndSectorTexture[doubleSidedVertexIndex++] = editorUVAndSectorTexture[i * 3 + 0]; } } } if (doubleSidedVertexIndex != vertexCount) { throw new ArgumentException("Double sided triangle count of RoomGeometry is wrong!"); } // Retry texturing once at max if (TexturesInvalidated && !TexturesInvalidatedRetried) { TexturesInvalidatedRetried = true; goto RetryTexturing; } } // Create GPU resources VertexBuffer = new Buffer(device.Device, new IntPtr(data), new BufferDescription(VertexBufferSize, ResourceUsage.Immutable, BindFlags.VertexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 0)); VertexBufferBindings = new VertexBufferBinding[] { new VertexBufferBinding(VertexBuffer, sizeof(Vector3), (int)((byte *)positions - data)), new VertexBufferBinding(VertexBuffer, sizeof(uint), (int)((byte *)colors - data)), new VertexBufferBinding(VertexBuffer, sizeof(uint), (int)((byte *)overlays - data)), new VertexBufferBinding(VertexBuffer, sizeof(ulong), (int)((byte *)uvwAndBlendModes - data)), new VertexBufferBinding(VertexBuffer, sizeof(uint), (int)((byte *)editorUVAndSectorTexture - data)) }; VertexBuffer.SetDebugName("Room " + (description.Room.Name ?? "")); } TextureAllocator.GarbageCollectionCollectEvent.Add(GarbageCollectTexture); }