Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion VisualPinball.Engine/VPT/Ramp/Ramp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class Ramp : Item<RampData>, IRenderable

public Ramp(RampData data) : base(data)
{
MeshGenerator = new RampMeshGenerator(Data);
MeshGenerator = new RampMeshGenerator(Data, Vertex3D.Zero);
}

public Ramp(BinaryReader reader, string itemName) : this(new RampData(reader, itemName))
Expand Down
20 changes: 11 additions & 9 deletions VisualPinball.Engine/VPT/Ramp/RampMeshGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ public class RampMeshGenerator
public const string Wires = "Wires";

private readonly IRampData _data;
private readonly Vertex3D _position;

public RampMeshGenerator(IRampData data)
public RampMeshGenerator(IRampData data, Vertex3D position)
{
_data = data;
_position = position;
}

public Mesh GetMesh(float tableWidth, float tableHeight, float heightZ, string id)
Expand Down Expand Up @@ -193,10 +195,10 @@ private Mesh GenerateFlatFloorMesh(float tableWidth, float tableHeight, RampVert

//if (_data.Image != null) {
if (_data.ImageAlignment == RampImageAlignment.ImageModeWorld) {
rgv3d1.Tu = rgv3d1.X * invTableWidth;
rgv3d1.Tv = rgv3d1.Y * invTableHeight;
rgv3d2.Tu = rgv3d2.X * invTableWidth;
rgv3d2.Tv = rgv3d2.Y * invTableHeight;
rgv3d1.Tu = (_position.X + rgv3d1.X) * invTableWidth;
rgv3d1.Tv = (_position.Y + rgv3d1.Y) * invTableHeight;
rgv3d2.Tu = (_position.X + rgv3d2.X) * invTableWidth;
rgv3d2.Tv = (_position.Y + rgv3d2.Y) * invTableHeight;

} else {
rgv3d1.Tu = 1.0f;
Expand Down Expand Up @@ -255,8 +257,8 @@ private Mesh GenerateFlatLeftWall(float tableWidth, float tableHeight, RampVerte
rgv3d2.Z = (rv.PointHeights[i] + _data.LeftWallHeightVisible);

if (_data.ImageAlignment == RampImageAlignment.ImageModeWorld) {
rgv3d1.Tu = rgv3d1.X * invTableWidth;
rgv3d1.Tv = rgv3d1.Y * invTableHeight;
rgv3d1.Tu = (_position.X + rgv3d1.X) * invTableWidth;
rgv3d1.Tv = (_position.Y + rgv3d1.Y) * invTableHeight;

} else {
rgv3d1.Tu = 0;
Expand Down Expand Up @@ -309,8 +311,8 @@ private Mesh GenerateFlatRightWall(float tableWidth, float tableHeight, RampVert
rgv3d2.Z = (rv.PointHeights[i] + _data.RightWallHeightVisible);

if (_data.ImageAlignment == RampImageAlignment.ImageModeWorld) {
rgv3d1.Tu = rgv3d1.X * invTableWidth;
rgv3d1.Tv = rgv3d1.Y * invTableHeight;
rgv3d1.Tu = (_position.X + rgv3d1.X) * invTableWidth;
rgv3d1.Tv = (_position.Y + rgv3d1.Y) * invTableHeight;

} else {
rgv3d1.Tu = 0;
Expand Down
2 changes: 1 addition & 1 deletion VisualPinball.Engine/VPT/Surface/Surface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class Surface : Item<SurfaceData>, IRenderable

public Surface(SurfaceData data) : base(data)
{
_meshGenerator = new SurfaceMeshGenerator(Data);
_meshGenerator = new SurfaceMeshGenerator(Data, Vertex3D.Zero);
}

public Surface(BinaryReader reader, string itemName) : this(new SurfaceData(reader, itemName))
Expand Down
17 changes: 9 additions & 8 deletions VisualPinball.Engine/VPT/Surface/SurfaceMeshGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

using System;
using System.Collections.Generic;
using VisualPinball.Engine.Game;
using VisualPinball.Engine.Math;
using MathF = VisualPinball.Engine.Math.MathF;

Expand All @@ -28,10 +27,12 @@ public class SurfaceMeshGenerator
public const string Top = "Top";

private readonly ISurfaceData _data;
private readonly Vertex3D _position;

public SurfaceMeshGenerator(ISurfaceData data)
public SurfaceMeshGenerator(ISurfaceData data, Vertex3D position)
{
_data = data;
_position = position;
}

public Mesh GetMesh(string id, float tableWidth, float tableHeight, float zHeight, bool asRightHanded)
Expand Down Expand Up @@ -123,8 +124,8 @@ private Mesh GenerateTopMesh(float tableWidth, float tableHeight, float zHeight)
X = pv0.X,
Y = pv0.Y,
Z = heightNotDropped + zHeight,
Tu = pv0.X * invTableWidth,
Tv = pv0.Y * invTableHeight,
Tu = (_position.X + pv0.X) * invTableWidth,
Tv = (_position.Y + pv0.Y) * invTableHeight,
Nx = 0,
Ny = 0,
Nz = 1.0f
Expand All @@ -134,8 +135,8 @@ private Mesh GenerateTopMesh(float tableWidth, float tableHeight, float zHeight)
X = pv0.X,
Y = pv0.Y,
Z = (float) heightDropped,
Tu = pv0.X * invTableWidth,
Tv = pv0.Y * invTableHeight,
Tu = (_position.X + pv0.X) * invTableWidth,
Tv = (_position.Y + pv0.Y) * invTableHeight,
Nx = 0,
Ny = 0,
Nz = 1.0f
Expand All @@ -145,8 +146,8 @@ private Mesh GenerateTopMesh(float tableWidth, float tableHeight, float zHeight)
X = pv0.X,
Y = pv0.Y,
Z = _data.HeightBottom,
Tu = pv0.X * invTableWidth,
Tv = pv0.Y * invTableHeight,
Tu = (_position.X + pv0.X) * invTableWidth,
Tv = (_position.Y + pv0.Y) * invTableHeight,
Nx = 0,
Ny = 0,
Nz = -1.0f
Expand Down
17 changes: 11 additions & 6 deletions VisualPinball.Engine/VPT/Table/TableLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ public static FileTableContainer Load(string filename, bool loadGameItems = true
using (var reader = new BinaryReader(stream)) {
var tableContainer = new FileTableContainer(reader);

LoadTableInfo(tableContainer, cf.RootStorage, gameStorage);
var tableInfoStorage = LoadTableInfo(tableContainer, cf.RootStorage, gameStorage);
if (loadGameItems) {
LoadGameItems(tableContainer, gameStorage, tableContainer.NumGameItems, "GameItem");
LoadGameItems(tableContainer, gameStorage, tableContainer.NumVpeGameItems, "VpeGameItem");
}
LoadTextures(tableContainer, gameStorage);
LoadTextures(tableContainer, gameStorage, tableInfoStorage);
LoadSounds(tableContainer, gameStorage, fileVersion);
LoadCollections(tableContainer, gameStorage);
LoadTableMeta(tableContainer, gameStorage);
Expand Down Expand Up @@ -256,7 +256,7 @@ private static void LoadGameItems(FileTableContainer tableContainer, CFStorage s
}
}

private static void LoadTextures(FileTableContainer tableContainer, CFStorage storage)
private static void LoadTextures(FileTableContainer tableContainer, CFStorage storage, CFStorage tableInfoStorage)
{
for (var i = 0; i < tableContainer.NumTextures; i++) {
var textureName = $"Image{i}";
Expand All @@ -273,7 +273,7 @@ private static void LoadTextures(FileTableContainer tableContainer, CFStorage st

using (var stream = new MemoryStream(textureData))
using (var reader = new BinaryReader(stream)) {
var texture = new Texture(reader, textureName);
var texture = new Texture(reader, textureName, tableInfoStorage);
tableContainer.AddTexture(texture);
}
}
Expand Down Expand Up @@ -313,7 +313,7 @@ private static void LoadSounds(FileTableContainer tableContainer, CFStorage stor
}
}

private static void LoadTableInfo(FileTableContainer tableContainer, CFStorage rootStorage, CFStorage gameStorage)
private static CFStorage LoadTableInfo(FileTableContainer tableContainer, CFStorage rootStorage, CFStorage gameStorage)
{
// first, although we can loop through entries, get them from the game storage, so we
// know their order, which is important when writing back (because you know, hashing).
Expand All @@ -329,16 +329,21 @@ private static void LoadTableInfo(FileTableContainer tableContainer, CFStorage r
rootStorage.TryGetStorage("TableInfo", out var tableInfoStorage);
if (tableInfoStorage == null) {
Logger.Info("TableInfo storage not found, skipping.");
return;
return null;
}
tableInfoStorage.VisitEntries(item => {
if (item.Name == "Screenshot") { // skip those
return;
}
if (item.IsStream) {
var itemStream = item as CFStream;
if (itemStream != null) {
tableContainer.TableInfo[item.Name] = BiffUtil.ParseWideString(itemStream.GetData());
}
}
}, false);

return tableInfoStorage;
}

private static void LoadTableMeta(FileTableContainer tableContainer, CFStorage gameStorage)
Expand Down
34 changes: 27 additions & 7 deletions VisualPinball.Engine/VPT/Texture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using System.Text;
using NetVips;
using NLog;
using OpenMcdf;
using VisualPinball.Engine.Resources;

namespace VisualPinball.Engine.VPT
Expand Down Expand Up @@ -65,15 +66,20 @@ public string FileExtension {
/// contain the header.
/// </summary>
/// <see cref="FileContent"/>
public byte[] Content => ImageData.Bytes;
public byte[] Content => ImageData?.Bytes ?? _screenshot;

/// <summary>
/// Data as it would written to an image file (incl headers).
/// </summary>
public byte[] FileContent => ImageData.FileContent;
public byte[] FileContent => ImageData?.FileContent ?? _screenshot;

private IImageData ImageData => Data.Binary as IImageData ?? Data.Bitmap;

/// <summary>
/// VPX can store texture data as screenshot in the TableInfo storage, this is it if it's the case.
/// </summary>
private byte[] _screenshot;

public bool HasTransparentFormat => Data.HasBitmap || Data.Path != null && Data.Path.ToLower().EndsWith(".png");

public bool UsageNormalMap;
Expand All @@ -85,11 +91,25 @@ public Texture(string name) : base(new TextureData(name))
Name = name;
}

public Texture(TextureData data) : base(data) { }
public Texture(TextureData data, CFStorage tableInfoStorage) : base(data)
{
if (data.Binary == null && data.Bitmap == null) {
if (data.LinkId == 1) {
if (tableInfoStorage == null) {
Logger.Warn($"Texture {Name} has no binary data and no storage to load from.");
return;
}
// load screenshot
_screenshot = tableInfoStorage.GetStream("Screenshot")?.GetData();
} else {
Logger.Warn($"Could not load texture {Name} from storage. No binaries and link is {data.LinkId}.");
}
}
}

public Texture(BinaryReader reader, string itemName) : this(new TextureData(reader, itemName)) { }
public Texture(BinaryReader reader, string itemName, CFStorage tableInfoStorage) : this(new TextureData(reader, itemName), tableInfoStorage) { }

private Texture(Resource res) : this(new TextureData(res)) { }
private Texture(Resource res) : this(new TextureData(res), null) { }

public void Analyze()
{
Expand Down Expand Up @@ -154,11 +174,11 @@ private TextureStats AnalyzeAlpha()
public Image GetImage()
{
try {
var data = Data.Binary != null ? Data.Binary.Data : Data.Bitmap.Bytes;
var data = Data.Binary != null ? Data.Binary.Data : Data.Bitmap != null ? Data.Bitmap.Bytes : _screenshot;
if (data.Length == 0) {
throw new InvalidDataException("Image data is empty.");
}
return Data.Binary != null
return Data.Binary != null || _screenshot != null
? Image.NewFromBuffer(data)
: Image.NewFromMemory(data, Width, Height, 4, Enums.BandFormat.Uchar);

Expand Down
4 changes: 4 additions & 0 deletions VisualPinball.Engine/VPT/TextureData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// ReSharper disable UnassignedField.Global
// ReSharper disable StringLiteralTypo
// ReSharper disable FieldCanBeMadeReadOnly.Global
// ReSharper disable InconsistentNaming
#endregion

using System;
Expand Down Expand Up @@ -61,6 +62,9 @@ public class TextureData : ItemData
[BiffBits("BITS", Pos = 6)]
public Bitmap Bitmap; // originally "PdsBuffer";

[BiffInt("LINK", Pos = 6)] // vpx doesn't seem to support anything else than 1, which is "screenshot", found at TableInfo/Screenshot
public int LinkId;

public TextureData(string name) : base(StoragePrefix.Image)
{
Name = name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,40 @@

namespace VisualPinball.Unity.Editor
{
public static class VpxMenuImporter
public static class MenuImporter
{
[MenuItem("Pinball/Import .vpx File", false, 2)]
public static void ImportVpxIntoScene(MenuCommand menuCommand)
[MenuItem("Pinball/Import Table", false, 1)]
public static async void ImportVpeIntoScene(MenuCommand menuCommand)
{
// if it's an untitled scene, save first.
if (!EnsureUntitledSceneHasBeenSaved("Before importing, you need to make your current scene an asset by saving it.")) {
if (!EnsureUntitledSceneHasBeenSaved()) {
return;
}

// open file dialog
var vpxPath = EditorUtility.OpenFilePanelWithFilters("Import .vpx File", null, new[] { "Visual Pinball Table Files", "vpx" });
if (vpxPath.Length == 0) {
var path = EditorUtility.OpenFilePanelWithFilters("Import", null, new[] { "Pinball Tables", "vpe,vpx" });
if (path.Length == 0) {
return;
}

VpxImportEngine.ImportIntoScene(vpxPath, tableName: Path.GetFileNameWithoutExtension(vpxPath));
switch (Path.GetExtension(path).ToLower()) {

case ".vpx": {
VpxImportEngine.ImportIntoScene(path, tableName: Path.GetFileNameWithoutExtension(path));
break;
}
case ".vpe": {
var importer = new PackageReader(path);
await importer.ImportIntoScene(Path.GetFileNameWithoutExtension(path));
break;
}
default:
EditorUtility.DisplayDialog("Import", "Unsupported file format. Only .vpe and .vpx files are currently supported.", "OK");
break;
}
}

private static bool EnsureUntitledSceneHasBeenSaved(string message)
private static bool EnsureUntitledSceneHasBeenSaved()
{
if (string.IsNullOrEmpty(SceneManager.GetActiveScene().path)) {

Expand Down

This file was deleted.

Loading
Loading