mirror of
https://github.com/Theaninova/mhlib.git
synced 2025-12-12 12:36:17 +00:00
mhk3
This commit is contained in:
48
rust/Cargo.lock
generated
48
rust/Cargo.lock
generated
@@ -20,6 +20,17 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"num-traits 0.1.43",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "binrw"
|
name = "binrw"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -144,6 +155,18 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dds-rs"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c293f2e4ae9760641b1b5faf1c05c63d2ff1755763f87853217c8774afa55a1"
|
||||||
|
dependencies = [
|
||||||
|
"bincode",
|
||||||
|
"rgb",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
@@ -355,7 +378,7 @@ dependencies = [
|
|||||||
"gif",
|
"gif",
|
||||||
"jpeg-decoder",
|
"jpeg-decoder",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
"num-traits",
|
"num-traits 0.2.15",
|
||||||
"png",
|
"png",
|
||||||
"qoi",
|
"qoi",
|
||||||
"tiff",
|
"tiff",
|
||||||
@@ -450,6 +473,7 @@ dependencies = [
|
|||||||
name = "mhgd"
|
name = "mhgd"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"dds-rs",
|
||||||
"godot",
|
"godot",
|
||||||
"itertools",
|
"itertools",
|
||||||
"lightwave-3d",
|
"lightwave-3d",
|
||||||
@@ -507,7 +531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"num-traits",
|
"num-traits 0.2.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -518,7 +542,16 @@ checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits 0.2.15",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.2.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -644,6 +677,15 @@ dependencies = [
|
|||||||
name = "renderwarelib"
|
name = "renderwarelib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rgb"
|
||||||
|
version = "0.8.36"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "mhjnr"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "mhjnr-viewer"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
name = "mhjnr"
|
|
||||||
crate-type = ["cdylib", "lib"]
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
itertools = "0.10.5"
|
|
||||||
unicode-segmentation = "1.10.1"
|
|
||||||
encoding_rs = "0.8.32"
|
|
||||||
binrw = "0.11.1"
|
|
||||||
serde = {version = "1.0.160", features = ["derive"]}
|
|
||||||
serde-xml-rs = "0.6.0"
|
|
||||||
image = "0.24.6"
|
|
||||||
base64 = "0.21.0"
|
|
||||||
godot = { git = "https://github.com/godot-rust/gdext", branch = "master" }
|
|
||||||
@@ -11,5 +11,6 @@ crate-type = ["cdylib"]
|
|||||||
godot = { git = "https://github.com/godot-rust/gdext", branch = "master" }
|
godot = { git = "https://github.com/godot-rust/gdext", branch = "master" }
|
||||||
lightwave-3d = "1.0.0"
|
lightwave-3d = "1.0.0"
|
||||||
itertools = "0.10.5"
|
itertools = "0.10.5"
|
||||||
|
dds-rs = "0.7.0"
|
||||||
starforcelib = { path = "../starforcelib" }
|
starforcelib = { path = "../starforcelib" }
|
||||||
springylib = { path = "../springylib" }
|
springylib = { path = "../springylib" }
|
||||||
|
|||||||
0
rust/mhgd/src/data_installer.rs
Normal file
0
rust/mhgd/src/data_installer.rs
Normal file
@@ -1,24 +1,34 @@
|
|||||||
use crate::sproing::datafile::DatafileLoader;
|
use crate::sproing::datafile::DatafileLoader;
|
||||||
|
use crate::starforce::sar_archive::SarLoader;
|
||||||
use ::godot::engine::class_macros::auto_register_classes;
|
use ::godot::engine::class_macros::auto_register_classes;
|
||||||
use ::godot::engine::{ResourceFormatLoaderVirtual, ResourceLoader};
|
use ::godot::engine::{ResourceFormatLoaderVirtual, ResourceLoader};
|
||||||
use ::godot::init::{gdextension, ExtensionLayer};
|
use ::godot::init::{gdextension, ExtensionLayer};
|
||||||
use ::godot::prelude::{ExtensionLibrary, Gd, InitHandle, InitLevel, Share};
|
use ::godot::prelude::{ExtensionLibrary, Gd, InitHandle, InitLevel, Share};
|
||||||
|
|
||||||
pub mod sproing;
|
pub mod data_installer;
|
||||||
pub mod lightwave_object;
|
pub mod lightwave_object;
|
||||||
|
pub mod sproing;
|
||||||
|
pub mod starforce;
|
||||||
|
|
||||||
struct Main {}
|
struct Main {}
|
||||||
|
|
||||||
#[gdextension]
|
#[gdextension]
|
||||||
unsafe impl ExtensionLibrary for Main {
|
unsafe impl ExtensionLibrary for Main {
|
||||||
fn load_library(handle: &mut InitHandle) -> bool {
|
fn load_library(handle: &mut InitHandle) -> bool {
|
||||||
handle.register_layer(InitLevel::Editor, ResourceLoaderLayer { datafile: None });
|
handle.register_layer(
|
||||||
|
InitLevel::Editor,
|
||||||
|
ResourceLoaderLayer {
|
||||||
|
datafile: None,
|
||||||
|
sarc: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ResourceLoaderLayer {
|
struct ResourceLoaderLayer {
|
||||||
pub datafile: Option<Gd<DatafileLoader>>,
|
pub datafile: Option<Gd<DatafileLoader>>,
|
||||||
|
pub sarc: Option<Gd<SarLoader>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtensionLayer for ResourceLoaderLayer {
|
impl ExtensionLayer for ResourceLoaderLayer {
|
||||||
@@ -26,9 +36,12 @@ impl ExtensionLayer for ResourceLoaderLayer {
|
|||||||
auto_register_classes();
|
auto_register_classes();
|
||||||
|
|
||||||
self.datafile = Some(Gd::<DatafileLoader>::with_base(DatafileLoader::init));
|
self.datafile = Some(Gd::<DatafileLoader>::with_base(DatafileLoader::init));
|
||||||
|
self.sarc = Some(Gd::<SarLoader>::with_base(SarLoader::init));
|
||||||
|
|
||||||
ResourceLoader::singleton()
|
ResourceLoader::singleton()
|
||||||
.add_resource_format_loader(self.datafile.as_ref().unwrap().share().upcast(), true);
|
.add_resource_format_loader(self.datafile.as_ref().unwrap().share().upcast(), true);
|
||||||
|
ResourceLoader::singleton()
|
||||||
|
.add_resource_format_loader(self.sarc.as_ref().unwrap().share().upcast(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinitialize(&mut self) {
|
fn deinitialize(&mut self) {
|
||||||
@@ -36,5 +49,9 @@ impl ExtensionLayer for ResourceLoaderLayer {
|
|||||||
ResourceLoader::singleton().remove_resource_format_loader(datafile.share().upcast());
|
ResourceLoader::singleton().remove_resource_format_loader(datafile.share().upcast());
|
||||||
self.datafile = None;
|
self.datafile = None;
|
||||||
}
|
}
|
||||||
|
if let Some(sarc) = &self.sarc {
|
||||||
|
ResourceLoader::singleton().remove_resource_format_loader(sarc.share().upcast());
|
||||||
|
self.sarc = None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,22 @@ use godot::builtin::{
|
|||||||
Dictionary, GodotString, PackedInt32Array, PackedVector2Array, PackedVector3Array,
|
Dictionary, GodotString, PackedInt32Array, PackedVector2Array, PackedVector3Array,
|
||||||
VariantArray, Vector2, Vector3,
|
VariantArray, Vector2, Vector3,
|
||||||
};
|
};
|
||||||
|
use godot::engine::base_material_3d::TextureParam;
|
||||||
use godot::engine::mesh::{ArrayFormat, ArrayType, PrimitiveType};
|
use godot::engine::mesh::{ArrayFormat, ArrayType, PrimitiveType};
|
||||||
use godot::engine::{ArrayMesh, SurfaceTool};
|
use godot::engine::{load, ArrayMesh, Image, ImageTexture, StandardMaterial3D, SurfaceTool};
|
||||||
|
use godot::log::godot_print;
|
||||||
use godot::obj::{EngineEnum, Gd};
|
use godot::obj::{EngineEnum, Gd};
|
||||||
use godot::prelude::{godot_warn, Array, GodotClass, Share, ToVariant};
|
use godot::prelude::{godot_warn, Array, GodotClass, Share, ToVariant};
|
||||||
use lightwave_3d::iff::Chunk;
|
use lightwave_3d::iff::Chunk;
|
||||||
|
use lightwave_3d::lwo2::sub_tags::blocks::image_texture::SurfaceBlockImageTextureSubChunk;
|
||||||
|
use lightwave_3d::lwo2::sub_tags::blocks::{
|
||||||
|
SurfaceBlockHeaderSubChunk, SurfaceBlocks, TextureChannel,
|
||||||
|
};
|
||||||
|
use lightwave_3d::lwo2::sub_tags::surface_parameters::SurfaceParameterSubChunk;
|
||||||
|
use lightwave_3d::lwo2::tags::image_clip::{ImageClip, ImageClipSubChunk};
|
||||||
use lightwave_3d::lwo2::tags::point_list::PointList;
|
use lightwave_3d::lwo2::tags::point_list::PointList;
|
||||||
use lightwave_3d::lwo2::tags::polygon_list::PolygonLists;
|
use lightwave_3d::lwo2::tags::polygon_list::PolygonLists;
|
||||||
|
use lightwave_3d::lwo2::tags::surface_definition::SurfaceDefinition;
|
||||||
use lightwave_3d::lwo2::tags::Tag;
|
use lightwave_3d::lwo2::tags::Tag;
|
||||||
use lightwave_3d::LightWaveObject;
|
use lightwave_3d::LightWaveObject;
|
||||||
|
|
||||||
@@ -27,7 +36,10 @@ impl Lwo {
|
|||||||
|
|
||||||
pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<ArrayMesh> {
|
pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<ArrayMesh> {
|
||||||
let mut mesh = ArrayMesh::new();
|
let mut mesh = ArrayMesh::new();
|
||||||
|
|
||||||
let mut arrays: Option<VariantArray> = None;
|
let mut arrays: Option<VariantArray> = None;
|
||||||
|
let mut materials = vec![];
|
||||||
|
let mut images: Option<ImageClip> = None;
|
||||||
|
|
||||||
let mut vert_count = 0;
|
let mut vert_count = 0;
|
||||||
|
|
||||||
@@ -46,26 +58,44 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<ArrayMesh> {
|
|||||||
);
|
);
|
||||||
arrays = Some(ars);
|
arrays = Some(ars);
|
||||||
}
|
}
|
||||||
|
Tag::DiscontinuousVertexMapping(vmad) => match &vmad.kind {
|
||||||
|
b"TXUV" => {
|
||||||
|
collect_uvs(
|
||||||
|
vmad.data.mappings.into_iter().map(|it| {
|
||||||
|
(
|
||||||
|
it.vert as usize,
|
||||||
|
Vector2 {
|
||||||
|
x: it.values[0],
|
||||||
|
y: it.values[1],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
vert_count,
|
||||||
|
arrays.as_mut().unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
x => godot_warn!(
|
||||||
|
"Discontinuous Vertex Mapping: {}",
|
||||||
|
String::from_utf8(x.to_vec()).unwrap()
|
||||||
|
),
|
||||||
|
},
|
||||||
Tag::VertexMapping(vmap) => match &vmap.kind {
|
Tag::VertexMapping(vmap) => match &vmap.kind {
|
||||||
b"TXUV" => {
|
b"TXUV" => {
|
||||||
if let Some(arrays) = &mut arrays {
|
/*collect_uvs(
|
||||||
let mut arr = PackedVector2Array::new();
|
vmap.data.mapping.into_iter().map(|it| {
|
||||||
arr.resize(vert_count);
|
(
|
||||||
|
it.vert as usize,
|
||||||
for uv in vmap.data.mapping {
|
|
||||||
arr.set(
|
|
||||||
uv.vert as usize,
|
|
||||||
Vector2 {
|
Vector2 {
|
||||||
x: uv.value[0],
|
x: it.value[0],
|
||||||
y: uv.value[1],
|
y: it.value[1],
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
}
|
}),
|
||||||
|
vert_count,
|
||||||
arrays.set(ArrayType::ARRAY_TEX_UV.ord() as usize, arr.to_variant());
|
arrays.as_mut().unwrap(),
|
||||||
}
|
);*/
|
||||||
}
|
}
|
||||||
x => godot_warn!("{}", String::from_utf8(x.to_vec()).unwrap()),
|
x => godot_warn!("Vertex Mapping: {}", String::from_utf8(x.to_vec()).unwrap()),
|
||||||
},
|
},
|
||||||
Tag::PolygonList(polygons) => match &polygons.kind {
|
Tag::PolygonList(polygons) => match &polygons.kind {
|
||||||
b"FACE" => {
|
b"FACE" => {
|
||||||
@@ -76,18 +106,32 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<ArrayMesh> {
|
|||||||
}
|
}
|
||||||
x => godot_warn!("{}", String::from_utf8(x.to_vec()).unwrap()),
|
x => godot_warn!("{}", String::from_utf8(x.to_vec()).unwrap()),
|
||||||
},
|
},
|
||||||
_ => (),
|
Tag::ImageClip(clip) => {
|
||||||
|
images = Some(clip.data);
|
||||||
|
}
|
||||||
|
Tag::SurfaceDefinition(surf) => {
|
||||||
|
let mat = collect_material(surf.data, images.unwrap());
|
||||||
|
images = None;
|
||||||
|
materials.push(mat);
|
||||||
|
}
|
||||||
|
x => {
|
||||||
|
godot_warn!("Invalid chunk {:?}", x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try_commit(&mut mesh, &arrays);
|
try_commit(&mut mesh, &arrays);
|
||||||
let mut out_mesh = ArrayMesh::new();
|
let mut out_mesh = ArrayMesh::new();
|
||||||
|
let mut mats = materials.into_iter();
|
||||||
for i in 0..mesh.get_surface_count() {
|
for i in 0..mesh.get_surface_count() {
|
||||||
let mut tool = SurfaceTool::new();
|
let mut tool = SurfaceTool::new();
|
||||||
tool.create_from(mesh.share().upcast(), i);
|
tool.create_from(mesh.share().upcast(), i);
|
||||||
tool.generate_normals(false);
|
tool.generate_normals(false);
|
||||||
tool.generate_tangents();
|
tool.generate_tangents();
|
||||||
try_commit(&mut out_mesh, &Some(tool.commit_to_arrays()));
|
try_commit(&mut out_mesh, &Some(tool.commit_to_arrays()));
|
||||||
|
if let Some(mat) = mats.next() {
|
||||||
|
out_mesh.surface_set_material(i, mat.upcast())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
out_mesh
|
out_mesh
|
||||||
}
|
}
|
||||||
@@ -104,6 +148,27 @@ fn try_commit(mesh: &mut ArrayMesh, arrays: &Option<VariantArray>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn collect_uvs<I: Iterator<Item = (usize, Vector2)>>(
|
||||||
|
mapping: I,
|
||||||
|
vert_count: usize,
|
||||||
|
arrays: &mut VariantArray,
|
||||||
|
) {
|
||||||
|
let mut arr = arrays
|
||||||
|
.get(ArrayType::ARRAY_TEX_UV.ord() as usize)
|
||||||
|
.try_to::<PackedVector2Array>()
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
let mut new_uvs = PackedVector2Array::new();
|
||||||
|
new_uvs.resize(vert_count);
|
||||||
|
new_uvs
|
||||||
|
});
|
||||||
|
|
||||||
|
for (index, uv) in mapping {
|
||||||
|
arr.set(index, uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
arrays.set(ArrayType::ARRAY_TEX_UV.ord() as usize, arr.to_variant());
|
||||||
|
}
|
||||||
|
|
||||||
fn collect_points(chunk: Chunk<PointList>) -> PackedVector3Array {
|
fn collect_points(chunk: Chunk<PointList>) -> PackedVector3Array {
|
||||||
PackedVector3Array::from(
|
PackedVector3Array::from(
|
||||||
chunk
|
chunk
|
||||||
@@ -116,6 +181,79 @@ fn collect_points(chunk: Chunk<PointList>) -> PackedVector3Array {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn collect_material(surface: SurfaceDefinition, clip: ImageClip) -> Gd<StandardMaterial3D> {
|
||||||
|
let mut material = StandardMaterial3D::new();
|
||||||
|
material.set_name(surface.name.to_string().into());
|
||||||
|
|
||||||
|
let mut i: Option<Gd<Image>> = None;
|
||||||
|
for img in clip.attributes {
|
||||||
|
match img {
|
||||||
|
ImageClipSubChunk::StillImage(still) => {
|
||||||
|
let path = format!(
|
||||||
|
"sar://{}",
|
||||||
|
still.name.to_string().replace('\\', "/").replace(':', ":/")
|
||||||
|
);
|
||||||
|
godot_print!("Loading {}", &path);
|
||||||
|
i = Some(load(path));
|
||||||
|
}
|
||||||
|
x => {
|
||||||
|
godot_warn!("Invalid clip chunk {:?}", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for attr in surface.attributes {
|
||||||
|
match attr {
|
||||||
|
SurfaceParameterSubChunk::Blocks(blocks) => {
|
||||||
|
if let SurfaceBlocks::ImageMapTexture { header, attributes } = blocks.data {
|
||||||
|
let mut texture = ImageTexture::new();
|
||||||
|
let mut chan = TextureParam::TEXTURE_ALBEDO;
|
||||||
|
for attr in header.data.block_attributes {
|
||||||
|
match attr {
|
||||||
|
SurfaceBlockHeaderSubChunk::Channel(c) => {
|
||||||
|
chan = match c.data.texture_channel {
|
||||||
|
TextureChannel::Color => TextureParam::TEXTURE_ALBEDO,
|
||||||
|
TextureChannel::Diffuse => TextureParam::TEXTURE_ALBEDO,
|
||||||
|
TextureChannel::Bump => TextureParam::TEXTURE_HEIGHTMAP,
|
||||||
|
TextureChannel::RefractiveIndex => {
|
||||||
|
TextureParam::TEXTURE_REFRACTION
|
||||||
|
}
|
||||||
|
TextureChannel::Specular => TextureParam::TEXTURE_METALLIC,
|
||||||
|
TextureChannel::Glossy => TextureParam::TEXTURE_ROUGHNESS,
|
||||||
|
x => {
|
||||||
|
godot_warn!("Invalid channel {:?}", x);
|
||||||
|
TextureParam::TEXTURE_ORM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => {
|
||||||
|
godot_warn!("Invalid surface header chunk {:?}", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for attr in attributes {
|
||||||
|
match attr {
|
||||||
|
SurfaceBlockImageTextureSubChunk::ImageMap(r) => {
|
||||||
|
texture.set_image(i.unwrap());
|
||||||
|
i = None;
|
||||||
|
}
|
||||||
|
x => {
|
||||||
|
godot_warn!("Invalid image texture chunk {:?}", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
material.set_texture(chan, texture.upcast());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x => {
|
||||||
|
godot_warn!("Invalid Surface Chunk {:?}", x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
material
|
||||||
|
}
|
||||||
|
|
||||||
fn collect_polygons(chunk: Chunk<PolygonLists>) -> PackedInt32Array {
|
fn collect_polygons(chunk: Chunk<PolygonLists>) -> PackedInt32Array {
|
||||||
debug_assert!(chunk.polygons.len() >= 3, "{:?}", chunk);
|
debug_assert!(chunk.polygons.len() >= 3, "{:?}", chunk);
|
||||||
PackedInt32Array::from(
|
PackedInt32Array::from(
|
||||||
|
|||||||
1
rust/mhgd/src/starforce/mod.rs
Normal file
1
rust/mhgd/src/starforce/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod sar_archive;
|
||||||
92
rust/mhgd/src/starforce/sar_archive.rs
Normal file
92
rust/mhgd/src/starforce/sar_archive.rs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
use crate::lightwave_object::lightwave_to_gd;
|
||||||
|
use dds::{Compression, PixelFormat, DDS};
|
||||||
|
use godot::bind::{godot_api, GodotClass};
|
||||||
|
use godot::builtin::{GodotString, PackedByteArray, StringName, ToVariant, Variant};
|
||||||
|
use godot::engine::global::Error;
|
||||||
|
use godot::engine::image::Format;
|
||||||
|
use godot::engine::{Image, ImageTexture, ResourceFormatLoader, ResourceFormatLoaderVirtual};
|
||||||
|
use godot::obj::{Base, Gd};
|
||||||
|
use lightwave_3d::LightWaveObject;
|
||||||
|
use starforcelib::sarc::SarcArchive;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
const SAR_PATH: &str = r#"E:\Games\mhall\Moorhuhn Kart 3\data.sar"#;
|
||||||
|
|
||||||
|
#[derive(GodotClass)]
|
||||||
|
#[class(base=ResourceFormatLoader)]
|
||||||
|
pub struct SarLoader {
|
||||||
|
pub archive: SarcArchive,
|
||||||
|
|
||||||
|
#[base]
|
||||||
|
pub base: Base<ResourceFormatLoader>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl SarLoader {}
|
||||||
|
|
||||||
|
#[godot_api]
|
||||||
|
impl ResourceFormatLoaderVirtual for SarLoader {
|
||||||
|
fn init(base: Base<Self::Base>) -> Self {
|
||||||
|
let mut file = File::open(SAR_PATH).unwrap();
|
||||||
|
let archive = SarcArchive::read(&mut file).unwrap();
|
||||||
|
|
||||||
|
Self { base, archive }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recognize_path(&self, path: GodotString, type_: StringName) -> bool {
|
||||||
|
path.to_string().starts_with("sar://")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
path: GodotString,
|
||||||
|
original_path: GodotString,
|
||||||
|
use_sub_threads: bool,
|
||||||
|
cache_mode: i64,
|
||||||
|
) -> Variant {
|
||||||
|
let internal_path = original_path
|
||||||
|
.to_string()
|
||||||
|
.strip_prefix("sar://")
|
||||||
|
.unwrap()
|
||||||
|
.replace('/', "\\");
|
||||||
|
|
||||||
|
match path.to_string().rsplit_once('.') {
|
||||||
|
Some((_, "lwo")) => {
|
||||||
|
let mut f = File::open(SAR_PATH).unwrap();
|
||||||
|
let data = self
|
||||||
|
.archive
|
||||||
|
.extract(&mut f, internal_path.as_str())
|
||||||
|
.unwrap();
|
||||||
|
let obj = LightWaveObject::read(&mut Cursor::new(data)).unwrap();
|
||||||
|
lightwave_to_gd(obj).to_variant()
|
||||||
|
}
|
||||||
|
Some((_, "bmp")) => {
|
||||||
|
let mut f = File::open(SAR_PATH).unwrap();
|
||||||
|
|
||||||
|
let mut image = Image::new();
|
||||||
|
if let Ok(bmp) = self.archive.extract(&mut f, internal_path.as_str()) {
|
||||||
|
image.load_bmp_from_buffer(PackedByteArray::from(bmp.as_slice()));
|
||||||
|
} else if let Ok(dds) = self
|
||||||
|
.archive
|
||||||
|
.extract(&mut f, format!("{}.dds", internal_path).as_str())
|
||||||
|
{
|
||||||
|
let data = DDS::decode(&mut Cursor::new(dds)).unwrap();
|
||||||
|
image.set_data(
|
||||||
|
data.header.width as i64,
|
||||||
|
data.header.height as i64,
|
||||||
|
false,
|
||||||
|
Format::FORMAT_RGBA8,
|
||||||
|
data.layers[0]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|px| [px.r, px.g, px.b, px.a])
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
image.to_variant()
|
||||||
|
}
|
||||||
|
None => Error::ERR_FILE_UNRECOGNIZED.to_variant(),
|
||||||
|
_ => Error::ERR_BUG.to_variant(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user