コード例 #1
0
        public SpriteFont(string name, byte[] data, int size, float scale, SheetBuilder builder)
        {
            if (builder.Type != SheetT.BGRA)
            {
                throw new ArgumentException("The sheet builder must create BGRA sheets.", "builder");
            }

            deviceScale  = scale;
            this.size    = size;
            this.builder = builder;

            face = new Face(Library, data, 0);
            face.SetPixelSizes((uint)(size * deviceScale), (uint)(size * deviceScale));

            glyphs = new Cache <Pair <char, Color>, GlyphInfo>(CreateGlyph);

            //PERF: Cache these delegates for Measure calls
            Func <char, float> characterWidth = character => glyphs[Pair.New(character, Color.White)].Advance;

            lineWidth = line => line.Sum(characterWidth) / deviceScale;

            if (size <= 24)
            {
                PrecacheColor(Color.White, name);
            }
        }
コード例 #2
0
        public void EndFrame()
        {
            if (!isInFrame)
            {
                throw new InvalidOperationException("BeginFrame has not been called,There is no frame to end.");
            }
            isInFrame    = false;
            sheetBuilder = null;
            if (doRender.Count == 0)
            {
                return;
            }

            Sheet        currentSheet = null;
            IFrameBuffer fbo          = null;

            foreach (var v in doRender)
            {
                //Change sheet
                if (v.First != currentSheet)
                {
                    if (fbo != null)
                    {
                        DisableFrameBuffer(fbo);
                    }

                    currentSheet = v.First;
                    fbo          = EnableFrameBuffer(currentSheet);
                }

                v.Second();
            }

            if (fbo != null)
            {
                DisableFrameBuffer(fbo);
            }

            doRender.Clear();
        }
