Implement native TGA and DDS compatibility (#39)

This commit is contained in:
2026-08-09 02:51:39 +00:00
parent 2c806d80ff
commit 5d1573fc82
10 changed files with 1285 additions and 31 deletions

7
Cargo.lock generated
View File

@@ -8,6 +8,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bcdec_rs"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f09c37bc0e9f0924b7dae9988265ef3c76c88538f41a3b06caf4bed07cee5226"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.4" version = "0.10.4"
@@ -183,6 +189,7 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
name = "libremetaverse" name = "libremetaverse"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"bcdec_rs",
"libremetaverse-imaging", "libremetaverse-imaging",
"libremetaverse-structured-data", "libremetaverse-structured-data",
"libremetaverse-types", "libremetaverse-types",

View File

@@ -129,5 +129,17 @@ constructors and resizers cap decoded images at 4096 by 4096 worth of pixels,
codec adapters cap buffered encoded input at 64 MiB, and canonical codec adapters cap buffered encoded input at 64 MiB, and canonical
interleaving accepts explicit row strides without exposing codec-library types interleaving accepts explicit row strides without exposing codec-library types
through the core abstraction. through the core abstraction.
The native TGA/Pfim-compatible path decodes uncompressed and RLE true-color,
grayscale, and indexed TGA data with all descriptor orientations, plus bounded
legacy and DX10 DDS packed luminance/RGB(A) layouts and BC1 through BC7 blocks.
TGA output preserves the reference header, BGR(A) order, descriptor choice,
alpha-only expansion, and deterministic trailing padding. File and stream
inputs are capped before decoding, and all dimensions, packed rows, palettes,
packets, masks, and block indices use checked arithmetic with positioned parse
errors.
Legacy and DX10 BC1 through BC5 decoding is built in. The default `dds-bc67`
feature adds BC6H/BC7 decoding through the safe, pure-Rust `bcdec_rs` crate;
disabling default features removes that optional dependency and makes those
two formats return a typed unsupported-format error.
The controlled audit aggregates every expected failure by standardized C# The controlled audit aggregates every expected failure by standardized C#
member ID and rejects unrelated fixture, assertion, compile, or symbol errors. member ID and rejects unrelated fixture, assertion, compile, or symbol errors.

View File

@@ -4,7 +4,7 @@ Generated by `python3 tools/generate_api_shims.py`; do not edit by hand.
| Assembly | Types | Members | Status | | Assembly | Types | Members | Status |
|---|---:|---:|---| |---|---:|---:|---|
| `LibreMetaverse` | 2,711 | 27,281 | callable failure-only shim | | `LibreMetaverse` | 2,711 | 27,281 | native implementation: 1 type / 3 members; remaining surface is callable failure-only shims |
| `LibreMetaverse.Imaging.Abstractions` | 3 | 20 | native implementation: 3 types / 20 members; no generated shims remain | | `LibreMetaverse.Imaging.Abstractions` | 3 | 20 | native implementation: 3 types / 20 members; no generated shims remain |
| `LibreMetaverse.Imaging.Skia` | 1 | 3 | callable failure-only shim | | `LibreMetaverse.Imaging.Skia` | 1 | 3 | callable failure-only shim |
| `LibreMetaverse.LslTools` | 164 | 768 | callable failure-only shim | | `LibreMetaverse.LslTools` | 164 | 768 | callable failure-only shim |

View File

@@ -7,7 +7,12 @@ license.workspace = true
repository.workspace = true repository.workspace = true
description = "Rust rewrite shell for the LibreMetaverse client library" description = "Rust rewrite shell for the LibreMetaverse client library"
[features]
default = ["dds-bc67"]
dds-bc67 = ["dep:bcdec_rs"]
[dependencies] [dependencies]
bcdec_rs = { version = "0.2.0", optional = true }
libremetaverse-imaging = { path = "../libremetaverse-imaging" } libremetaverse-imaging = { path = "../libremetaverse-imaging" }
libremetaverse-structured-data = { path = "../libremetaverse-structured-data" } libremetaverse-structured-data = { path = "../libremetaverse-structured-data" }
libremetaverse-types = { path = "../libremetaverse-types" } libremetaverse-types = { path = "../libremetaverse-types" }

View File

@@ -34081,33 +34081,10 @@ pub mod imaging {
} }
/// C# type: `T:LibreMetaverse.Imaging.Targa`. /// C# type: `T:LibreMetaverse.Imaging.Targa`.
pub struct Targa; /// C# member: `M:LibreMetaverse.Imaging.Targa.DecodeToManagedImage(System.IO.Stream)`.
impl Targa { /// C# member: `M:LibreMetaverse.Imaging.Targa.DecodeToManagedImage(System.String)`.
/// C# member: `M:LibreMetaverse.Imaging.Targa.DecodeToManagedImage(System.IO.Stream)`. /// C# member: `M:LibreMetaverse.Imaging.Targa.Encode(LibreMetaverse.Imaging.ManagedImage)`.
pub fn decode_to_managed_image_with_stream( pub use crate::targa::Targa;
stream: Box<dyn libremetaverse_types::compat::ReadWrite + Send>,
) -> Result<libremetaverse_imaging::ManagedImage, crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Imaging.Targa.DecodeToManagedImage(System.IO.Stream)",
)
}
/// C# member: `M:LibreMetaverse.Imaging.Targa.DecodeToManagedImage(System.String)`.
pub fn decode_to_managed_image_with_string(
file_name: String,
) -> Result<libremetaverse_imaging::ManagedImage, crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Imaging.Targa.DecodeToManagedImage(System.String)",
)
}
/// C# member: `M:LibreMetaverse.Imaging.Targa.Encode(LibreMetaverse.Imaging.ManagedImage)`.
pub fn encode(
image: libremetaverse_imaging::ManagedImage,
) -> Result<Vec<u8>, crate::Error> {
libremetaverse_types::not_implemented(
"M:LibreMetaverse.Imaging.Targa.Encode(LibreMetaverse.Imaging.ManagedImage)",
)
}
}
} }
pub mod import_export { pub mod import_export {

View File

@@ -3,6 +3,7 @@
extern crate self as libremetaverse; extern crate self as libremetaverse;
mod generated; mod generated;
mod targa;
#[cfg(test)] #[cfg(test)]
mod appearance_baker_semantics; mod appearance_baker_semantics;

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bcdec_rs"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f09c37bc0e9f0924b7dae9988265ef3c76c88538f41a3b06caf4bed07cee5226"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
version = "0.10.4" version = "0.10.4"
@@ -183,6 +189,7 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
name = "libremetaverse" name = "libremetaverse"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"bcdec_rs",
"libremetaverse-imaging", "libremetaverse-imaging",
"libremetaverse-structured-data", "libremetaverse-structured-data",
"libremetaverse-types", "libremetaverse-types",

View File

@@ -101,5 +101,5 @@
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUUID::test", "LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUUID::test",
"LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUndef::test" "LibreMetaverse.Tests/XmlLLSDTests.cs::XmlSDTests.DeserializeUndef::test"
], ],
"support_passes": 104 "support_passes": 109
} }

