DS2Revival/mods/modloader/gltf.h

72 lines
3.8 KiB
C++

// glTF 2.0 -> Dungeon Siege II formats, in process (DS2ModLoader) - a C++ port of the import path of
// tools/ds2mesh.py (fromgltf / toprs): .asp meshes (static props and skinned), .prs animations, DXT5 .dds textures.
// The port follows the Python step by step (same double arithmetic in the same order) so that both give the same
// bytes for the same input; tools/gltf_cpp_check.py builds mods/modloader/test/gltfconv.cpp and compares them.
// Formats: docs/formats/asp.md, prs.md, gltf-pipeline.md. In-game use: docs/architecture/gltf-loading.md.
//
// Nothing here talks to the game: gltf_mods.cpp decides what to convert and where the results go.
#pragma once
#include <cstdint>
#include <functional>
#include <string>
#include <vector>
namespace gltf {
using Bytes = std::vector<uint8_t>;
struct Options {
std::string meshName; // bone name of a static mesh (ds2mesh --name; default: file stem)
std::vector<std::string> textureNames; // one per material, in material order (ds2mesh --texture)
bool forceStatic = false; // ds2mesh --static
double scale = 1.0; // ds2mesh --scale
int maxTexture = 1024; // ds2mesh --max-texture
bool loop = false; // ds2mesh --loop (BEGL/ENDL notes in the .prs)
// If set: the texture names for the materials a mesh uses, given their glTF names in texture order (instead of
// textureNames / the defaults).
std::function<std::vector<std::string>(const std::vector<std::string>&)> textureNamer;
// ConvertAnimation: when no animation has exactly that name, take one whose name matches ignoring case, else the
// first (ds2mesh toprs fails instead).
bool animFallbackFirst = false;
};
struct Named {
std::string name;
Bytes data;
};
struct Result {
Bytes asp; // the mesh (empty for ConvertAnimation)
bool skinned = false;
std::vector<Named> textures; // texture name -> DDS (DXT5, full mip chain)
std::vector<Named> anims; // animation name (as in ds2mesh --anims "") -> .prs
std::vector<std::string> warnings;
std::vector<std::wstring> dependencies; // external files the glTF referenced (buffers, images)
};
// A glTF (.glb or .gltf) -> .asp + textures; with withAnims also every animation of a skinned model -> .prs.
// False on any error (message in error); never throws.
bool ConvertMesh(const std::wstring& path, const Options& opt, bool withAnims, Result& out, std::string& error);
// One animation of a skinned glTF -> .prs (ds2mesh toprs). name: animation name or index ("" = the first).
bool ConvertAnimation(const std::wstring& path, const std::string& name, const Options& opt, Result& out,
std::string& error);
// Texture names ds2mesh fromgltf gives a mesh without --texture: b<rest of the mesh name>[-NN].
std::vector<std::string> DefaultTextureNames(const std::string& meshName, size_t count);
// --- images (gltf_image.cpp) ---------------------------------------------------------------------------------------
struct Image {
int w = 0, h = 0;
std::vector<uint8_t> rgba; // w * h * 4
};
// PNG / JPEG / ... (stb_image) -> RGBA. False if the data is not a supported image.
bool DecodeImage(const uint8_t* data, size_t size, Image& out, std::string& error);
// Pillow's Image.resize(..., LANCZOS) for an RGBA image (premultiplied alpha, 22-bit fixed point), bit for bit.
Image ResizeLanczos(const Image& in, int w, int h);
// ds2mesh write_dds(..., 'dxt5'): sides rounded up to powers of two (at most maxSize), full mip chain, DXT5.
Bytes WriteDds(Image im, int maxSize);
// zlib stream -> bytes (for compressed tank entries), via stb_image's inflater. False on bad data.
bool Inflate(const uint8_t* data, size_t size, size_t expected, Bytes& out);
} // namespace gltf