public Allocate ( |
||
imageSize | ||
Результат |
Vertex[] GenerateSlicePlane(int su, int sv, Func <int, int, VxlElement> first, Func <int, int, VxlElement> second, Func <int, int, float[]> coord) { var colors = new byte[su * sv]; var normals = new byte[su * sv]; var c = 0; for (var v = 0; v < sv; v++) { for (var u = 0; u < su; u++) { var voxel = first(u, v) ?? second(u, v); colors[c] = voxel == null ? (byte)0 : voxel.Color; normals[c] = voxel == null ? (byte)0 : voxel.Normal; c++; } } Sprite s = sheetBuilder.Allocate(new Size(su, sv)); Util.FastCopyIntoChannel(s, 0, colors); Util.FastCopyIntoChannel(s, 1, normals); s.sheet.CommitData(); var channels = new float2(channelSelect[(int)s.channel], channelSelect[(int)s.channel + 1]); return(new Vertex[4] { new Vertex(coord(0, 0), s.FastMapTextureCoords(0), channels), new Vertex(coord(su, 0), s.FastMapTextureCoords(1), channels), new Vertex(coord(su, sv), s.FastMapTextureCoords(3), channels), new Vertex(coord(0, sv), s.FastMapTextureCoords(2), channels) }); }
Vertex[] GenerateSlicePlane(int su, int sv, Func <int, int, VxlElement> first, Func <int, int, VxlElement> second, Func <int, int, float[]> coord) { var colors = new byte[su * sv]; var normals = new byte[su * sv]; var c = 0; for (var v = 0; v < sv; v++) { for (var u = 0; u < su; u++) { var voxel = first(u, v) ?? second(u, v); colors[c] = voxel == null ? (byte)0 : voxel.Color; normals[c] = voxel == null ? (byte)0 : voxel.Normal; c++; } } var s = sheetBuilder.Allocate(new Size(su, sv)); Util.FastCopyIntoChannel(s, 0, colors); Util.FastCopyIntoChannel(s, 1, normals); s.sheet.CommitData(); var channelP = channelSelect[(int)s.channel]; var channelC = channelSelect[(int)s.channel + 1]; return(new Vertex[4] { new Vertex(coord(0, 0), s.left, s.top, channelP, channelC), new Vertex(coord(su, 0), s.right, s.top, channelP, channelC), new Vertex(coord(su, sv), s.right, s.bottom, channelP, channelC), new Vertex(coord(0, sv), s.left, s.bottom, channelP, channelC) }); }
GlyphInfo CreateGlyph(Pair <char, Color> c) { var glyph = font.CreateGlyph(c.First, size, deviceScale); if (glyph.Data == null) { return(new GlyphInfo { Sprite = null, Advance = 0, Offset = int2.Zero }); } var s = builder.Allocate(glyph.Size); var g = new GlyphInfo { Sprite = s, Advance = glyph.Advance, Offset = glyph.Offset }; var dest = s.Sheet.GetData(); var destStride = s.Sheet.Size.Width * 4; for (var j = 0; j < s.Size.Y; j++) { for (var i = 0; i < s.Size.X; i++) { var p = glyph.Data[j * glyph.Size.Width + i]; if (p != 0) { var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left); var pmc = Util.PremultiplyAlpha(Color.FromArgb(p, c.Second)); dest[q] = pmc.B; dest[q + 1] = pmc.G; dest[q + 2] = pmc.R; dest[q + 3] = pmc.A; } } } s.Sheet.CommitBufferedData(); return(g); }
public Theater(TileSet tileset) { this.tileset = tileset; var allocated = false; var type = tileset.EnableDepth ? SheetType.DualIndexed : SheetType.Indexed; Func<Sheet> allocate = () => { if (allocated) throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); allocated = true; return new Sheet(type, new Size(tileset.SheetSize, tileset.SheetSize)); }; sheetBuilder = new SheetBuilder(type, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.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 s = sheetBuilder.Allocate(f.Size, f.Offset); Util.FastCopyIntoChannel(s, 0, f.Data); if (tileset.EnableDepth) Util.FastCopyIntoChannel(s, 1, allFrames[j + frameCount].Data); return s; }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, float2.Zero, s.Channel, s.BlendMode)); templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
Vertex[] GenerateSlicePlane(int su, int sv, Func <int, int, VxlElement> first, Func <int, int, VxlElement> second, Func <int, int, float3> coord) { var colors = new byte[su * sv]; var normals = new byte[su * sv]; var c = 0; for (var v = 0; v < sv; v++) { for (var u = 0; u < su; u++) { var voxel = first(u, v) ?? second(u, v); colors[c] = voxel == null ? (byte)0 : voxel.Color; normals[c] = voxel == null ? (byte)0 : voxel.Normal; c++; } } var size = new Size(su, sv); var s = sheetBuilder.Allocate(size); var t = sheetBuilder.Allocate(size); Util.FastCopyIntoChannel(s, colors); Util.FastCopyIntoChannel(t, normals); // s and t are guaranteed to use the same sheet because // of the custom voxel sheet allocation implementation s.Sheet.CommitBufferedData(); var channelP = ChannelSelect[(int)s.Channel]; var channelC = ChannelSelect[(int)t.Channel]; return(new Vertex[6] { new Vertex(coord(0, 0), s.Left, s.Top, t.Left, t.Top, channelP, channelC), new Vertex(coord(su, 0), s.Right, s.Top, t.Right, t.Top, channelP, channelC), new Vertex(coord(su, sv), s.Right, s.Bottom, t.Right, t.Bottom, channelP, channelC), new Vertex(coord(su, sv), s.Right, s.Bottom, t.Right, t.Bottom, channelP, channelC), new Vertex(coord(0, sv), s.Left, s.Bottom, t.Left, t.Bottom, channelP, channelC), new Vertex(coord(0, 0), s.Left, s.Top, t.Left, t.Top, channelP, channelC) }); }
GlyphInfo CreateGlyph(Pair <char, Color> c) { face.LoadChar(c.First, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); var size = new Size((int)face.Glyph.Metrics.Width, (int)face.Glyph.Metrics.Height); var s = builder.Allocate(size); var g = new GlyphInfo { Sprite = s, Advance = (float)face.Glyph.Metrics.HorizontalAdvance, Offset = new int2(face.Glyph.BitmapLeft, -face.Glyph.BitmapTop) }; // A new bitmap is generated each time this property is accessed, so we do need to dispose it. using (var bitmap = face.Glyph.Bitmap) { unsafe { var p = (byte *)bitmap.Buffer; var dest = s.Sheet.GetData(); var destStride = s.Sheet.Size.Width * 4; for (var j = 0; j < s.Size.Y; j++) { for (var i = 0; i < s.Size.X; i++) { if (p[i] != 0) { var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left); var pmc = Util.PremultiplyAlpha(Color.FromArgb(p[i], c.Second)); dest[q] = pmc.B; dest[q + 1] = pmc.G; dest[q + 2] = pmc.R; dest[q + 3] = pmc.A; } } p += bitmap.Pitch; } } } s.Sheet.CommitBufferedData(); return(g); }
/// <summary> /// Запускается из PrecacheColor. /// </summary> /// <param name="c">Буква шрифта.</param> /// <returns>Один визуальный образ буквы.</returns> GlyphInfo CreateGlyph(Pair <char, Color> c) { FontGlyph glyph = font.CreateGlyph(c.First); if (glyph.Data == null) { return(new GlyphInfo { Sprite = null, Advance = 0, Offset = int2.Zero }); } var s = builder.Allocate(glyph.Size); var g = new GlyphInfo { Sprite = s, Advance = glyph.Advance, Offset = glyph.Bearing, fg = glyph }; //var dest = s.Sheet.GetData(); //var destStride = s.Sheet.Size.Width * 4; //for (var j = 0; j < s.Size.Y; j++) //{ // for (var i = 0; i < s.Size.X; i++) // { // // тут происходит копирование байтов из глифа в "p", а после в dest общий массив текстуры. // var p = glyph.Data[j * glyph.Size.Width + i]; // if (p != 0) // { // var q = destStride * (j + s.Bounds.Top) + 4 * (i + s.Bounds.Left); // var pmc = Util.PremultiplyAlpha(Color.FromArgb(p, c.Second)); // dest[q] = pmc.B; // dest[q + 1] = pmc.G; // dest[q + 2] = pmc.R; // dest[q + 3] = pmc.A; // } // } //} //s.Sheet.CommitBufferedData(); return(g); }
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 float2(float.MaxValue, float.MaxValue); var br = new float2(float.MinValue, float.MinValue); // Shadow sprite rectangle var stl = new float2(float.MaxValue, float.MaxValue); var sbr = new float2(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 = float2.Min(tl, new float2(screenBounds[0], screenBounds[1])); br = float2.Max(br, new float2(screenBounds[3], screenBounds[4])); stl = float2.Min(stl, new float2(shadowBounds[0], shadowBounds[1])); sbr = float2.Max(sbr, new float2(shadowBounds[3], shadowBounds[4])); } // Inflate rects to ensure rendering 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 float3[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 float3(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 (sheetBuilderForFrame == null) { sheetBuilderForFrame = new SheetBuilder(SheetType.BGRA, AllocateSheet); } var sprite = sheetBuilderForFrame.Allocate(spriteSize, 0, spriteOffset); var shadowSprite = sheetBuilderForFrame.Allocate(shadowSpriteSize, 0, shadowSpriteOffset); var sb = sprite.Bounds; var ssb = shadowSprite.Bounds; var spriteCenter = new float2(sb.Left + sb.Width / 2, sb.Top + sb.Height / 2); var shadowCenter = new float2(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])); }
public VoxelRenderProxy RenderAsync(WorldRenderer wr, IEnumerable <VoxelAnimation> voxels, WRot camera, float scale, float[] groundNormal, WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor, PaletteReference color, PaletteReference normals, PaletteReference shadowPalette) { // 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); // Sprite rectangle var tl = new float2(float.MaxValue, float.MaxValue); var br = new float2(float.MinValue, float.MinValue); // Shadow sprite rectangle var stl = new float2(float.MaxValue, float.MaxValue); var sbr = new float2(float.MinValue, float.MinValue); foreach (var v in voxels) { // Convert screen offset back to world coords var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(v.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var worldTransform = v.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 = v.Voxel.Bounds(v.FrameFunc()); var worldBounds = Util.MatrixAABBMultiply(worldTransform, bounds); var screenBounds = Util.MatrixAABBMultiply(cameraTransform, worldBounds); var shadowBounds = Util.MatrixAABBMultiply(shadowTransform, worldBounds); // Aggregate bounds rects tl = float2.Min(tl, new float2(screenBounds[0], screenBounds[1])); br = float2.Max(br, new float2(screenBounds[3], screenBounds[4])); stl = float2.Min(stl, new float2(shadowBounds[0], shadowBounds[1])); sbr = float2.Max(sbr, new float2(shadowBounds[3], shadowBounds[4])); } // Inflate rects to ensure rendering is within bounds tl -= spritePadding; br += spritePadding; stl -= spritePadding; sbr += spritePadding; // Corners of the shadow quad, in shadow-space var corners = new float[][] { new float[] { stl.X, stl.Y, 0, 1 }, new float[] { sbr.X, sbr.Y, 0, 1 }, new float[] { sbr.X, stl.Y, 0, 1 }, new float[] { stl.X, sbr.Y, 0, 1 } }; var shadowScreenTransform = Util.MatrixMultiply(cameraTransform, invShadowTransform); var shadowGroundNormal = Util.MatrixVectorMultiply(shadowTransform, groundNormal); var screenCorners = new float2[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 float2(corners[j][0], corners[j][1]); } // Shadows are rendered at twice the resolution to reduce artefacts Size spriteSize, shadowSpriteSize; int2 spriteOffset, shadowSpriteOffset; CalculateSpriteGeometry(tl, br, 1, out spriteSize, out spriteOffset); CalculateSpriteGeometry(stl, sbr, 2, out shadowSpriteSize, out shadowSpriteOffset); var sprite = sheetBuilder.Allocate(spriteSize, spriteOffset); var shadowSprite = sheetBuilder.Allocate(shadowSpriteSize, shadowSpriteOffset); var sb = sprite.bounds; var ssb = shadowSprite.bounds; var spriteCenter = new float2(sb.Left + sb.Width / 2, sb.Top + sb.Height / 2); var shadowCenter = new float2(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 v in voxels) { // Convert screen offset to world offset var offsetVec = Util.MatrixVectorMultiply(invCameraTransform, wr.ScreenVector(v.OffsetFunc())); var offsetTransform = Util.TranslationMatrix(offsetVec[0], offsetVec[1], offsetVec[2]); var rotations = v.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 = v.FrameFunc(); for (uint i = 0; i < v.Voxel.Limbs; i++) { var rd = v.Voxel.RenderData(i); var t = v.Voxel.TransformationMatrix(i, frame); // Transform light vector from shadow -> world -> limb coords var lightDirection = ExtractRotationVector(Util.MatrixMultiply(Util.MatrixInverse(t), lightTransform)); Render(rd, Util.MatrixMultiply(transform, t), lightDirection, lightAmbientColor, lightDiffuseColor, color.Index, normals.Index); // Disable shadow normals by forcing zero diffuse and identity ambient light Render(rd, Util.MatrixMultiply(shadow, t), lightDirection, shadowAmbient, shadowDiffuse, shadowPalette.Index, normals.Index); } } })); var screenLightVector = Util.MatrixVectorMultiply(invShadowTransform, zVector); screenLightVector = Util.MatrixVectorMultiply(cameraTransform, screenLightVector); return(new VoxelRenderProxy(sprite, shadowSprite, screenCorners, -screenLightVector[2] / screenLightVector[1])); }
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(SheetType.Indexed, new Size(tileset.SheetSize, tileset.SheetSize))); }; sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.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 float3(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); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) { allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); } templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public Theater(TileSet tileset) { this.tileset = tileset; var allocated = false; var type = tileset.EnableDepth ? SheetType.DualIndexed : SheetType.Indexed; Func <Sheet> allocate = () => { if (allocated) { throw new SheetOverflowException("Terrain sheet overflow. Try increasing the tileset SheetSize parameter."); } allocated = true; return(new Sheet(type, new Size(tileset.SheetSize, tileset.SheetSize))); }; sheetBuilder = new SheetBuilder(type, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.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 s = sheetBuilder.Allocate(f.Size, f.Offset); Util.FastCopyIntoChannel(s, 0, f.Data); if (tileset.EnableDepth) { Util.FastCopyIntoChannel(s, 1, allFrames[j + frameCount].Data); } return(s); }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) { allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, float2.Zero, s.Channel, s.BlendMode)); } templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
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(SheetType.Indexed, new Size(tileset.SheetSize, tileset.SheetSize)); }; sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.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 float3(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); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); Sheet.ReleaseBuffer(); }
public Theater(TileSet tileset, Action <uint, string> onMissingImage = null) { 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(SheetType.Indexed, new Size(tileset.SheetSize, tileset.SheetSize))); }; random = new MersenneTwister(); var frameCache = new FrameCache(Game.ModData.DefaultFileSystem, Game.ModData.SpriteLoaders); foreach (var t in tileset.Templates) { var variants = new List <Sprite[]>(); foreach (var i in t.Value.Images) { ISpriteFrame[] allFrames; if (onMissingImage != null) { try { allFrames = frameCache[i]; } catch (FileNotFoundException) { onMissingImage(t.Key, i); continue; } } else { allFrames = frameCache[i]; } var frameCount = tileset.EnableDepth ? allFrames.Length / 2 : allFrames.Length; var indices = t.Value.Frames != null ? t.Value.Frames : Exts.MakeArray(t.Value.TilesCount, j => j); var start = indices.Min(); var end = indices.Max(); if (start < 0 || end >= frameCount) { throw new YamlException("Template `{0}` uses frames [{1}..{2}] of {3}, but only [0..{4}] actually exist" .F(t.Key, start, end, i, frameCount - 1)); } 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 float3(f.Offset, zOffset); var type = SheetBuilder.FrameTypeToSheetType(f.Type); // Defer SheetBuilder creation until we know what type of frames we are loading! // TODO: Support mixed indexed and BGRA frames if (sheetBuilder == null) { sheetBuilder = new SheetBuilder(SheetBuilder.FrameTypeToSheetType(f.Type), allocate); } else if (type != sheetBuilder.Type) { throw new YamlException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA."); } 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, s.Sheet, ss.Bounds, ss.Channel); } return(s); }).ToArray()); } var allSprites = variants.SelectMany(s => s); // Ignore the offsets baked into R8 sprites if (tileset.IgnoreTileSpriteOffsets) { allSprites = allSprites.Select(s => new Sprite(s.Sheet, s.Bounds, s.ZRamp, new float3(float2.Zero, s.Offset.Z), s.Channel, s.BlendMode)); } if (onMissingImage != null && !variants.Any()) { continue; } templates.Add(t.Value.Id, new TheaterTemplate(allSprites.ToArray(), variants.First().Count(), t.Value.Images.Length)); } // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[sheetBuilder.Type == SheetType.BGRA ? 4 : 1], new Size(1, 1)); Sheet.ReleaseBuffer(); }