コード例 #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="wr"></param>
        /// <param name="models"></param>
        /// <param name="camera"></param>
        /// <param name="scale">缩放</param>
        /// <param name="groundNormal"></param>
        /// <param name="lightSource"></param>
        /// <param name="lightAmbientColor"></param>
        /// <param name="lightDiffuseColor"></param>
        /// <param name="color"></param>
        /// <param name="normals"></param>
        /// <param name="shadowPalette"></param>
        /// <returns></returns>
        public ModelRenderProxy RenderAsync(WorldRenderer wr, IEnumerable <ModelAnimation> models, WRot camera, float scale,
                                            float[] groundNormal, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadowPalette)
        {
            if (!isInFrame)
            {
                throw new InvalidOperationException("BeginFrame has not been called.You cannot render until a frame has been started.");
            }

            //Correct for inverted y-axis
            var scaleTransform = Util.ScaleMatrix(scale, scale, scale);

            //Correct for bogus light source definition
            var lightYaw        = Util.MakeFloatMatrix(new WRot(WAngle.Zero, WAngle.Zero, -lightSource.Yaw).AsMatrix());
            var lightPitch      = Util.MakeFloatMatrix(new WRot(WAngle.Zero, -lightSource.Pitch, WAngle.Zero).AsMatrix());
            var shadowTransform = Util.MatrixMultiply(lightPitch, lightYaw);

            var invShadowTransform = Util.MatrixInverse(shadowTransform);
            var cameraTransform    = Util.MakeFloatMatrix(camera.AsMatrix());
            var invCameraTransform = Util.MatrixInverse(cameraTransform);

            if (invCameraTransform == null)
            {
                throw new InvalidOperationException("Failed to invert the cameraTransform matrix during RenderAsync");
            }


            //Sprite rectangle
            var tl = new Vector2(float.MaxValue, float.MaxValue);
            var br = new Vector2(float.MinValue, float.MinValue);

            //Shadow sprite rectangle

            var stl = new Vector2(float.MaxValue, float.MaxValue);
            var sbr = new Vector2(float.MinValue, float.MinValue);

            foreach (var m in models)
            {
                // Convert screen offset back to world coords
                var offsetVec       = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc()));
                var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]);

                var worldTransform = m.RotationFunc().Aggregate(Util.IdentityMatrix(), (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x));
                worldTransform = Util.MatrixMultiply(scaleTransform, worldTransform);
                worldTransform = Util.MatrixMultiply(offsetTransform, worldTransform);

                var bounds       = m.Model.Bounds(m.FrameFunc());
                var worldBounds  = Util.MatrixAABBMultiply(worldTransform, bounds);
                var screenBounds = Util.MatrixAABBMultiply(cameraTransform, worldBounds);
                var shadowBounds = Util.MatrixAABBMultiply(shadowTransform, worldBounds);

                //Aggregate bounds rects
                tl  = Vector2.Min(tl, new Vector2(screenBounds[0], screenBounds[1]));
                br  = Vector2.Max(br, new Vector2(screenBounds[3], screenBounds[4]));
                stl = Vector2.Min(stl, new Vector2(shadowBounds[0], shadowBounds[1]));
                sbr = Vector2.Max(sbr, new Vector2(shadowBounds[3], shadowBounds[4]));
            }

            //Inflate rects to ensure redering is within bounds
            tl  -= SpritePadding;
            br  += SpritePadding;
            stl -= SpritePadding;
            sbr += SpritePadding;

            //Corners of the shadow quad,in shadow-space
            var corners = new float[][]
            {
                new[] { stl.X, stl.Y, 0, 1 },
                new[] { sbr.X, sbr.Y, 0, 1 },
                new[] { sbr.X, stl.Y, 0, 1 },
                new[] { stl.X, sbr.Y, 0, 1 }
            };

            var shadowScreenTransform = Util.MatrixMultiply(cameraTransform, invShadowTransform);
            var shadowGroundNormal    = Util.MatrixVectorMultiply(shadowTransform, groundNormal);
            var screenCorners         = new Vector3[4];

            for (var j = 0; j < 4; j++)
            {
                //Project to ground plane.
                corners[j][2] = -(corners[j][1] * shadowGroundNormal[1] / shadowGroundNormal[2] +
                                  corners[j][0] * shadowGroundNormal[0] / shadowGroundNormal[2]);

                //Rotate to camera-space
                corners[j]       = Util.MatrixVectorMultiply(shadowScreenTransform, corners[j]);
                screenCorners[j] = new Vector3(corners[j][0], corners[j][1], 0);
            }

            //Shadows are rendered at twice the resolution to reduce artifacts.
            //阴影以两倍的分辨率渲染以减少伪像
            Size spriteSize, shadowSpriteSize;
            Int2 spriteOffset, shadowSpriteOffset;

            CalculateSpriteGeometry(tl, br, 1, out spriteSize, out spriteOffset);
            CalculateSpriteGeometry(stl, sbr, 2, out shadowSpriteSize, out shadowSpriteOffset);

            if (sheetBuilder == null)
            {
                sheetBuilder = new SheetBuilder(SheetT.BGRA, AllocateSheet);
            }
            var sprite       = sheetBuilder.Allocate(spriteSize, 0, spriteOffset);
            var shadowSprite = sheetBuilder.Allocate(shadowSpriteSize, 0, shadowSpriteOffset);

            var sb  = sprite.Bounds;
            var ssb = shadowSprite.Bounds;

            var spriteCenter = new Vector2(sb.Left + sb.Width / 2, sb.Top + sb.Height / 2);
            var shadowCenter = new Vector2(ssb.Left + ssb.Width / 2, ssb.Top + ssb.Height / 2);

            var translateMtx              = Util.TranslationMatrix(spriteCenter.X - spriteOffset.X, renderer.SheetSize - (spriteCenter.Y - spriteOffset.Y), 0);
            var shadowTranslateMtx        = Util.TranslationMatrix(shadowCenter.X - shadowSpriteOffset.X, renderer.SheetSize - (shadowCenter.Y - shadowSpriteOffset.Y), 0);
            var correctionTransform       = Util.MatrixMultiply(translateMtx, FlipMtx);
            var shadowCorrectionTransform = Util.MatrixMultiply(shadowTranslateMtx, ShadowScaleFlipMtx);

            doRender.Add(Pair.New <Sheet, Action>(sprite.Sheet, () =>
            {
                foreach (var m in models)
                {
                    //Convert screen offset to world offset
                    var offsetVec       = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(m.OffsetFunc()));
                    var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]);

                    var rotations = m.RotationFunc().Aggregate(Util.IdentityMatrix(),
                                                               (x, y) => Util.MatrixMultiply(Util.MakeFloatMatrix(y.AsMatrix()), x));

                    var worldTransform = Util.MatrixMultiply(scaleTransform, rotations);
                    worldTransform     = Util.MatrixMultiply(offsetTransform, worldTransform);

                    var transform = Util.MatrixMultiply(cameraTransform, worldTransform);
                    transform     = Util.MatrixMultiply(correctionTransform, transform);

                    var shadow = Util.MatrixMultiply(shadowTransform, worldTransform);
                    shadow     = Util.MatrixMultiply(shadowCorrectionTransform, shadow);

                    var lightTransform = Util.MatrixMultiply(Util.MatrixInverse(rotations), invShadowTransform);

                    var frame = m.FrameFunc();

                    for (uint i = 0; i < m.Model.Sections; i++)
                    {
                        var rd = m.Model.RenderData(i);
                        var t  = m.Model.TransformationMatrix(i, frame);
                        var it = Util.MatrixInverse(t);
                        if (it == null)
                        {
                            throw new InvalidOperationException("Failed to invert the transformed matrix of frame {0} during RenderAsync.".F(i));
                        }

                        // Transform light vector from shadow -> world -> limb coords
                        var lightDirection = ExtractRotationVector(Util.MatrixMultiply(it, lightTransform));

                        Render(rd, wr.World.ModelCache, Util.MatrixMultiply(transform, t), lightDirection,
                               lightAmbientColor, lightDiffuseColor, color.TextureMidIndex, normals.TextureMidIndex);

                        //Disable shadow normals by forcing zero diffuse and identity ambient light
                        if (m.ShowShadow)
                        {
                            Render(rd, wr.World.ModelCache, Util.MatrixMultiply(shadow, t), lightDirection,
                                   ShadowAmbient, ShadowDiffuse, shadowPalette.TextureMidIndex, normals.TextureMidIndex);
                        }
                    }
                }
            }));


            var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, ZVector);

            screenLightVector = Util.MatrixVectorMultiply(cameraTransform, screenLightVector);
            return(new ModelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2] / screenLightVector[1]));
        }
