mirror of
https://github.com/Theaninova/mhlib.git
synced 2025-12-11 03:56:18 +00:00
stuff
This commit is contained in:
@@ -1,25 +1,25 @@
|
||||
[gd_scene load_steps=21 format=3 uid="uid://cmqfu6cc780h4"]
|
||||
|
||||
[ext_resource type="Theme" uid="uid://ks2uyxqg6u4k" path="res://mhjnr/theme.tres" id="1_24af1"]
|
||||
[ext_resource type="Script" path="res://main.gd" id="2_3ufyn"]
|
||||
[ext_resource type="Texture2D" uid="uid://dyga5qn124307" path="res://cover_art/schatzjaeger.webp" id="3_dq726"]
|
||||
[ext_resource type="Texture2D" uid="uid://by4wug5r7311q" path="res://cover_art/schatzjaeger_2.jpg" id="4_qurcc"]
|
||||
[ext_resource type="Texture2D" uid="uid://bkn3cdrm1fj8b" path="res://cover_art/schatzjaeger_3.jpg" id="5_wceoy"]
|
||||
[ext_resource type="Texture2D" uid="uid://8vn1dpq37mve" path="res://cover_art/atlantis.webp" id="6_mwmag"]
|
||||
[ext_resource type="Texture2D" uid="uid://bk5a3xob0raqj" path="res://cover_art/mh_kart.jpg" id="7_kndjp"]
|
||||
[ext_resource type="Texture2D" uid="uid://dkhygfyylbjov" path="res://cover_art/mh_kart2.jpg" id="8_r2mlu"]
|
||||
[ext_resource type="Texture2D" uid="uid://l8groudaf385" path="res://cover_art/mh_kart3.webp" id="9_yfa8e"]
|
||||
[ext_resource type="Texture2D" uid="uid://cjp0ilsodyu4j" path="res://cover_art/mh_kart4.jpg" id="10_s4ouh"]
|
||||
[ext_resource type="Texture2D" uid="uid://wetnflcj1b0w" path="res://cover_art/mh1.jpg" id="11_0icjw"]
|
||||
[ext_resource type="Texture2D" uid="uid://baqjofchj6yaw" path="res://cover_art/mhw.webp" id="12_8qgke"]
|
||||
[ext_resource type="Texture2D" uid="uid://brovl1cel1uiw" path="res://cover_art/mh2.jpg" id="13_dypyq"]
|
||||
[ext_resource type="Texture2D" uid="uid://ix132vewff0h" path="res://cover_art/mh3.jpg" id="14_tc2rn"]
|
||||
[ext_resource type="Texture2D" uid="uid://k8i84cvnuun" path="res://cover_art/mhx.jpg" id="15_gxg0f"]
|
||||
[ext_resource type="Texture2D" uid="uid://bst48atkwn7r1" path="res://cover_art/mhrem.png" id="16_dtmhv"]
|
||||
[ext_resource type="Texture2D" uid="uid://l37kev18676o" path="res://cover_art/mhwant.jpg" id="17_pcn4f"]
|
||||
[ext_resource type="Texture2D" uid="uid://cpigwqlll0kbf" path="res://cover_art/mhpir.jpg" id="18_w72rq"]
|
||||
[ext_resource type="Texture2D" uid="uid://chcjw51coc53r" path="res://cover_art/mhinv.jpg" id="19_31858"]
|
||||
[ext_resource type="Texture2D" uid="uid://bmybnhi2i2ep" path="res://cover_art/mhdir.jpg" id="20_b2doc"]
|
||||
[ext_resource type="Theme" uid="uid://ks2uyxqg6u4k" path="res://mhjnr/theme.tres" id="1_knjtf"]
|
||||
[ext_resource type="Script" path="res://main.gd" id="2_p7swk"]
|
||||
[ext_resource type="Texture2D" uid="uid://dyga5qn124307" path="res://cover_art/schatzjaeger.webp" id="3_5nh86"]
|
||||
[ext_resource type="Texture2D" uid="uid://by4wug5r7311q" path="res://cover_art/schatzjaeger_2.jpg" id="4_f32r0"]
|
||||
[ext_resource type="Texture2D" uid="uid://bkn3cdrm1fj8b" path="res://cover_art/schatzjaeger_3.jpg" id="5_wx0lg"]
|
||||
[ext_resource type="Texture2D" uid="uid://8vn1dpq37mve" path="res://cover_art/atlantis.webp" id="6_hvil1"]
|
||||
[ext_resource type="Texture2D" uid="uid://bk5a3xob0raqj" path="res://cover_art/mh_kart.jpg" id="7_2e20o"]
|
||||
[ext_resource type="Texture2D" uid="uid://dkhygfyylbjov" path="res://cover_art/mh_kart2.jpg" id="8_txpwp"]
|
||||
[ext_resource type="Texture2D" uid="uid://l8groudaf385" path="res://cover_art/mh_kart3.webp" id="9_lxivp"]
|
||||
[ext_resource type="Texture2D" uid="uid://cjp0ilsodyu4j" path="res://cover_art/mh_kart4.jpg" id="10_7ea4r"]
|
||||
[ext_resource type="Texture2D" uid="uid://wetnflcj1b0w" path="res://cover_art/mh1.jpg" id="11_jg4b8"]
|
||||
[ext_resource type="Texture2D" uid="uid://baqjofchj6yaw" path="res://cover_art/mhw.webp" id="12_rg2iw"]
|
||||
[ext_resource type="Texture2D" uid="uid://brovl1cel1uiw" path="res://cover_art/mh2.jpg" id="13_q5tum"]
|
||||
[ext_resource type="Texture2D" uid="uid://ix132vewff0h" path="res://cover_art/mh3.jpg" id="14_pi7qg"]
|
||||
[ext_resource type="Texture2D" uid="uid://k8i84cvnuun" path="res://cover_art/mhx.jpg" id="15_gwira"]
|
||||
[ext_resource type="Texture2D" uid="uid://bst48atkwn7r1" path="res://cover_art/mhrem.png" id="16_mgcbp"]
|
||||
[ext_resource type="Texture2D" uid="uid://l37kev18676o" path="res://cover_art/mhwant.jpg" id="17_xtbol"]
|
||||
[ext_resource type="Texture2D" uid="uid://cpigwqlll0kbf" path="res://cover_art/mhpir.jpg" id="18_s6b4p"]
|
||||
[ext_resource type="Texture2D" uid="uid://chcjw51coc53r" path="res://cover_art/mhinv.jpg" id="19_f2jto"]
|
||||
[ext_resource type="Texture2D" uid="uid://bmybnhi2i2ep" path="res://cover_art/mhdir.jpg" id="20_bo8ks"]
|
||||
|
||||
[node name="main" type="ScrollContainer"]
|
||||
anchors_preset = 15
|
||||
@@ -29,8 +29,8 @@ offset_right = 20.0
|
||||
offset_bottom = 154.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme = ExtResource("1_24af1")
|
||||
script = ExtResource("2_3ufyn")
|
||||
theme = ExtResource("1_knjtf")
|
||||
script = ExtResource("2_p7swk")
|
||||
|
||||
[node name="margins" type="MarginContainer" parent="."]
|
||||
layout_mode = 2
|
||||
@@ -55,7 +55,7 @@ layout_mode = 2
|
||||
[node name="Schatzjaeger1" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
icon = ExtResource("3_dq726")
|
||||
icon = ExtResource("3_5nh86")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -63,7 +63,7 @@ expand_icon = true
|
||||
[node name="Schatzjaeger2" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
icon = ExtResource("4_qurcc")
|
||||
icon = ExtResource("4_f32r0")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -71,7 +71,7 @@ expand_icon = true
|
||||
[node name="Schatzjaeger3" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
icon = ExtResource("5_wceoy")
|
||||
icon = ExtResource("5_wx0lg")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -80,7 +80,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("6_mwmag")
|
||||
icon = ExtResource("6_hvil1")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -100,7 +100,7 @@ layout_mode = 2
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("7_kndjp")
|
||||
icon = ExtResource("7_2e20o")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -109,7 +109,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("8_r2mlu")
|
||||
icon = ExtResource("8_txpwp")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -118,7 +118,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("9_yfa8e")
|
||||
icon = ExtResource("9_lxivp")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -127,7 +127,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("10_s4ouh")
|
||||
icon = ExtResource("10_7ea4r")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -147,7 +147,7 @@ layout_mode = 2
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("11_0icjw")
|
||||
icon = ExtResource("11_jg4b8")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -156,7 +156,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("12_8qgke")
|
||||
icon = ExtResource("12_rg2iw")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -165,7 +165,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("13_dypyq")
|
||||
icon = ExtResource("13_q5tum")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -174,7 +174,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("14_tc2rn")
|
||||
icon = ExtResource("14_pi7qg")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -183,7 +183,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("15_gxg0f")
|
||||
icon = ExtResource("15_gwira")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -192,7 +192,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("16_dtmhv")
|
||||
icon = ExtResource("16_mgcbp")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -201,7 +201,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("17_pcn4f")
|
||||
icon = ExtResource("17_xtbol")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -210,7 +210,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("18_w72rq")
|
||||
icon = ExtResource("18_s6b4p")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -219,7 +219,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("19_31858")
|
||||
icon = ExtResource("19_f2jto")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
@@ -228,7 +228,7 @@ expand_icon = true
|
||||
custom_minimum_size = Vector2(200, 256)
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
icon = ExtResource("20_b2doc")
|
||||
icon = ExtResource("20_bo8ks")
|
||||
flat = true
|
||||
icon_alignment = 1
|
||||
expand_icon = true
|
||||
|
||||
6
godot/starforce/mhk3.gd
Normal file
6
godot/starforce/mhk3.gd
Normal file
@@ -0,0 +1,6 @@
|
||||
@tool
|
||||
extends EditorScript
|
||||
|
||||
func _run():
|
||||
var result = Mhk3Map.install("/home/theaninova/Projects/mhlib/games/Moorhuhn Kart 3/data.sar", "mhk3")
|
||||
print(result)
|
||||
@@ -52,15 +52,15 @@ vec3 project(
|
||||
case 3:
|
||||
vec3 p = (transform * vec4(position, 1.0)).xyz;
|
||||
vec3 n = normalize(abs(mat3(transform) * normal));
|
||||
vec2 uv2 = (n.x > n.y && n.x > n.z) ? vec2(p.z, p.y)
|
||||
: ((n.y > n.x && n.y > n.z) ? vec2(p.x, p.z) : vec2(p.x, p.y));
|
||||
vec2 uv2 = (n.x > n.y && n.x > n.z) ? p.zy
|
||||
: ((n.y > n.x && n.y > n.z) ? p.zx : p.xy);
|
||||
return texture(tex, uv2 + 0.5).rgb;
|
||||
case 2: // Spherical
|
||||
return vec3(0.0, 0.0, 1.0);
|
||||
case 1: // Cylindrical
|
||||
return vec3(1.0, 1.0, 0.0);
|
||||
case 0: // Planar
|
||||
return texture(tex, (transform * vec4(position, 1.0)).xz).rgb;
|
||||
return texture(tex, (transform * vec4(position, 1.0)).zx + 0.5).rgb;
|
||||
default:
|
||||
return vec3(0.0);
|
||||
}
|
||||
@@ -92,7 +92,7 @@ void fragment() {
|
||||
);
|
||||
}
|
||||
|
||||
/*void light() {
|
||||
void light() {
|
||||
DIFFUSE_LIGHT =project(
|
||||
tex_diffuse,
|
||||
tex_diffuse_projection,
|
||||
@@ -102,4 +102,4 @@ void fragment() {
|
||||
tex_diffuse_projection_world_coords,
|
||||
UV
|
||||
);
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -2,26 +2,14 @@
|
||||
|
||||
[sub_resource type="GDScript" id="GDScript_jhapx"]
|
||||
resource_name = "load"
|
||||
script/source = "@tool
|
||||
extends Node3D
|
||||
script/source = "extends Node3D
|
||||
|
||||
@export var load_list = [
|
||||
\"anlagen\",
|
||||
\"boden\",
|
||||
\"bok\",
|
||||
\"fensterscheiben\",
|
||||
\"gelaender\",
|
||||
\"kraftfelder\",
|
||||
\"rundgang\",
|
||||
\"stampfer\",
|
||||
\"timetunnel\",
|
||||
\"waende\",
|
||||
]
|
||||
@export var perform_install_on_start = true
|
||||
|
||||
func _ready():
|
||||
for item in load_list:
|
||||
var scene = load(\"sar://D:/Moorhuhnkart/3dobjects_tracks/track07_ufo/%s.lwo\" % item).instantiate()
|
||||
add_child(scene)
|
||||
if perform_install_on_start:
|
||||
var result = Mhk3Map.install(\"/home/theaninova/Projects/mhlib/games/Moorhuhn Kart 3/data.sar\", \"mhk3\")
|
||||
print(result)
|
||||
"
|
||||
|
||||
[node name="test" type="Node3D"]
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
use crate::sproing::datafile::DatafileLoader;
|
||||
use crate::starforce::sar_archive::SarLoader;
|
||||
use crate::starforce::sar_archive::{GAMES_PATH, INSTALL_PATH};
|
||||
use ::godot::engine::class_macros::auto_register_classes;
|
||||
use ::godot::engine::{ResourceFormatLoaderVirtual, ResourceLoader};
|
||||
use ::godot::init::{gdextension, ExtensionLayer};
|
||||
use ::godot::prelude::{ExtensionLibrary, Gd, InitHandle, InitLevel, Share};
|
||||
use godot::bind::godot_api;
|
||||
use godot::builtin::{GodotString, StringName, ToVariant, Variant};
|
||||
use godot::engine::global::Error;
|
||||
use godot::engine::resource_loader::CacheMode;
|
||||
use godot::engine::{Engine, ResourceFormatLoader};
|
||||
use godot::log::godot_error;
|
||||
use godot::obj::EngineEnum;
|
||||
use godot::prelude::{Base, GodotClass};
|
||||
|
||||
pub mod data_installer;
|
||||
pub mod lwo;
|
||||
@@ -20,16 +28,53 @@ unsafe impl ExtensionLibrary for Main {
|
||||
InitLevel::Editor,
|
||||
ResourceLoaderLayer {
|
||||
datafile: None,
|
||||
sarc: None,
|
||||
editor_pck: None,
|
||||
},
|
||||
);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=ResourceFormatLoader)]
|
||||
struct EditorPck {
|
||||
#[base]
|
||||
pub base: Base<ResourceFormatLoader>,
|
||||
}
|
||||
#[godot_api]
|
||||
impl ResourceFormatLoaderVirtual for EditorPck {
|
||||
fn recognize_path(&self, path: GodotString, type_: StringName) -> bool {
|
||||
path.to_string().starts_with(GAMES_PATH)
|
||||
}
|
||||
|
||||
fn load(
|
||||
&self,
|
||||
path: GodotString,
|
||||
original_path: GodotString,
|
||||
use_sub_threads: bool,
|
||||
cache_mode: i64,
|
||||
) -> Variant {
|
||||
let original_path = format!(
|
||||
"{}{}",
|
||||
INSTALL_PATH,
|
||||
original_path.to_string().strip_prefix(GAMES_PATH).unwrap()
|
||||
);
|
||||
if let Some(resource) = ResourceLoader::singleton().load(
|
||||
original_path.clone().into(),
|
||||
"".into(),
|
||||
CacheMode::from_ord(cache_mode as i32),
|
||||
) {
|
||||
resource.to_variant()
|
||||
} else {
|
||||
godot_error!("Could not find {}", original_path);
|
||||
Error::ERR_FILE_NOT_FOUND.to_variant()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ResourceLoaderLayer {
|
||||
pub datafile: Option<Gd<DatafileLoader>>,
|
||||
pub sarc: Option<Gd<SarLoader>>,
|
||||
pub editor_pck: Option<Gd<EditorPck>>,
|
||||
}
|
||||
|
||||
impl ExtensionLayer for ResourceLoaderLayer {
|
||||
@@ -37,12 +82,17 @@ impl ExtensionLayer for ResourceLoaderLayer {
|
||||
auto_register_classes();
|
||||
|
||||
self.datafile = Some(Gd::<DatafileLoader>::with_base(DatafileLoader::init));
|
||||
self.sarc = Some(Gd::<SarLoader>::with_base(SarLoader::init));
|
||||
self.editor_pck = Some(Gd::<EditorPck>::with_base(|base| EditorPck { base }));
|
||||
|
||||
if Engine::singleton().is_editor_hint() {
|
||||
ResourceLoader::singleton().add_resource_format_loader(
|
||||
self.editor_pck.as_ref().unwrap().share().upcast(),
|
||||
true,
|
||||
)
|
||||
}
|
||||
|
||||
ResourceLoader::singleton()
|
||||
.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) {
|
||||
@@ -50,9 +100,9 @@ impl ExtensionLayer for ResourceLoaderLayer {
|
||||
ResourceLoader::singleton().remove_resource_format_loader(datafile.share().upcast());
|
||||
self.datafile = None;
|
||||
}
|
||||
if let Some(sarc) = &self.sarc {
|
||||
ResourceLoader::singleton().remove_resource_format_loader(sarc.share().upcast());
|
||||
self.sarc = None;
|
||||
if let Some(editor_pck) = &self.editor_pck {
|
||||
ResourceLoader::singleton().remove_resource_format_loader(editor_pck.share().upcast());
|
||||
self.editor_pck = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
use crate::starforce::sar_archive::sarc_path_to_gd;
|
||||
use godot::builtin::{GodotString, Variant};
|
||||
use godot::engine::{load, AnimatedTexture, Image, ImageTexture, Texture2D};
|
||||
use godot::log::godot_error;
|
||||
use godot::log::{godot_error, godot_print};
|
||||
use godot::obj::Gd;
|
||||
use lightwave_3d::lwo2::tags::image_clip::{ImageClip, ImageClipSubChunk};
|
||||
use std::collections::HashMap;
|
||||
|
||||
fn convert_path(path: &str) -> String {
|
||||
path.replace('\\', "/").replace(':', ":/")
|
||||
}
|
||||
|
||||
fn load_texture(path: &str, name: &str) -> Gd<ImageTexture> {
|
||||
let mut image: Gd<Image> = load(path);
|
||||
image.set_name(name.into());
|
||||
let mut texture = ImageTexture::new();
|
||||
texture.set_name(name.into());
|
||||
texture.set_image(image);
|
||||
texture
|
||||
fn load_texture(path: &str) -> Gd<ImageTexture> {
|
||||
let mut image: Gd<ImageTexture> = load(path);
|
||||
godot_print!("ResPath: {}", image.get_path());
|
||||
let target_path = image
|
||||
.get_meta("target_path".into(), Variant::nil())
|
||||
.to::<GodotString>();
|
||||
image.set_path(target_path);
|
||||
godot_print!(
|
||||
"NowResPath: {} - {}",
|
||||
image.is_local_to_scene(),
|
||||
image.get_path()
|
||||
);
|
||||
image
|
||||
}
|
||||
|
||||
pub fn collect_clip(target: &mut HashMap<u32, Gd<Texture2D>>, clip: ImageClip) {
|
||||
@@ -22,11 +26,11 @@ pub fn collect_clip(target: &mut HashMap<u32, Gd<Texture2D>>, clip: ImageClip) {
|
||||
|
||||
match attributes.next().unwrap() {
|
||||
ImageClipSubChunk::StillImage(still) => {
|
||||
let path = format!("sar://{}", convert_path(&still.name));
|
||||
let path = sarc_path_to_gd(&still.name);
|
||||
for meta in attributes {
|
||||
godot_error!("TODO: {:?}", meta)
|
||||
}
|
||||
target.insert(clip.index, load_texture(&path, &still.name).upcast());
|
||||
target.insert(clip.index, load_texture(&path).upcast());
|
||||
}
|
||||
ImageClipSubChunk::ImageSequence(sequence) => {
|
||||
let mut texture = AnimatedTexture::new();
|
||||
@@ -47,15 +51,17 @@ pub fn collect_clip(target: &mut HashMap<u32, Gd<Texture2D>>, clip: ImageClip) {
|
||||
|
||||
for i in sequence.data.start..sequence.data.end {
|
||||
let path = format!(
|
||||
"sar://{}{:0width$}{}",
|
||||
convert_path(&sequence.data.prefix),
|
||||
"{}{:0width$}{}.res",
|
||||
sarc_path_to_gd(&sequence.data.prefix)
|
||||
.strip_suffix(".res")
|
||||
.unwrap(),
|
||||
i,
|
||||
sequence.data.suffix,
|
||||
width = sequence.data.num_digits as usize
|
||||
);
|
||||
let frame = i as i64 - sequence.data.start as i64;
|
||||
|
||||
texture.set_frame_texture(frame, load_texture(&path, &i.to_string()).upcast());
|
||||
texture.set_frame_texture(frame, load_texture(&path).upcast());
|
||||
texture.set_frame_duration(frame, frame_duration);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
use crate::lwo::object::lightwave_to_gd;
|
||||
use godot::bind::{godot_api, GodotClass};
|
||||
use godot::builtin::GodotString;
|
||||
use godot::engine::{ArrayMesh, PackedScene};
|
||||
use godot::obj::Gd;
|
||||
use lightwave_3d::LightWaveObject;
|
||||
|
||||
pub(crate) mod clips;
|
||||
pub(crate) mod intermediate_layer;
|
||||
pub(crate) mod mapping;
|
||||
@@ -12,15 +5,3 @@ pub(crate) mod material;
|
||||
pub(crate) mod object;
|
||||
pub(crate) mod surface_info;
|
||||
pub(crate) mod unique_vertex;
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(init)]
|
||||
struct Lwo {}
|
||||
|
||||
#[godot_api]
|
||||
impl Lwo {
|
||||
#[func]
|
||||
pub fn get_mesh(path: GodotString) -> Gd<PackedScene> {
|
||||
lightwave_to_gd(LightWaveObject::read_file(path.to_string()).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,15 @@ use crate::lwo::intermediate_layer::IntermediateLayer;
|
||||
use crate::lwo::mapping::{collect_discontinuous_mappings, collect_mappings};
|
||||
use crate::lwo::material::MaterialUvInfo;
|
||||
use godot::builtin::{Vector2, Vector3};
|
||||
use godot::engine::node::InternalMode;
|
||||
use godot::engine::{MeshInstance3D, Node3D, PackedScene, Texture2D};
|
||||
use godot::log::{godot_error, godot_print, godot_warn};
|
||||
use godot::obj::{Gd, Share};
|
||||
use godot::engine::{ArrayMesh, Texture2D};
|
||||
use godot::log::{godot_error, godot_warn};
|
||||
use godot::obj::Gd;
|
||||
use itertools::Itertools;
|
||||
use lightwave_3d::lwo2::tags::Tag;
|
||||
use lightwave_3d::LightWaveObject;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
||||
pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Vec<Gd<ArrayMesh>> {
|
||||
let mut materials = HashMap::<u16, MaterialUvInfo>::new();
|
||||
let mut textures = HashMap::<u32, Gd<Texture2D>>::new();
|
||||
let mut layers = vec![];
|
||||
@@ -22,7 +21,6 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
||||
match tag {
|
||||
Tag::TagStrings(it) => {
|
||||
tag_strings = it.data.tag_strings.into_iter().collect();
|
||||
godot_print!("{:?}", tag_strings);
|
||||
}
|
||||
Tag::Layer(layer_tag) => {
|
||||
layers.push(IntermediateLayer {
|
||||
@@ -143,7 +141,6 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
||||
.iter()
|
||||
.find_position(|name| name == &&surf_name)
|
||||
.expect("Invalid File");
|
||||
godot_print!("'{}': {}", surf_name, tag_index);
|
||||
|
||||
materials.insert(
|
||||
tag_index as u16,
|
||||
@@ -157,36 +154,8 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
||||
}
|
||||
}
|
||||
|
||||
/*godot_print!(
|
||||
"{:?}",
|
||||
surfaces
|
||||
.iter()
|
||||
.map(|(k, v)| (
|
||||
k,
|
||||
tag_strings[*k as usize].clone(),
|
||||
v.material.get_shader_parameter("tex_diffuse".into()),
|
||||
v.material.get_shader_parameter("tex_color".into())
|
||||
))
|
||||
.collect_vec()
|
||||
);*/
|
||||
|
||||
let mut root_node = Node3D::new_alloc();
|
||||
|
||||
for layer in layers {
|
||||
let mut instance = MeshInstance3D::new_alloc();
|
||||
instance.set_name(layer.name.clone().into());
|
||||
instance.set_mesh(layer.commit(&materials).upcast());
|
||||
|
||||
root_node.add_child(
|
||||
instance.share().upcast(),
|
||||
false,
|
||||
InternalMode::INTERNAL_MODE_DISABLED,
|
||||
);
|
||||
instance.set_owner(root_node.share().upcast());
|
||||
}
|
||||
|
||||
let mut scene = PackedScene::new();
|
||||
scene.pack(root_node.share().upcast());
|
||||
root_node.queue_free();
|
||||
scene
|
||||
layers
|
||||
.into_iter()
|
||||
.map(|layer| layer.commit(&materials))
|
||||
.collect()
|
||||
}
|
||||
|
||||
99
rust/mhgd/src/starforce/mhk3_map.rs
Normal file
99
rust/mhgd/src/starforce/mhk3_map.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use crate::starforce::sar_archive::{sarc_path_to_gd, SarLoader, GAMES_PATH};
|
||||
use godot::bind::godot_api;
|
||||
use godot::builtin::GodotString;
|
||||
use godot::engine::file_access::ModeFlags;
|
||||
use godot::engine::global::Error;
|
||||
use godot::engine::{try_load, DirAccess, FileAccess, PckPacker, Resource, ResourceLoader};
|
||||
use godot::log::godot_print;
|
||||
use godot::obj::{Gd, Share};
|
||||
use godot::prelude::GodotClass;
|
||||
use itertools::Itertools;
|
||||
use starforcelib::sarc::SarcArchive;
|
||||
use std::collections::HashSet;
|
||||
use std::io::Cursor;
|
||||
use std::iter::{Chain, FlatMap};
|
||||
use std::path::Iter;
|
||||
use std::vec::IntoIter;
|
||||
|
||||
/// This is supposedly to be the default.
|
||||
const KEY: &str = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(init)]
|
||||
pub struct Mhk3Map {}
|
||||
|
||||
#[godot_api]
|
||||
impl Mhk3Map {
|
||||
#[func]
|
||||
pub fn get_available_maps() {}
|
||||
|
||||
#[func]
|
||||
pub fn test() {}
|
||||
|
||||
#[func]
|
||||
pub fn install(path: GodotString, game: GodotString) -> Error {
|
||||
let file = if let Some(file) = FileAccess::open(path, ModeFlags::READ) {
|
||||
file
|
||||
} else {
|
||||
return Error::ERR_FILE_NOT_FOUND;
|
||||
};
|
||||
|
||||
let data = file.get_buffer(file.get_length()).to_vec();
|
||||
let mut archive = match SarcArchive::read(&mut Cursor::new(&data)) {
|
||||
Ok(archive) => archive,
|
||||
Err(error) => return Error::ERR_FILE_CORRUPT,
|
||||
};
|
||||
let mut files_to_convert = HashSet::new();
|
||||
for file in archive.files.iter_mut() {
|
||||
let convert = file.path.ends_with(".lwo");
|
||||
file.path = sarc_path_to_gd(&file.path);
|
||||
if convert {
|
||||
files_to_convert.insert(file.path.clone());
|
||||
}
|
||||
}
|
||||
|
||||
files_to_convert.remove(
|
||||
"user://.install/D/Moorhuhnkart/3dobjects_tracks/track01_steinzeit/pflanzen.lwo.res",
|
||||
);
|
||||
files_to_convert.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/rauch.lwo.res");
|
||||
files_to_convert.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/rauch2.lwo.res");
|
||||
files_to_convert.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/rauch3.lwo.res");
|
||||
files_to_convert.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/rauch4.lwo.res");
|
||||
files_to_convert.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/rauch5.lwo.res");
|
||||
files_to_convert.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/rauch6.lwo.res");
|
||||
files_to_convert.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/rauch7.lwo.res");
|
||||
files_to_convert.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/rauch8.lwo.res");
|
||||
files_to_convert
|
||||
.remove("user://.install/D/Moorhuhnkart/3dobjects_extras/schutzschild.lwo.res");
|
||||
files_to_convert.remove(
|
||||
"user://.install/D/Moorhuhnkart/menu/kart_select/menu_character_moorhuhn.lwo.res",
|
||||
);
|
||||
|
||||
let sar_loader = Gd::<SarLoader>::with_base(|base| SarLoader {
|
||||
archive,
|
||||
data,
|
||||
target_path: game.to_string(),
|
||||
base,
|
||||
});
|
||||
|
||||
ResourceLoader::singleton().add_resource_format_loader(sar_loader.share().upcast(), true);
|
||||
for (i, file) in files_to_convert.into_iter().sorted().enumerate() {
|
||||
godot_print!("{}x Next up: {}", i, file);
|
||||
try_load::<Resource>(file);
|
||||
}
|
||||
ResourceLoader::singleton().remove_resource_format_loader(sar_loader.upcast());
|
||||
|
||||
let mut packer = PckPacker::new();
|
||||
packer.pck_start(format!("user://{}.pck", game).into(), 32, KEY.into(), false);
|
||||
for file in SarLoader::list_installed_files() {
|
||||
packer.add_file(
|
||||
SarLoader::resource_path_at(file.clone(), &game),
|
||||
file.clone().into(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
packer.flush(true);
|
||||
|
||||
Error::OK
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
pub mod mhk3_map;
|
||||
pub mod sar_archive;
|
||||
|
||||
@@ -1,41 +1,81 @@
|
||||
use crate::lwo::object::lightwave_to_gd;
|
||||
use dds::{Compression, PixelFormat, DDS};
|
||||
use dds::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 godot::engine::resource_loader::CacheMode;
|
||||
use godot::engine::resource_saver::SaverFlags;
|
||||
use godot::engine::{
|
||||
DirAccess, FileAccess, Image, ImageTexture, Resource, ResourceFormatLoader,
|
||||
ResourceFormatLoaderVirtual, ResourceLoader, ResourceSaver, Texture2D,
|
||||
};
|
||||
use godot::log::godot_error;
|
||||
use godot::obj::{Base, Share};
|
||||
use godot::prelude::godot_print;
|
||||
use lightwave_3d::LightWaveObject;
|
||||
use starforcelib::sarc::SarcArchive;
|
||||
use std::fs::File;
|
||||
use std::io::Cursor;
|
||||
|
||||
const SAR_PATH: &str = r#"../games/Moorhuhn Kart 3/data.sar"#;
|
||||
pub const GAMES_PATH: &str = "res://games/";
|
||||
pub const INSTALL_PATH: &str = "user://.install/";
|
||||
|
||||
pub fn sarc_path_to_gd<T: ToString>(path: &T) -> String {
|
||||
format!(
|
||||
"{}{}.res",
|
||||
INSTALL_PATH,
|
||||
path.to_string()
|
||||
.replace(['\\', ':'], "/")
|
||||
.replace("//", "/")
|
||||
)
|
||||
}
|
||||
|
||||
fn files_recursive(path: String) -> Vec<String> {
|
||||
DirAccess::get_directories_at(path.clone().into())
|
||||
.to_vec()
|
||||
.into_iter()
|
||||
.map(|it| format!("{}/{}", path, it))
|
||||
.flat_map(files_recursive)
|
||||
.chain(
|
||||
DirAccess::get_files_at(path.clone().into())
|
||||
.to_vec()
|
||||
.into_iter()
|
||||
.map(|it| format!("{}/{}", path, it)),
|
||||
)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[derive(GodotClass)]
|
||||
#[class(base=ResourceFormatLoader)]
|
||||
pub struct SarLoader {
|
||||
pub archive: SarcArchive,
|
||||
pub data: Vec<u8>,
|
||||
pub target_path: String,
|
||||
|
||||
#[base]
|
||||
pub base: Base<ResourceFormatLoader>,
|
||||
}
|
||||
|
||||
#[godot_api]
|
||||
impl SarLoader {}
|
||||
impl SarLoader {
|
||||
pub fn list_installed_files() -> Vec<String> {
|
||||
files_recursive(INSTALL_PATH.strip_suffix('/').unwrap().into())
|
||||
}
|
||||
|
||||
pub fn resource_path_at(path: String, game: &GodotString) -> GodotString {
|
||||
format!(
|
||||
"{}/{}",
|
||||
GAMES_PATH,
|
||||
path.strip_prefix(INSTALL_PATH).unwrap()
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[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://")
|
||||
path.to_string().starts_with(INSTALL_PATH) /*|| path.to_string().starts_with(GAMES_PATH)*/
|
||||
}
|
||||
|
||||
fn load(
|
||||
@@ -45,32 +85,84 @@ impl ResourceFormatLoaderVirtual for SarLoader {
|
||||
use_sub_threads: bool,
|
||||
cache_mode: i64,
|
||||
) -> Variant {
|
||||
let internal_path = original_path
|
||||
.to_string()
|
||||
.strip_prefix("sar://")
|
||||
.unwrap()
|
||||
.replace('/', "\\");
|
||||
let path = original_path.to_string();
|
||||
let original_path = if path.starts_with(GAMES_PATH) {
|
||||
path.strip_prefix(GAMES_PATH)
|
||||
.unwrap()
|
||||
.strip_prefix(&self.target_path)
|
||||
.unwrap()
|
||||
.strip_prefix('/')
|
||||
.unwrap()
|
||||
} else {
|
||||
path.strip_prefix(INSTALL_PATH).unwrap()
|
||||
};
|
||||
let internal_path: GodotString = format!("{}{}", INSTALL_PATH, original_path).into();
|
||||
let original_path: GodotString = format!(
|
||||
"{}{}/{}",
|
||||
INSTALL_PATH,
|
||||
self.target_path,
|
||||
original_path
|
||||
.strip_prefix(&format!("{}/", self.target_path))
|
||||
.unwrap_or(original_path)
|
||||
)
|
||||
.into();
|
||||
|
||||
match path.to_string().rsplit_once('.') {
|
||||
match internal_path
|
||||
.to_string()
|
||||
.strip_suffix(".res")
|
||||
.unwrap_or(&internal_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())
|
||||
.extract(&mut Cursor::new(&self.data), &internal_path.to_string())
|
||||
.unwrap();
|
||||
let obj = LightWaveObject::read(&mut Cursor::new(data)).unwrap();
|
||||
lightwave_to_gd(obj).to_variant()
|
||||
|
||||
let directory = original_path
|
||||
.to_string()
|
||||
.strip_suffix(".res")
|
||||
.unwrap()
|
||||
.to_string();
|
||||
|
||||
DirAccess::make_dir_recursive_absolute(directory.clone().into());
|
||||
for mut mesh in lightwave_to_gd(obj) {
|
||||
let name = mesh.get_name();
|
||||
let path = format!("{}/{}.res", directory, name);
|
||||
|
||||
mesh.set_path(Self::resource_path_at(
|
||||
path.to_string(),
|
||||
&self.target_path.clone().into(),
|
||||
));
|
||||
println!("{}", path);
|
||||
ResourceSaver::singleton().save(
|
||||
mesh.upcast(),
|
||||
path.into(),
|
||||
SaverFlags::FLAG_CHANGE_PATH,
|
||||
);
|
||||
}
|
||||
|
||||
Resource::new().to_variant()
|
||||
}
|
||||
Some((_, "bmp" | "dds")) => {
|
||||
let mut f = File::open(SAR_PATH).unwrap();
|
||||
Some((base, "bmp" | "dds")) => {
|
||||
if FileAccess::file_exists(original_path.clone()) {
|
||||
godot_print!("Reusing {}", original_path);
|
||||
return ResourceLoader::singleton()
|
||||
.load(original_path, "".into(), CacheMode::CACHE_MODE_REUSE)
|
||||
.to_variant();
|
||||
}
|
||||
|
||||
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
|
||||
if let Ok(bmp) = self
|
||||
.archive
|
||||
.extract(&mut f, format!("{}.dds", internal_path).as_str())
|
||||
.extract(&mut Cursor::new(&self.data), &internal_path.to_string())
|
||||
{
|
||||
image.load_bmp_from_buffer(PackedByteArray::from(bmp.as_slice()));
|
||||
} else if let Ok(dds) = self.archive.extract(
|
||||
&mut Cursor::new(&self.data),
|
||||
format!("{}.bmp.dds.res", &base).as_str(),
|
||||
) {
|
||||
let data = DDS::decode(&mut Cursor::new(dds)).unwrap();
|
||||
image.set_data(
|
||||
data.header.width as i64,
|
||||
@@ -81,9 +173,48 @@ impl ResourceFormatLoaderVirtual for SarLoader {
|
||||
.iter()
|
||||
.flat_map(|px| [px.r, px.g, px.b, px.a])
|
||||
.collect(),
|
||||
)
|
||||
);
|
||||
image.decompress();
|
||||
} else {
|
||||
godot_error!("Could not find {} or {}.bmp.dds.res", original_path, base)
|
||||
}
|
||||
image.to_variant()
|
||||
|
||||
image.generate_mipmaps(true);
|
||||
|
||||
image.set_name(
|
||||
original_path
|
||||
.to_string()
|
||||
.rsplit_once('/')
|
||||
.unwrap()
|
||||
.1
|
||||
.strip_suffix(".res")
|
||||
.unwrap()
|
||||
.into(),
|
||||
);
|
||||
|
||||
println!("{}", original_path);
|
||||
// image.set_path(cache_path.to_string().into());
|
||||
DirAccess::make_dir_recursive_absolute(
|
||||
original_path.to_string().rsplit_once('/').unwrap().0.into(),
|
||||
);
|
||||
|
||||
let mut texture = ImageTexture::new();
|
||||
texture.set_name(image.get_name());
|
||||
texture.set_image(image);
|
||||
|
||||
let target_path = Self::resource_path_at(
|
||||
original_path.clone().into(),
|
||||
&self.target_path.clone().into(),
|
||||
);
|
||||
texture.set_meta("target_path".into(), target_path.to_variant());
|
||||
texture.set_path(target_path);
|
||||
ResourceSaver::singleton().save(
|
||||
texture.share().upcast(),
|
||||
original_path,
|
||||
SaverFlags::FLAG_COMPRESS,
|
||||
);
|
||||
|
||||
texture.to_variant()
|
||||
}
|
||||
None => Error::ERR_FILE_UNRECOGNIZED.to_variant(),
|
||||
_ => Error::ERR_BUG.to_variant(),
|
||||
|
||||
Reference in New Issue
Block a user