Skip to content

Commit

Permalink
Refactor VoxelData into VoxelDataBytes and VoxelDataColors.
Browse files Browse the repository at this point in the history
Add support for .qb file animated gifs.
  • Loading branch information
Arlorean committed Jun 10, 2023
1 parent 2ff39ad commit af86170
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 10 deletions.
8 changes: 5 additions & 3 deletions Voxels.CommandLine/Animation.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using NGif.Components;
using SkiaSharp;
using System;
using System.IO;
using Voxels.SkiaSharp;

namespace Voxels.CommandLine {
internal static class Animation {
public static byte[] RenderGif(MagicaVoxel magicaVoxel, RenderSettings renderSettings, int frames, float duration, int cameraOrbits) {
public static byte[] RenderGif(RenderSettings renderSettings, int frames, float duration, int cameraOrbits, BoundsXYZ worldBounds, Func<int, VoxelData> flattenFrame) {
var delay = (int)(duration / frames * 1000);

var encoder = new AnimatedGifEncoder();
Expand All @@ -16,14 +17,15 @@ public static byte[] RenderGif(MagicaVoxel magicaVoxel, RenderSettings renderSet
encoder.SetRepeat(0);
encoder.SetTransparent(SKColors.Black);

var worldBounds = magicaVoxel.GetWorldAABB(0, frames - 1);
//var worldBounds = magicaVoxel.GetWorldAABB(0, frames - 1);

var startAngle = renderSettings.Yaw;
var stepAngle = (360*cameraOrbits) / frames;
for (var i=0; i < frames; i++) {
renderSettings.Yaw = startAngle + stepAngle * i;

var voxelData = magicaVoxel.Flatten(worldBounds, i);
//var voxelData = magicaVoxel.Flatten(worldBounds, i);
var voxelData = flattenFrame(i);
var bytes = Renderer.RenderPng(voxelData, renderSettings);
var image = SKImage.FromBitmap(SKBitmap.Decode(bytes));
encoder.AddFrame(image);
Expand Down
2 changes: 1 addition & 1 deletion Voxels.CommandLine/ImageToVoxel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static VoxelData Import(string path, Color[] palette) {
if (bitmap == null) return null;

var size = new XYZ(bitmap.Width, 1, bitmap.Height);
var voxelData = new VoxelData(size, palette);
var voxelData = new VoxelDataBytes(size, palette);

for (var x = 0; x < bitmap.Width; x++) {
for (var y = 0; y < bitmap.Height; y++) {
Expand Down
Binary file added Voxels.CommandLine/Nerds.qb
Binary file not shown.
Binary file added Voxels.CommandLine/Nerds.qbcl
Binary file not shown.
24 changes: 19 additions & 5 deletions Voxels.CommandLine/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,25 @@ void RenderFiles(string[] filenames, RenderSettings renderSettings) {
}
else {
if (GIF) {
// NOTE: MagicaVoxel only for now
using (var stream = File.OpenRead(filename)) {
var magicaVoxel = new MagicaVoxel();
if (magicaVoxel.Read(stream)) {
WriteOutput(filename, "gif", Animation.RenderGif(magicaVoxel, renderSettings, Frames, Duration, CameraOrbits));
// Support animation frames in MagicaVoxel
if (Path.GetExtension(filename).ToLower() == ".vox") {
var magicaVoxel = new MagicaVoxel();
if (magicaVoxel.Read(stream)) {
var worldBounds = magicaVoxel.GetWorldAABB(0, Frames - 1);
WriteOutput(filename, "gif",
Animation.RenderGif(renderSettings, Frames, Duration, CameraOrbits,
worldBounds, i => magicaVoxel.Flatten(worldBounds, i))
);
}
}
else {
var voxelData = VoxelImport.Import(filename);
var worldBounds = new BoundsXYZ(voxelData.Size);
WriteOutput(filename, "gif",
Animation.RenderGif(renderSettings, Frames, Duration, CameraOrbits,
worldBounds, _ => voxelData)
);
}
}
}
Expand Down Expand Up @@ -155,7 +169,7 @@ void ConvertFiles(string[] filenames, Color[] pallete) {
var voxelData = ImageToVoxel.Import(filename, pallete);
if (voxelData != null) {
using (var stream = File.Create(Path.ChangeExtension(filename, ".vox"))) {
var magicaVoxel = new MagicaVoxel(voxelData);
var magicaVoxel = new MagicaVoxel((VoxelDataBytes)voxelData);
magicaVoxel.Write(stream);
}
}
Expand Down
2 changes: 1 addition & 1 deletion Voxels.ShellExtensions/ThumbnailHandlerQb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Voxels.ShellExtensions {
public class ThumbnailHandlerQb : SharpThumbnailHandler {
protected override Bitmap GetThumbnailImage(uint width) {
var size = (int)width;
var voxelData = QbFile.Read(SelectedItemStream);
var voxelData = QbFile.ReadAndFlatten(SelectedItemStream);
if (voxelData == null) {
return null;
}
Expand Down
Binary file added Voxels.Test/Nerds.qb
Binary file not shown.
4 changes: 4 additions & 0 deletions Voxels.Test/TestMagicaVoxel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public void Test8x8x8() {
}
}

/// <summary>
/// The cars.vox is the MagicaVoxel example of using multiple voxel models
/// with rotations and translations to place them in a larger world.
/// </summary>
[Test]
public void TestCars() {
using (var stream = File.OpenRead("cars.vox")) {
Expand Down
38 changes: 38 additions & 0 deletions Voxels.Test/TestQubicle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using NUnit.Framework;
using System.IO;

namespace Voxels.Test {
[TestFixture]
public class TestQubicle {
[OneTimeSetUp]
public void SetUp() {
Directory.SetCurrentDirectory(TestContext.CurrentContext.TestDirectory);
}

/// <summary>
/// The Nerds.qb is the test file that comes with the Qubicle demo.
/// </summary>
[Test]
public void TestNerds() {
using (var stream = File.OpenRead("Nerds.qb")) {
var qubicle = new QbFile();
qubicle.Read(stream);

Assert.AreEqual(257, qubicle.Version);

var voxelData = qubicle.Flatten();

Assert.AreEqual(new XYZ(48,45,44), voxelData.Size);

Assert.AreEqual(15965, voxelData.Count);

// Left size speaker foot
Assert.AreEqual(new Color(89, 93, 96), voxelData.ColorOf(XYZ.Zero));

// Middle nerd's hair
Assert.AreEqual(new Color(83, 33, 21), voxelData.ColorOf(new XYZ(24, 40, 43)));
}
}
}
}
4 changes: 4 additions & 0 deletions Voxels.Test/Voxels.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<ItemGroup>
<Compile Include="TestAmbientOcclusion.cs" />
<Compile Include="TestColor.cs" />
<Compile Include="TestQubicle.cs" />
<Compile Include="TestMagicaVoxel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
Expand Down Expand Up @@ -80,6 +81,9 @@
<Content Include="cars.vox">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Nerds.qb">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSHARP.Targets" />
Expand Down

0 comments on commit af86170

Please sign in to comment.