コード例 #4
0
ファイル: Theater.cs プロジェクト: hadow/Commander
        public Theater(TileSet tileset)
        {
            this.tileset = tileset;

            var allocated = false;

            Func <Sheet> allocate = () =>
            {
                if (allocated)
                {
                    throw new SheetOverflowException("Terrain sheet overflow.Try increasing the tileset SheetSize parameter.");
                }
                allocated = true;
                return(new Sheet(SheetT.Indexed, new Size(tileset.SheetSize, tileset.SheetSize)));
            };

            sheetBuilder = new SheetBuilder(SheetT.Indexed, allocate);
            random       = new MersenneTwister();

            var frameCache = new FrameCache(WarGame.ModData.DefaultFileSystem, WarGame.ModData.SpriteLoaders);

            foreach (var t in tileset.Templates)
            {
                var variants = new List <Sprite[]>();

                foreach (var i in t.Value.Images)
                {
                    var allFrames  = frameCache[i];
                    var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length;
                    var indices    = t.Value.Frames != null ? t.Value.Frames : Enumerable.Range(0, frameCount);
                    variants.Add(indices.Select(j => {
                        var f    = allFrames[j];
                        var tile = t.Value.Contains(j)?t.Value[j]:null;

                        //The internal z axis is inverted from expectation (negative is closer)
                        var zOffset = tile != null ? -tile.ZOffset : 0;

                        var zRamp = tile != null ? tile.ZRamp : 1f;

                        var offset = new Vector3(f.Offset, zOffset);

                        var s = sheetBuilder.Allocate(f.Size, zRamp, offset);

                        Util.FastCopyIntoChannel(s, f.Data);

                        if (tileset.EnableDepth)
                        {
                            var ss = sheetBuilder.Allocate(f.Size, zRamp, offset);
                            Util.FastCopyIntoChannel(ss, allFrames[j + frameCount].Data);

                            //s and ss are guaranteed to use the same sheet because of the custom terrain sheet allocation.
                            s = new SpriteWithSecondaryData(s, ss.Bounds, ss.Channel);
                        }
                        return(s);
                    }).ToArray());
                }

                var allSprites = variants.SelectMany(s => s);

                if (tileset.IgnoreTileSpriteOffsets)
                {
                    allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new Vector3(Vector2.Zero, s.Offset.Z), s.Channel, s.BlendMode));
                }

                templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length));
            }

            missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1));

            Sheet.ReleaseBuffer();
        }
コード例 #5
0
ファイル: SpriteLoader.cs プロジェクト: hadow/Commander
 public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
 {
     this.SheetBuilder = sheetBuilder;
     this.loaders      = loaders;
     this.fileSystem   = fileSystem;
 }
コード例 #6
0
ファイル: SpriteLoader.cs プロジェクト: hadow/Commander
 /// <summary>
 ///
 /// </summary>
 /// <param name="fileSystem"></param>
 /// <param name="filename"></param>
 /// <param name="loaders"></param>
 /// <param name="sheetBuilder"></param>
 /// <returns></returns>
 public static Sprite[] GetSprites(IReadOnlyFileSystem fileSystem, string filename, ISpriteLoader[] loaders, SheetBuilder sheetBuilder)
 {
     return(GetFrames(fileSystem, filename, loaders).Select(a => sheetBuilder.Add(a)).ToArray());
 }