Esempio n. 1
0
        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);
        }