View File

@@ -38,6 +38,7 @@ TARGETS = {
# implementations. The generated module keeps catalog markers and re-exports # implementations. The generated module keeps catalog markers and re-exports
# the hand-written type so coverage remains deterministic. # the hand-written type so coverage remains deterministic.
NATIVE_TYPES = { NATIVE_TYPES = {
"T:LibreMetaverse.Imaging.Targa": "crate::targa::Targa",
"T:LibreMetaverse.Imaging.ITextureCodec": "crate::managed_image::ITextureCodec", "T:LibreMetaverse.Imaging.ITextureCodec": "crate::managed_image::ITextureCodec",
"T:LibreMetaverse.Imaging.ManagedImage": "crate::managed_image::ManagedImage", "T:LibreMetaverse.Imaging.ManagedImage": "crate::managed_image::ManagedImage",
"T:LibreMetaverse.Imaging.ManagedImage.ImageChannels": "crate::managed_image::ManagedImageImageChannels", "T:LibreMetaverse.Imaging.ManagedImage.ImageChannels": "crate::managed_image::ManagedImageImageChannels",
@@ -1019,14 +1020,15 @@ def coverage_report(catalog: dict, coverage: dict[str, tuple[int, int, bool]]) -
if item["doc_id"] in native_type_ids or member["doc_id"] in NATIVE_MEMBER_BODIES if item["doc_id"] in native_type_ids or member["doc_id"] in NATIVE_MEMBER_BODIES
} }
if native_type_ids or native_member_ids: if native_type_ids or native_member_ids:
type_noun = "type" if len(native_type_ids) == 1 else "types"
if len(native_member_ids) == members: if len(native_member_ids) == members:
status = ( status = (
f"native implementation: {len(native_type_ids):,} types / " f"native implementation: {len(native_type_ids):,} {type_noun} / "
f"{len(native_member_ids):,} members; no generated shims remain" f"{len(native_member_ids):,} members; no generated shims remain"
) )
else: else:
status = ( status = (
f"native implementation: {len(native_type_ids):,} types / " f"native implementation: {len(native_type_ids):,} {type_noun} / "
f"{len(native_member_ids):,} members; remaining surface is callable failure-only shims" f"{len(native_member_ids):,} members; remaining surface is callable failure-only shims"
) )
else: else: