mirror of
https://github.com/Theaninova/mhlib.git
synced 2026-01-03 15:22:52 +00:00
cleanup
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
[gd_scene load_steps=5 format=3 uid="uid://4n26dt3e4pv3"]
|
[gd_scene load_steps=5 format=3 uid="uid://4n26dt3e4pv3"]
|
||||||
|
|
||||||
[ext_resource type="Shader" path="res://kart/flag.gdshader" id="1_lbvg8"]
|
[ext_resource type="Shader" path="res://kart/flag.gdshader" id="1_mtrao"]
|
||||||
[ext_resource type="FontFile" uid="uid://b50bdb32aerbb" path="res://remakes/font/LondrinaSolid-Regular.otf" id="2_fj37l"]
|
[ext_resource type="FontFile" uid="uid://b50bdb32aerbb" path="res://remakes/font/LondrinaSolid-Regular.otf" id="2_vriwa"]
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_y6o8u"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_y6o8u"]
|
||||||
shader = ExtResource("1_lbvg8")
|
shader = ExtResource("1_mtrao")
|
||||||
shader_parameter/rotation = 2.2
|
shader_parameter/rotation = 2.2
|
||||||
shader_parameter/size = 160.0
|
shader_parameter/size = 160.0
|
||||||
shader_parameter/time_scale = 0.125
|
shader_parameter/time_scale = 0.125
|
||||||
@@ -40,7 +40,7 @@ grow_horizontal = 2
|
|||||||
theme_override_colors/font_color = Color(0.996078, 0.92549, 0.14902, 1)
|
theme_override_colors/font_color = Color(0.996078, 0.92549, 0.14902, 1)
|
||||||
theme_override_colors/font_outline_color = Color(0.776471, 0.215686, 0.14902, 1)
|
theme_override_colors/font_outline_color = Color(0.776471, 0.215686, 0.14902, 1)
|
||||||
theme_override_constants/outline_size = 23
|
theme_override_constants/outline_size = 23
|
||||||
theme_override_fonts/font = ExtResource("2_fj37l")
|
theme_override_fonts/font = ExtResource("2_vriwa")
|
||||||
theme_override_font_sizes/font_size = 60
|
theme_override_font_sizes/font_size = 60
|
||||||
text = "Moorhuhn"
|
text = "Moorhuhn"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
@@ -55,7 +55,7 @@ theme_override_colors/font_color = Color(0.894118, 0.133333, 0.0705882, 1)
|
|||||||
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
theme_override_colors/font_outline_color = Color(1, 1, 1, 1)
|
||||||
theme_override_constants/outline_size = 15
|
theme_override_constants/outline_size = 15
|
||||||
theme_override_constants/line_spacing = -140
|
theme_override_constants/line_spacing = -140
|
||||||
theme_override_fonts/font = ExtResource("2_fj37l")
|
theme_override_fonts/font = ExtResource("2_vriwa")
|
||||||
theme_override_font_sizes/font_size = 97
|
theme_override_font_sizes/font_size = 97
|
||||||
text = "»KART«"
|
text = "»KART«"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
@@ -71,7 +71,7 @@ rotation = -0.338594
|
|||||||
theme_override_colors/font_color = Color(0.913725, 0.945098, 0.952941, 1)
|
theme_override_colors/font_color = Color(0.913725, 0.945098, 0.952941, 1)
|
||||||
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
|
||||||
theme_override_constants/outline_size = 14
|
theme_override_constants/outline_size = 14
|
||||||
theme_override_fonts/font = ExtResource("2_fj37l")
|
theme_override_fonts/font = ExtResource("2_vriwa")
|
||||||
theme_override_font_sizes/font_size = 48
|
theme_override_font_sizes/font_size = 48
|
||||||
text = "ULTIMATE"
|
text = "ULTIMATE"
|
||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
[gd_scene load_steps=21 format=3 uid="uid://cmqfu6cc780h4"]
|
[gd_scene load_steps=21 format=3 uid="uid://cmqfu6cc780h4"]
|
||||||
|
|
||||||
[ext_resource type="Theme" uid="uid://ks2uyxqg6u4k" path="res://mhjnr/theme.tres" id="1_4qyey"]
|
[ext_resource type="Theme" uid="uid://ks2uyxqg6u4k" path="res://mhjnr/theme.tres" id="1_24af1"]
|
||||||
[ext_resource type="Texture2D" uid="uid://wetnflcj1b0w" path="res://cover_art/mh1.jpg" id="2_epsv5"]
|
[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="2_f5uhf"]
|
[ext_resource type="Texture2D" uid="uid://dyga5qn124307" path="res://cover_art/schatzjaeger.webp" id="3_dq726"]
|
||||||
[ext_resource type="Script" path="res://main.gd" id="2_j1xqk"]
|
[ext_resource type="Texture2D" uid="uid://by4wug5r7311q" path="res://cover_art/schatzjaeger_2.jpg" id="4_qurcc"]
|
||||||
[ext_resource type="Texture2D" uid="uid://baqjofchj6yaw" path="res://cover_art/mhw.webp" id="3_wgtv5"]
|
[ext_resource type="Texture2D" uid="uid://bkn3cdrm1fj8b" path="res://cover_art/schatzjaeger_3.jpg" id="5_wceoy"]
|
||||||
[ext_resource type="Texture2D" uid="uid://brovl1cel1uiw" path="res://cover_art/mh2.jpg" id="4_fb5aq"]
|
[ext_resource type="Texture2D" uid="uid://8vn1dpq37mve" path="res://cover_art/atlantis.webp" id="6_mwmag"]
|
||||||
[ext_resource type="Texture2D" uid="uid://ix132vewff0h" path="res://cover_art/mh3.jpg" id="5_q44ta"]
|
[ext_resource type="Texture2D" uid="uid://bk5a3xob0raqj" path="res://cover_art/mh_kart.jpg" id="7_kndjp"]
|
||||||
[ext_resource type="Texture2D" uid="uid://k8i84cvnuun" path="res://cover_art/mhx.jpg" id="6_b76vr"]
|
[ext_resource type="Texture2D" uid="uid://dkhygfyylbjov" path="res://cover_art/mh_kart2.jpg" id="8_r2mlu"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bst48atkwn7r1" path="res://cover_art/mhrem.png" id="7_ios37"]
|
[ext_resource type="Texture2D" uid="uid://l8groudaf385" path="res://cover_art/mh_kart3.webp" id="9_yfa8e"]
|
||||||
[ext_resource type="Texture2D" uid="uid://chcjw51coc53r" path="res://cover_art/mhinv.jpg" id="8_1fm4r"]
|
[ext_resource type="Texture2D" uid="uid://cjp0ilsodyu4j" path="res://cover_art/mh_kart4.jpg" id="10_s4ouh"]
|
||||||
[ext_resource type="Texture2D" uid="uid://l37kev18676o" path="res://cover_art/mhwant.jpg" id="8_yb215"]
|
[ext_resource type="Texture2D" uid="uid://wetnflcj1b0w" path="res://cover_art/mh1.jpg" id="11_0icjw"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bk5a3xob0raqj" path="res://cover_art/mh_kart.jpg" id="9_b3ixn"]
|
[ext_resource type="Texture2D" uid="uid://baqjofchj6yaw" path="res://cover_art/mhw.webp" id="12_8qgke"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cpigwqlll0kbf" path="res://cover_art/mhpir.jpg" id="9_v7fae"]
|
[ext_resource type="Texture2D" uid="uid://brovl1cel1uiw" path="res://cover_art/mh2.jpg" id="13_dypyq"]
|
||||||
[ext_resource type="Texture2D" uid="uid://dkhygfyylbjov" path="res://cover_art/mh_kart2.jpg" id="10_1woe1"]
|
[ext_resource type="Texture2D" uid="uid://ix132vewff0h" path="res://cover_art/mh3.jpg" id="14_tc2rn"]
|
||||||
[ext_resource type="Texture2D" uid="uid://l8groudaf385" path="res://cover_art/mh_kart3.webp" id="11_7me0v"]
|
[ext_resource type="Texture2D" uid="uid://k8i84cvnuun" path="res://cover_art/mhx.jpg" id="15_gxg0f"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bmybnhi2i2ep" path="res://cover_art/mhdir.jpg" id="11_fweyu"]
|
[ext_resource type="Texture2D" uid="uid://bst48atkwn7r1" path="res://cover_art/mhrem.png" id="16_dtmhv"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cjp0ilsodyu4j" path="res://cover_art/mh_kart4.jpg" id="12_hv57k"]
|
[ext_resource type="Texture2D" uid="uid://l37kev18676o" path="res://cover_art/mhwant.jpg" id="17_pcn4f"]
|
||||||
[ext_resource type="Texture2D" uid="uid://by4wug5r7311q" path="res://cover_art/schatzjaeger_2.jpg" id="14_tnyyh"]
|
[ext_resource type="Texture2D" uid="uid://cpigwqlll0kbf" path="res://cover_art/mhpir.jpg" id="18_w72rq"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bkn3cdrm1fj8b" path="res://cover_art/schatzjaeger_3.jpg" id="15_kbsip"]
|
[ext_resource type="Texture2D" uid="uid://chcjw51coc53r" path="res://cover_art/mhinv.jpg" id="19_31858"]
|
||||||
[ext_resource type="Texture2D" uid="uid://8vn1dpq37mve" path="res://cover_art/atlantis.webp" id="16_xvpbi"]
|
[ext_resource type="Texture2D" uid="uid://bmybnhi2i2ep" path="res://cover_art/mhdir.jpg" id="20_b2doc"]
|
||||||
|
|
||||||
[node name="main" type="ScrollContainer"]
|
[node name="main" type="ScrollContainer"]
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
@@ -29,8 +29,8 @@ offset_right = 20.0
|
|||||||
offset_bottom = 154.0
|
offset_bottom = 154.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
theme = ExtResource("1_4qyey")
|
theme = ExtResource("1_24af1")
|
||||||
script = ExtResource("2_j1xqk")
|
script = ExtResource("2_3ufyn")
|
||||||
|
|
||||||
[node name="margins" type="MarginContainer" parent="."]
|
[node name="margins" type="MarginContainer" parent="."]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
@@ -55,7 +55,7 @@ layout_mode = 2
|
|||||||
[node name="Schatzjaeger1" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
[node name="Schatzjaeger1" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
icon = ExtResource("2_f5uhf")
|
icon = ExtResource("3_dq726")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -63,7 +63,7 @@ expand_icon = true
|
|||||||
[node name="Schatzjaeger2" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
[node name="Schatzjaeger2" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
icon = ExtResource("14_tnyyh")
|
icon = ExtResource("4_qurcc")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -71,7 +71,7 @@ expand_icon = true
|
|||||||
[node name="Schatzjaeger3" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
[node name="Schatzjaeger3" type="Button" parent="margins/VBoxContainer/JNR/JNR"]
|
||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
icon = ExtResource("15_kbsip")
|
icon = ExtResource("5_wceoy")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -80,7 +80,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("16_xvpbi")
|
icon = ExtResource("6_mwmag")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -100,7 +100,7 @@ layout_mode = 2
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("9_b3ixn")
|
icon = ExtResource("7_kndjp")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -109,7 +109,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("10_1woe1")
|
icon = ExtResource("8_r2mlu")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -118,7 +118,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("11_7me0v")
|
icon = ExtResource("9_yfa8e")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -127,7 +127,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("12_hv57k")
|
icon = ExtResource("10_s4ouh")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -147,7 +147,7 @@ layout_mode = 2
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("2_epsv5")
|
icon = ExtResource("11_0icjw")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -156,7 +156,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("3_wgtv5")
|
icon = ExtResource("12_8qgke")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -165,7 +165,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("4_fb5aq")
|
icon = ExtResource("13_dypyq")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -174,7 +174,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("5_q44ta")
|
icon = ExtResource("14_tc2rn")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -183,7 +183,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("6_b76vr")
|
icon = ExtResource("15_gxg0f")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -192,7 +192,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("7_ios37")
|
icon = ExtResource("16_dtmhv")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -201,7 +201,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("8_yb215")
|
icon = ExtResource("17_pcn4f")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -210,7 +210,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("9_v7fae")
|
icon = ExtResource("18_w72rq")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -219,7 +219,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("8_1fm4r")
|
icon = ExtResource("19_31858")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
@@ -228,7 +228,7 @@ expand_icon = true
|
|||||||
custom_minimum_size = Vector2(200, 256)
|
custom_minimum_size = Vector2(200, 256)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
disabled = true
|
disabled = true
|
||||||
icon = ExtResource("11_fweyu")
|
icon = ExtResource("20_b2doc")
|
||||||
flat = true
|
flat = true
|
||||||
icon_alignment = 1
|
icon_alignment = 1
|
||||||
expand_icon = true
|
expand_icon = true
|
||||||
|
|||||||
@@ -48,5 +48,4 @@ config/icon="res://icon.png"
|
|||||||
|
|
||||||
[rendering]
|
[rendering]
|
||||||
|
|
||||||
renderer/rendering_method="gl_compatibility"
|
|
||||||
renderer/rendering_method.mobile="gl_compatibility"
|
renderer/rendering_method.mobile="gl_compatibility"
|
||||||
|
|||||||
105
godot/starforce/starforce.gdshader
Normal file
105
godot/starforce/starforce.gdshader
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
shader_type spatial;
|
||||||
|
render_mode skip_vertex_transform;
|
||||||
|
|
||||||
|
uniform vec4 color: source_color;
|
||||||
|
|
||||||
|
uniform float diffuse;
|
||||||
|
uniform float diffuse_envelope;
|
||||||
|
uniform float specular;
|
||||||
|
uniform float specular_envelope;
|
||||||
|
uniform float luminosity;
|
||||||
|
uniform float luminosity_envelope;
|
||||||
|
uniform float reflectivity;
|
||||||
|
uniform float reflectivity_envelope;
|
||||||
|
uniform float translucency;
|
||||||
|
uniform float translucency_envelope;
|
||||||
|
uniform float transparency;
|
||||||
|
uniform float transparency_envelope;
|
||||||
|
|
||||||
|
uniform sampler2D tex_color: source_color;
|
||||||
|
uniform int tex_color_axis;
|
||||||
|
uniform int tex_color_projection;
|
||||||
|
uniform mat4 tex_color_projection_transform;
|
||||||
|
uniform vec3 tex_color_projection_falloff;
|
||||||
|
uniform int tex_color_projection_falloff_type;
|
||||||
|
uniform bool tex_color_projection_world_coords;
|
||||||
|
|
||||||
|
uniform sampler2D tex_diffuse: source_color;
|
||||||
|
uniform int tex_diffuse_axis;
|
||||||
|
uniform int tex_diffuse_projection;
|
||||||
|
uniform mat4 tex_diffuse_projection_transform;
|
||||||
|
uniform vec3 tex_diffuse_projection_falloff;
|
||||||
|
uniform int tex_diffuse_projection_falloff_type;
|
||||||
|
uniform bool tex_diffuse_projection_world_coords;
|
||||||
|
|
||||||
|
varying vec3 position;
|
||||||
|
varying vec3 normal;
|
||||||
|
|
||||||
|
vec3 project(
|
||||||
|
sampler2D tex,
|
||||||
|
int mode,
|
||||||
|
mat4 transform,
|
||||||
|
vec3 falloff,
|
||||||
|
int falloff_type,
|
||||||
|
bool world_coords,
|
||||||
|
vec2 uv,
|
||||||
|
) {
|
||||||
|
switch (mode) {
|
||||||
|
case 5: // UV
|
||||||
|
return texture(tex, uv).rgb;
|
||||||
|
case 4: // Front Projection
|
||||||
|
return vec3(0.0, 1.0, 0.0);
|
||||||
|
case 3:
|
||||||
|
vec3 p = (transform * vec4(position, 1.0)).xyz / 10.0;
|
||||||
|
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));
|
||||||
|
return texture(tex, uv2).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 / 10.0).rgb;
|
||||||
|
default:
|
||||||
|
return vec3(0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
position = VERTEX;
|
||||||
|
VERTEX = (MODELVIEW_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||||
|
NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
vec3 rot = vec3(PI / 4.0, PI / -2.0, PI / -4.0);
|
||||||
|
mat3 x = mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, cos(rot.x), -sin(rot.x)), vec3(0.0, sin(rot.x), cos(rot.x)));
|
||||||
|
mat3 y = mat3(vec3(cos(rot.y), 0.0, sin(rot.y)), vec3(0.0, 1.0, 0.0), vec3(-sin(rot.y), 0.0, cos(rot.y)));
|
||||||
|
mat3 z = mat3(vec3(cos(rot.z), -sin(rot.z), 0.0), vec3(sin(rot.z), cos(rot.z), 0.0), vec3(0.0, 0.0, 1.0));
|
||||||
|
mat3 mat = x * y * z;
|
||||||
|
|
||||||
|
normal = (INV_VIEW_MATRIX * vec4(NORMAL, 0.0)).xyz;
|
||||||
|
|
||||||
|
ALBEDO = project(
|
||||||
|
tex_color,
|
||||||
|
tex_color_projection,
|
||||||
|
tex_color_projection_transform,
|
||||||
|
tex_color_projection_falloff,
|
||||||
|
tex_color_projection_falloff_type,
|
||||||
|
tex_color_projection_world_coords,
|
||||||
|
UV2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void light() {
|
||||||
|
DIFFUSE_LIGHT =project(
|
||||||
|
tex_diffuse,
|
||||||
|
tex_diffuse_projection,
|
||||||
|
tex_diffuse_projection_transform,
|
||||||
|
tex_diffuse_projection_falloff,
|
||||||
|
tex_diffuse_projection_falloff_type,
|
||||||
|
tex_diffuse_projection_world_coords,
|
||||||
|
UV
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ script/source = "@tool
|
|||||||
extends Node3D
|
extends Node3D
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
var scene = load(\"sar://D:/Moorhuhnkart/3dobjects_tracks/track07_ufo/boden.lwo\")
|
var scene = load(\"sar://D:/Moorhuhnkart/3dobjects_tracks/track07_ufo/waende.lwo\").instantiate()
|
||||||
add_child(scene.instantiate())
|
add_child(scene)
|
||||||
"
|
"
|
||||||
|
|
||||||
[node name="test" type="Node3D"]
|
[node name="test" type="Node3D"]
|
||||||
|
|||||||
1
rust/.gitignore
vendored
1
rust/.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
/target
|
/target
|
||||||
.idea
|
.idea
|
||||||
|
.cargo
|
||||||
mhjnr.iml
|
mhjnr.iml
|
||||||
|
|||||||
@@ -8,11 +8,10 @@ pub fn collect_clip(target: &mut HashMap<u32, Gd<Image>>, clip: ImageClip) {
|
|||||||
for img in clip.attributes.iter() {
|
for img in clip.attributes.iter() {
|
||||||
match img {
|
match img {
|
||||||
ImageClipSubChunk::StillImage(still) => {
|
ImageClipSubChunk::StillImage(still) => {
|
||||||
let path = format!(
|
let path = format!("sar://{}", still.name.replace('\\', "/").replace(':', ":/"));
|
||||||
"sar://{}",
|
let mut image: Gd<Image> = load(path);
|
||||||
still.name.to_string().replace('\\', "/").replace(':', ":/")
|
image.set_name(still.name.clone().into());
|
||||||
);
|
target.insert(clip.index, image);
|
||||||
target.insert(clip.index, load(path));
|
|
||||||
}
|
}
|
||||||
x => {
|
x => {
|
||||||
godot_error!("TODO: Clip chunk {:?}", x)
|
godot_error!("TODO: Clip chunk {:?}", x)
|
||||||
|
|||||||
92
rust/mhgd/src/lwo/intermediate_layer.rs
Normal file
92
rust/mhgd/src/lwo/intermediate_layer.rs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
use crate::lwo::material::MaterialUvInfo;
|
||||||
|
use crate::lwo::surface_info::SurfaceInfo;
|
||||||
|
use godot::builtin::{Array, Dictionary, Vector2, Vector3};
|
||||||
|
use godot::engine::mesh::{ArrayFormat, PrimitiveType};
|
||||||
|
use godot::engine::{ArrayMesh, SurfaceTool};
|
||||||
|
use godot::obj::{Gd, Share};
|
||||||
|
use itertools::Itertools;
|
||||||
|
use lightwave_3d::lwo2::tags::polygon_list::PolygonList;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub type SurfaceMapping<T> = HashMap<i32, HashMap<i32, T>>;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct IntermediateLayer {
|
||||||
|
pub name: String,
|
||||||
|
pub pivot: Vector3,
|
||||||
|
pub parent: Option<u16>,
|
||||||
|
pub id: u16,
|
||||||
|
pub points: Vec<Vector3>,
|
||||||
|
pub uv_mappings: Vec<(String, SurfaceMapping<Vector2>)>,
|
||||||
|
pub weight_mappings: SurfaceMapping<f32>,
|
||||||
|
pub polygons: Vec<PolygonList>,
|
||||||
|
pub material_mappings: HashMap<i32, u16>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntermediateLayer {
|
||||||
|
pub fn commit(mut self, materials: &HashMap<u16, MaterialUvInfo>) -> Gd<ArrayMesh> {
|
||||||
|
let mut mesh = ArrayMesh::new();
|
||||||
|
mesh.set_name(self.name.clone().into());
|
||||||
|
let mut surface_material_ids = Vec::<u16>::new();
|
||||||
|
|
||||||
|
self.uv_mappings.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
|
||||||
|
for material_id in self.material_mappings.values().unique() {
|
||||||
|
let material = &materials[material_id];
|
||||||
|
let surface_info = SurfaceInfo::collect_from_layer(&self, material);
|
||||||
|
|
||||||
|
if !surface_info.is_empty() {
|
||||||
|
mesh.add_surface_from_arrays(
|
||||||
|
PrimitiveType::PRIMITIVE_TRIANGLES,
|
||||||
|
surface_info.commit_to_arrays(),
|
||||||
|
Array::new(),
|
||||||
|
Dictionary::new(),
|
||||||
|
ArrayFormat::ARRAY_FORMAT_NORMAL,
|
||||||
|
);
|
||||||
|
surface_material_ids.push(*material_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut final_mesh = post_process_mesh(
|
||||||
|
mesh,
|
||||||
|
materials,
|
||||||
|
surface_material_ids,
|
||||||
|
&self.material_mappings,
|
||||||
|
);
|
||||||
|
final_mesh.set_name(self.name.into());
|
||||||
|
final_mesh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn post_process_mesh(
|
||||||
|
mesh: Gd<ArrayMesh>,
|
||||||
|
materials: &HashMap<u16, MaterialUvInfo>,
|
||||||
|
material_ids: Vec<u16>,
|
||||||
|
material_mappings: &HashMap<i32, u16>,
|
||||||
|
) -> Gd<ArrayMesh> {
|
||||||
|
let mut out_mesh = ArrayMesh::new();
|
||||||
|
|
||||||
|
debug_assert_eq!(mesh.get_surface_count() as usize, material_ids.len());
|
||||||
|
|
||||||
|
for (surface_idx, surface_id) in material_ids.into_iter().enumerate() {
|
||||||
|
let mut tool = SurfaceTool::new();
|
||||||
|
|
||||||
|
tool.create_from(mesh.share().upcast(), surface_idx as i64);
|
||||||
|
tool.generate_normals(false);
|
||||||
|
tool.generate_tangents();
|
||||||
|
|
||||||
|
out_mesh.add_surface_from_arrays(
|
||||||
|
PrimitiveType::PRIMITIVE_TRIANGLES,
|
||||||
|
tool.commit_to_arrays(),
|
||||||
|
Array::new(),
|
||||||
|
Dictionary::new(),
|
||||||
|
ArrayFormat::ARRAY_FORMAT_NORMAL,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(mat) = materials.get(&material_mappings[&(surface_id as i32)]) {
|
||||||
|
out_mesh.surface_set_material(surface_idx as i64, mat.material.share().upcast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out_mesh
|
||||||
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
use godot::builtin::{
|
use godot::builtin::{Basis, Color, EulerOrder, ToVariant, Transform3D, Variant, Vector3};
|
||||||
Basis, Color, EulerOrder, Quaternion, ToVariant, Transform3D, Variant, Vector3,
|
|
||||||
};
|
|
||||||
use godot::engine::{load, Image, ImageTexture, ShaderMaterial};
|
use godot::engine::{load, Image, ImageTexture, ShaderMaterial};
|
||||||
use godot::log::{godot_error, godot_print};
|
use godot::log::{godot_error, godot_print};
|
||||||
use godot::obj::{Gd, Share};
|
use godot::obj::{Gd, Share};
|
||||||
@@ -17,20 +15,23 @@ use lightwave_3d::lwo2::sub_tags::surface_parameters::SurfaceParameterSubChunk;
|
|||||||
use lightwave_3d::lwo2::tags::surface_definition::SurfaceDefinition;
|
use lightwave_3d::lwo2::tags::surface_definition::SurfaceDefinition;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct MaterialUvInfo {
|
pub struct MaterialUvInfo {
|
||||||
pub diffuse_channel: Option<String>,
|
pub diffuse_channel: Option<String>,
|
||||||
pub color_channel: Option<String>,
|
pub color_channel: Option<String>,
|
||||||
pub material: Gd<ShaderMaterial>,
|
pub material: Gd<ShaderMaterial>,
|
||||||
|
pub id: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MaterialUvInfo {
|
impl MaterialUvInfo {
|
||||||
pub fn collect(surface: SurfaceDefinition, images: &HashMap<u32, Gd<Image>>) -> Self {
|
pub fn collect(surface: SurfaceDefinition, images: &HashMap<u32, Gd<Image>>, id: u16) -> Self {
|
||||||
let mut m = MaterialUvInfo {
|
let mut m = MaterialUvInfo {
|
||||||
diffuse_channel: None,
|
diffuse_channel: None,
|
||||||
color_channel: None,
|
color_channel: None,
|
||||||
material: ShaderMaterial::new(),
|
material: ShaderMaterial::new(),
|
||||||
|
id,
|
||||||
};
|
};
|
||||||
m.material.set_name(surface.name.to_string().into());
|
m.material.set_name(surface.name.into());
|
||||||
m.material
|
m.material
|
||||||
.set_shader(load("res://starforce/starforce.gdshader"));
|
.set_shader(load("res://starforce/starforce.gdshader"));
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ impl MaterialUvInfo {
|
|||||||
let mut texture = ImageTexture::new();
|
let mut texture = ImageTexture::new();
|
||||||
let mut chan = TextureChannel::Color;
|
let mut chan = TextureChannel::Color;
|
||||||
let mut uv_channel = None;
|
let mut uv_channel = None;
|
||||||
|
let mut major_axis = 0;
|
||||||
let mut projection_mode = ProjectionMode::UV;
|
let mut projection_mode = ProjectionMode::UV;
|
||||||
let mut mapping_info = Vec::<(&str, Variant)>::new();
|
let mut mapping_info = Vec::<(&str, Variant)>::new();
|
||||||
for attr in header.data.block_attributes {
|
for attr in header.data.block_attributes {
|
||||||
@@ -66,6 +68,7 @@ impl MaterialUvInfo {
|
|||||||
match attr {
|
match attr {
|
||||||
SurfaceBlockImageTextureSubChunk::ImageMap(r) => {
|
SurfaceBlockImageTextureSubChunk::ImageMap(r) => {
|
||||||
if let Some(i) = images.get(&r.texture_image) {
|
if let Some(i) = images.get(&r.texture_image) {
|
||||||
|
godot_print!("{}", i.get_name());
|
||||||
texture.set_image(i.share());
|
texture.set_image(i.share());
|
||||||
} else {
|
} else {
|
||||||
godot_error!("Missing texture {:?}", r);
|
godot_error!("Missing texture {:?}", r);
|
||||||
@@ -75,7 +78,7 @@ impl MaterialUvInfo {
|
|||||||
projection_mode = projection.data;
|
projection_mode = projection.data;
|
||||||
}
|
}
|
||||||
SurfaceBlockImageTextureSubChunk::UvVertexMap(map) => {
|
SurfaceBlockImageTextureSubChunk::UvVertexMap(map) => {
|
||||||
uv_channel = Some(map.txuv_map_name.to_string());
|
uv_channel = Some(map.txuv_map_name.clone());
|
||||||
}
|
}
|
||||||
SurfaceBlockImageTextureSubChunk::TextureMapping(mapping) => {
|
SurfaceBlockImageTextureSubChunk::TextureMapping(mapping) => {
|
||||||
let mut pos = Vector3::default();
|
let mut pos = Vector3::default();
|
||||||
@@ -85,33 +88,33 @@ impl MaterialUvInfo {
|
|||||||
match mapping_param {
|
match mapping_param {
|
||||||
TextureMappingSubChunk::Center(it) => {
|
TextureMappingSubChunk::Center(it) => {
|
||||||
pos = Vector3 {
|
pos = Vector3 {
|
||||||
x: it.base_color[0],
|
z: it.base_color[0],
|
||||||
y: it.base_color[1],
|
y: it.base_color[1],
|
||||||
z: it.base_color[2],
|
x: it.base_color[2],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
TextureMappingSubChunk::Rotation(it) => {
|
TextureMappingSubChunk::Rotation(it) => {
|
||||||
rot = Vector3 {
|
rot = Vector3 {
|
||||||
x: it.base_color[0],
|
z: it.base_color[0],
|
||||||
y: it.base_color[1],
|
y: it.base_color[1],
|
||||||
z: it.base_color[2],
|
x: it.base_color[2],
|
||||||
}
|
}
|
||||||
.normalized();
|
.normalized();
|
||||||
}
|
}
|
||||||
TextureMappingSubChunk::Size(it) => {
|
TextureMappingSubChunk::Size(it) => {
|
||||||
size = Vector3 {
|
size = Vector3 {
|
||||||
x: it.base_color[0],
|
z: it.base_color[0],
|
||||||
y: it.base_color[1],
|
y: it.base_color[1],
|
||||||
z: it.base_color[2],
|
x: it.base_color[2],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
TextureMappingSubChunk::Falloff(it) => {
|
TextureMappingSubChunk::Falloff(it) => {
|
||||||
mapping_info.push((
|
mapping_info.push((
|
||||||
"falloff",
|
"falloff",
|
||||||
Vector3 {
|
Vector3 {
|
||||||
x: it.vector[0],
|
z: it.vector[0],
|
||||||
y: it.vector[1],
|
y: it.vector[1],
|
||||||
z: it.vector[2],
|
x: it.vector[2],
|
||||||
}
|
}
|
||||||
.to_variant(),
|
.to_variant(),
|
||||||
));
|
));
|
||||||
@@ -138,10 +141,8 @@ impl MaterialUvInfo {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
TextureMappingSubChunk::ReferenceObject(it) => {
|
TextureMappingSubChunk::ReferenceObject(it) => {
|
||||||
if !matches!(
|
if !matches!(it.object_name.as_str(), "" | "(none)")
|
||||||
it.object_name.to_string().as_str(),
|
{
|
||||||
"" | "(none)"
|
|
||||||
) {
|
|
||||||
godot_error!("Reference object '{}': not supported for texture mapping", it.object_name)
|
godot_error!("Reference object '{}': not supported for texture mapping", it.object_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,15 +152,15 @@ impl MaterialUvInfo {
|
|||||||
mapping_info.push((
|
mapping_info.push((
|
||||||
"transform",
|
"transform",
|
||||||
Transform3D {
|
Transform3D {
|
||||||
basis: Basis::from_euler(EulerOrder::XYZ, rot)
|
basis: Basis::from_euler(EulerOrder::ZYX, rot)
|
||||||
.scaled(size),
|
.scaled(size),
|
||||||
origin: pos,
|
origin: pos,
|
||||||
}
|
}
|
||||||
.to_variant(),
|
.to_variant(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
SurfaceBlockImageTextureSubChunk::MajorAxis(_) => {
|
SurfaceBlockImageTextureSubChunk::MajorAxis(axis) => {
|
||||||
// TODO;
|
major_axis = axis.data.texture_axis;
|
||||||
}
|
}
|
||||||
SurfaceBlockImageTextureSubChunk::ImageWrapOptions(_) => {
|
SurfaceBlockImageTextureSubChunk::ImageWrapOptions(_) => {
|
||||||
// TODO;
|
// TODO;
|
||||||
@@ -181,19 +182,31 @@ impl MaterialUvInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
godot_print!("TX: {:?} @ UV{:?}", chan, uv_channel);
|
/*godot_print!(
|
||||||
let channel_name = match chan {
|
"TX: {:?} ({:?}) @ UV{:?}",
|
||||||
|
chan,
|
||||||
|
projection_mode,
|
||||||
|
uv_channel
|
||||||
|
);*/
|
||||||
|
let channel_name = match &chan {
|
||||||
TextureChannel::Color => "color",
|
TextureChannel::Color => "color",
|
||||||
TextureChannel::Diffuse => "diffuse",
|
TextureChannel::Diffuse => "diffuse",
|
||||||
TextureChannel::Luminosity => "luminosity",
|
x => {
|
||||||
TextureChannel::Specular => "specular",
|
godot_error!("TODO: Texture channel {:?} is not supported", x);
|
||||||
TextureChannel::Glossy => "glossy",
|
"color"
|
||||||
TextureChannel::Reflectivity => "reflectivity",
|
} /*TextureChannel::Luminosity => "luminosity",
|
||||||
TextureChannel::Transparency => "transparency",
|
TextureChannel::Specular => "specular",
|
||||||
TextureChannel::RefractiveIndex => "refractive_index",
|
TextureChannel::Glossy => "glossy",
|
||||||
TextureChannel::Translucency => "translucency",
|
TextureChannel::Reflectivity => "reflectivity",
|
||||||
TextureChannel::Bump => "bump",
|
TextureChannel::Transparency => "transparency",
|
||||||
|
TextureChannel::RefractiveIndex => "refractive_index",
|
||||||
|
TextureChannel::Translucency => "translucency",
|
||||||
|
TextureChannel::Bump => "bump",*/
|
||||||
};
|
};
|
||||||
|
m.material.set_shader_parameter(
|
||||||
|
format!("tex_{}_axis", channel_name).into(),
|
||||||
|
major_axis.to_variant(),
|
||||||
|
);
|
||||||
m.material.set_shader_parameter(
|
m.material.set_shader_parameter(
|
||||||
format!("tex_{}_projection", channel_name).into(),
|
format!("tex_{}_projection", channel_name).into(),
|
||||||
match projection_mode {
|
match projection_mode {
|
||||||
|
|||||||
@@ -6,10 +6,12 @@ use godot::obj::Gd;
|
|||||||
use lightwave_3d::LightWaveObject;
|
use lightwave_3d::LightWaveObject;
|
||||||
|
|
||||||
pub(crate) mod clips;
|
pub(crate) mod clips;
|
||||||
|
pub(crate) mod intermediate_layer;
|
||||||
pub(crate) mod mapping;
|
pub(crate) mod mapping;
|
||||||
pub(crate) mod material;
|
pub(crate) mod material;
|
||||||
pub(crate) mod object;
|
pub(crate) mod object;
|
||||||
pub(crate) mod surface;
|
pub(crate) mod surface_info;
|
||||||
|
pub(crate) mod unique_vertex;
|
||||||
|
|
||||||
#[derive(GodotClass)]
|
#[derive(GodotClass)]
|
||||||
#[class(init)]
|
#[class(init)]
|
||||||
|
|||||||
@@ -1,52 +1,59 @@
|
|||||||
use crate::lwo::clips::collect_clip;
|
use crate::lwo::clips::collect_clip;
|
||||||
|
use crate::lwo::intermediate_layer::IntermediateLayer;
|
||||||
use crate::lwo::mapping::{collect_discontinuous_mappings, collect_mappings};
|
use crate::lwo::mapping::{collect_discontinuous_mappings, collect_mappings};
|
||||||
use crate::lwo::material::MaterialUvInfo;
|
use crate::lwo::material::MaterialUvInfo;
|
||||||
use crate::lwo::surface::IntermediateLayer;
|
|
||||||
use godot::builtin::{Vector2, Vector3};
|
use godot::builtin::{Vector2, Vector3};
|
||||||
use godot::engine::node::InternalMode;
|
use godot::engine::node::InternalMode;
|
||||||
use godot::engine::{Image, MeshInstance3D, Node3D, PackedScene};
|
use godot::engine::{Image, MeshInstance3D, Node3D, PackedScene};
|
||||||
use godot::log::{godot_error, godot_print, godot_warn};
|
use godot::log::{godot_error, godot_print, godot_warn};
|
||||||
use godot::obj::{Gd, Share};
|
use godot::obj::{Gd, Share};
|
||||||
|
use itertools::Itertools;
|
||||||
use lightwave_3d::lwo2::tags::Tag;
|
use lightwave_3d::lwo2::tags::Tag;
|
||||||
use lightwave_3d::LightWaveObject;
|
use lightwave_3d::LightWaveObject;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
||||||
let mut materials = vec![];
|
let mut surfaces = HashMap::<u16, MaterialUvInfo>::new();
|
||||||
let mut images = HashMap::<u32, Gd<Image>>::new();
|
let mut images = HashMap::<u32, Gd<Image>>::new();
|
||||||
let mut layers = vec![];
|
let mut layers = vec![];
|
||||||
|
let mut tag_strings = vec![];
|
||||||
|
|
||||||
for tag in lightwave.data {
|
for tag in lightwave.data {
|
||||||
match tag {
|
match tag {
|
||||||
|
Tag::TagStrings(it) => {
|
||||||
|
tag_strings = it.data.tag_strings.into_iter().collect();
|
||||||
|
godot_print!("{:?}", tag_strings);
|
||||||
|
}
|
||||||
Tag::Layer(layer_tag) => {
|
Tag::Layer(layer_tag) => {
|
||||||
layers.push(IntermediateLayer {
|
layers.push(IntermediateLayer {
|
||||||
name: layer_tag.name.to_string(),
|
name: layer_tag.name.clone(),
|
||||||
parent: layer_tag.parent,
|
parent: layer_tag.parent,
|
||||||
id: layer_tag.number,
|
id: layer_tag.number,
|
||||||
pivot: Vector3 {
|
pivot: Vector3 {
|
||||||
x: layer_tag.pivot[0],
|
z: layer_tag.pivot[0],
|
||||||
y: layer_tag.pivot[1],
|
y: layer_tag.pivot[1],
|
||||||
z: layer_tag.pivot[2],
|
x: layer_tag.pivot[2],
|
||||||
},
|
},
|
||||||
..IntermediateLayer::default()
|
..IntermediateLayer::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Tag::PointList(points_chunk) => {
|
Tag::PointList(points_chunk) => {
|
||||||
|
debug_assert_eq!(layers.last().unwrap().points.len(), 0);
|
||||||
layers.last_mut().unwrap().points = points_chunk
|
layers.last_mut().unwrap().points = points_chunk
|
||||||
.data
|
.data
|
||||||
.point_location
|
.point_location
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|p| Vector3 {
|
.map(|p| Vector3 {
|
||||||
x: p[0],
|
z: p[0],
|
||||||
y: p[1],
|
y: p[1],
|
||||||
z: p[2],
|
x: p[2],
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
Tag::DiscontinuousVertexMapping(vmad) => match &vmad.kind {
|
Tag::DiscontinuousVertexMapping(vmad) => match &vmad.kind {
|
||||||
b"TXUV" => {
|
b"TXUV" => {
|
||||||
debug_assert!(vmad.data.mappings[0].values.len() == 2);
|
debug_assert!(vmad.data.mappings[0].values.len() == 2);
|
||||||
let name = vmad.name.to_string();
|
let name = vmad.name.clone();
|
||||||
|
|
||||||
let layer = layers.last_mut().unwrap();
|
let layer = layers.last_mut().unwrap();
|
||||||
let map = if let Some(mappings) =
|
let map = if let Some(mappings) =
|
||||||
@@ -76,7 +83,7 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
|||||||
Tag::VertexMapping(vmap) => match &vmap.kind {
|
Tag::VertexMapping(vmap) => match &vmap.kind {
|
||||||
b"TXUV" => {
|
b"TXUV" => {
|
||||||
debug_assert!(vmap.data.mapping[0].value.len() == 2);
|
debug_assert!(vmap.data.mapping[0].value.len() == 2);
|
||||||
let name = vmap.name.to_string();
|
let name = vmap.name.clone();
|
||||||
|
|
||||||
let layer = layers.last_mut().unwrap();
|
let layer = layers.last_mut().unwrap();
|
||||||
let map = if let Some(mappings) =
|
let map = if let Some(mappings) =
|
||||||
@@ -109,7 +116,7 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
|||||||
layers
|
layers
|
||||||
.last_mut()
|
.last_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.surfaces
|
.material_mappings
|
||||||
.insert(surf.poly as i32, surf.tag);
|
.insert(surf.poly as i32, surf.tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,14 +127,24 @@ pub fn lightwave_to_gd(lightwave: LightWaveObject) -> Gd<PackedScene> {
|
|||||||
},
|
},
|
||||||
Tag::PolygonList(polygon_lists) => match &polygon_lists.kind {
|
Tag::PolygonList(polygon_lists) => match &polygon_lists.kind {
|
||||||
b"FACE" => {
|
b"FACE" => {
|
||||||
|
debug_assert_eq!(layers.last().unwrap().polygons.len(), 0);
|
||||||
layers.last_mut().unwrap().polygons = polygon_lists.data.polygons;
|
layers.last_mut().unwrap().polygons = polygon_lists.data.polygons;
|
||||||
}
|
}
|
||||||
x => godot_warn!("{}", String::from_utf8(x.to_vec()).unwrap()),
|
x => godot_warn!("{}", String::from_utf8(x.to_vec()).unwrap()),
|
||||||
},
|
},
|
||||||
Tag::ImageClip(clip) => collect_clip(&mut images, clip.data),
|
Tag::ImageClip(clip) => collect_clip(&mut images, clip.data),
|
||||||
Tag::SurfaceDefinition(surf) => {
|
Tag::SurfaceDefinition(surf) => {
|
||||||
godot_print!("Def: '{}' -> '{}'", surf.source, surf.name);
|
let surf_name = surf.name.clone();
|
||||||
materials.push(MaterialUvInfo::collect(surf.data, &images));
|
let (tag_index, _) = tag_strings
|
||||||
|
.iter()
|
||||||
|
.find_position(|name| name == &&surf_name)
|
||||||
|
.expect("Invalid File");
|
||||||
|
godot_print!("'{}': {}", surf_name, tag_index);
|
||||||
|
|
||||||
|
surfaces.insert(
|
||||||
|
tag_index as u16,
|
||||||
|
MaterialUvInfo::collect(surf.data, &images, tag_index as u16),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Tag::BoundingBox(_) => (),
|
Tag::BoundingBox(_) => (),
|
||||||
x => {
|
x => {
|
||||||
@@ -136,12 +153,25 @@ 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();
|
let mut root_node = Node3D::new_alloc();
|
||||||
|
|
||||||
for layer in layers {
|
for layer in layers {
|
||||||
let mut instance = MeshInstance3D::new_alloc();
|
let mut instance = MeshInstance3D::new_alloc();
|
||||||
instance.set_name(layer.name.clone().into());
|
instance.set_name(layer.name.clone().into());
|
||||||
instance.set_mesh(layer.commit(&mut materials).upcast());
|
instance.set_mesh(layer.commit(&surfaces).upcast());
|
||||||
|
|
||||||
root_node.add_child(
|
root_node.add_child(
|
||||||
instance.share().upcast(),
|
instance.share().upcast(),
|
||||||
|
|||||||
@@ -1,193 +0,0 @@
|
|||||||
use crate::lwo::mapping::find_mapping;
|
|
||||||
use crate::lwo::material::MaterialUvInfo;
|
|
||||||
use godot::builtin::{
|
|
||||||
Array, Dictionary, PackedFloat32Array, PackedInt32Array, PackedVector2Array,
|
|
||||||
PackedVector3Array, ToVariant, VariantArray, Vector2, Vector3,
|
|
||||||
};
|
|
||||||
use godot::engine::mesh::{ArrayFormat, ArrayType, PrimitiveType};
|
|
||||||
use godot::engine::{ArrayMesh, SurfaceTool};
|
|
||||||
use godot::obj::{EngineEnum, Gd, Share};
|
|
||||||
use godot::prelude::godot_error;
|
|
||||||
use itertools::Itertools;
|
|
||||||
use lightwave_3d::lwo2::tags::polygon_list::PolygonList;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Hash, Eq, PartialEq)]
|
|
||||||
struct UniqueVertex {
|
|
||||||
vert: i32,
|
|
||||||
uv: Vec<Option<[[u8; 4]; 2]>>,
|
|
||||||
weight: [u8; 4],
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type SurfaceMapping<T> = HashMap<i32, HashMap<i32, T>>;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct IntermediateLayer {
|
|
||||||
pub name: String,
|
|
||||||
pub pivot: Vector3,
|
|
||||||
pub parent: Option<u16>,
|
|
||||||
pub id: u16,
|
|
||||||
pub points: Vec<Vector3>,
|
|
||||||
pub uv_mappings: Vec<(String, SurfaceMapping<Vector2>)>,
|
|
||||||
pub weight_mappings: SurfaceMapping<f32>,
|
|
||||||
pub polygons: Vec<PolygonList>,
|
|
||||||
pub surfaces: HashMap<i32, u16>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntermediateLayer {
|
|
||||||
pub fn commit(mut self, materials: &[MaterialUvInfo]) -> Gd<ArrayMesh> {
|
|
||||||
let mut mesh = ArrayMesh::new();
|
|
||||||
mesh.set_name(self.name.clone().into());
|
|
||||||
let mut surface_materials = Vec::<u16>::new();
|
|
||||||
|
|
||||||
self.uv_mappings.sort_by(|a, b| a.0.cmp(&b.0));
|
|
||||||
|
|
||||||
for surface_id in self.surfaces.values().unique() {
|
|
||||||
let material = &materials[*surface_id as usize];
|
|
||||||
let material_uv_names = [
|
|
||||||
material.diffuse_channel.as_ref(),
|
|
||||||
material.color_channel.as_ref(),
|
|
||||||
];
|
|
||||||
let mut material_incomplete = material_uv_names.iter().map(|_| 0).collect_vec();
|
|
||||||
let materials_subset = material_uv_names
|
|
||||||
.iter()
|
|
||||||
.map(|it| it.and_then(|it| self.uv_mappings.iter().find(|(name, _)| name == it)))
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
let mut vertex_map = HashMap::<UniqueVertex, i32>::new();
|
|
||||||
let mut vertices = PackedVector3Array::new();
|
|
||||||
let mut uvs = materials_subset
|
|
||||||
.iter()
|
|
||||||
.map(|it| it.map(|_| PackedVector2Array::new()))
|
|
||||||
.collect_vec();
|
|
||||||
let mut weights = PackedFloat32Array::new();
|
|
||||||
let mut indices = PackedInt32Array::new();
|
|
||||||
|
|
||||||
for (id, poly) in self
|
|
||||||
.polygons
|
|
||||||
.iter_mut()
|
|
||||||
.enumerate()
|
|
||||||
.filter(|(id, _)| self.surfaces.get(&(*id as i32)).unwrap_or(&0) == surface_id)
|
|
||||||
{
|
|
||||||
let fan_v = poly.vert.remove(0) as i32;
|
|
||||||
let fan = poly
|
|
||||||
.vert
|
|
||||||
.windows(2)
|
|
||||||
.flat_map(|w| [w[1] as i32, w[0] as i32, fan_v]);
|
|
||||||
|
|
||||||
for vert in fan {
|
|
||||||
let uv = materials_subset
|
|
||||||
.iter()
|
|
||||||
.map(|it| {
|
|
||||||
it.and_then(|(name, it)| {
|
|
||||||
find_mapping(it, id, vert).map(|it| (name, it))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect_vec();
|
|
||||||
// let weight = find_mapping(weight_mappings, id, vert);
|
|
||||||
|
|
||||||
indices.push(
|
|
||||||
*vertex_map
|
|
||||||
.entry(UniqueVertex {
|
|
||||||
vert,
|
|
||||||
uv: uv
|
|
||||||
.iter()
|
|
||||||
.map(|it| {
|
|
||||||
it.map(|(_, uv)| [uv.x.to_ne_bytes(), uv.y.to_ne_bytes()])
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
weight: (0.0f32).to_ne_bytes(),
|
|
||||||
})
|
|
||||||
.or_insert_with(|| {
|
|
||||||
vertices.push(*self.points.get(vert as usize).unwrap());
|
|
||||||
for (i, uv) in uv.iter().enumerate() {
|
|
||||||
if let Some(uvs) = &mut uvs[i] {
|
|
||||||
uvs.push(uv.map(|(_, it)| it).unwrap_or_else(|| {
|
|
||||||
material_incomplete[i] += 1;
|
|
||||||
Vector2::ZERO
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
weights.push(0.0);
|
|
||||||
vertices.len() as i32 - 1
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut surface = VariantArray::new();
|
|
||||||
surface.resize(ArrayType::ARRAY_MAX.ord() as usize);
|
|
||||||
surface.set(
|
|
||||||
ArrayType::ARRAY_VERTEX.ord() as usize,
|
|
||||||
vertices.to_variant(),
|
|
||||||
);
|
|
||||||
for (i, uv) in uvs.iter().enumerate() {
|
|
||||||
if let Some(uv) = uv {
|
|
||||||
surface.set(
|
|
||||||
match i {
|
|
||||||
0 => ArrayType::ARRAY_TEX_UV,
|
|
||||||
1 => ArrayType::ARRAY_TEX_UV2,
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
.ord() as usize,
|
|
||||||
uv.to_variant(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*TODO: surface.set(
|
|
||||||
ArrayType::ARRAY_WEIGHTS.ord() as usize,
|
|
||||||
weights.to_variant(),
|
|
||||||
);*/
|
|
||||||
surface.set(ArrayType::ARRAY_INDEX.ord() as usize, indices.to_variant());
|
|
||||||
|
|
||||||
for (i, inc) in material_incomplete.into_iter().enumerate() {
|
|
||||||
if inc != 0 {
|
|
||||||
godot_error!(
|
|
||||||
"{}:{}'s UV map '{}' has {} ({}%) incomplete UVs",
|
|
||||||
self.name,
|
|
||||||
surface_id,
|
|
||||||
material_uv_names[i].unwrap(),
|
|
||||||
inc,
|
|
||||||
(inc as f32 / vertices.len() as f32) * 100.0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if vertices.is_empty() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mesh.add_surface_from_arrays(
|
|
||||||
PrimitiveType::PRIMITIVE_TRIANGLES,
|
|
||||||
surface,
|
|
||||||
Array::new(),
|
|
||||||
Dictionary::new(),
|
|
||||||
ArrayFormat::ARRAY_FORMAT_NORMAL,
|
|
||||||
);
|
|
||||||
surface_materials.push(*surface_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut out_mesh = ArrayMesh::new();
|
|
||||||
out_mesh.set_name(self.name.into());
|
|
||||||
for i in 0..mesh.get_surface_count() {
|
|
||||||
let mut tool = SurfaceTool::new();
|
|
||||||
|
|
||||||
tool.create_from(mesh.share().upcast(), i);
|
|
||||||
tool.generate_normals(false);
|
|
||||||
tool.generate_tangents();
|
|
||||||
|
|
||||||
out_mesh.add_surface_from_arrays(
|
|
||||||
PrimitiveType::PRIMITIVE_TRIANGLES,
|
|
||||||
tool.commit_to_arrays(),
|
|
||||||
Array::new(),
|
|
||||||
Dictionary::new(),
|
|
||||||
ArrayFormat::ARRAY_FORMAT_NORMAL,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(mat) = materials.get(self.surfaces[&(i as i32)] as usize) {
|
|
||||||
out_mesh.surface_set_material(i, mat.material.share().upcast())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out_mesh
|
|
||||||
}
|
|
||||||
}
|
|
||||||
144
rust/mhgd/src/lwo/surface_info.rs
Normal file
144
rust/mhgd/src/lwo/surface_info.rs
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
use crate::lwo::intermediate_layer::IntermediateLayer;
|
||||||
|
use crate::lwo::mapping::find_mapping;
|
||||||
|
use crate::lwo::material::MaterialUvInfo;
|
||||||
|
use crate::lwo::unique_vertex::UniqueVertex;
|
||||||
|
use godot::builtin::{
|
||||||
|
PackedFloat32Array, PackedInt32Array, PackedVector2Array, PackedVector3Array, ToVariant,
|
||||||
|
VariantArray, Vector2, Vector3,
|
||||||
|
};
|
||||||
|
use godot::engine::mesh::ArrayType;
|
||||||
|
use godot::log::godot_error;
|
||||||
|
use godot::obj::EngineEnum;
|
||||||
|
use itertools::Itertools;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
fn triangulate(poly: &[u32]) -> Vec<i32> {
|
||||||
|
let mut poly = poly.iter().collect_vec();
|
||||||
|
|
||||||
|
let fan_v = *poly.pop().unwrap() as i32;
|
||||||
|
poly.reverse();
|
||||||
|
poly.windows(2)
|
||||||
|
.flat_map(move |w| [*w[1] as i32, *w[0] as i32, fan_v])
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct SurfaceInfo {
|
||||||
|
vertex_map: HashMap<UniqueVertex, i32>,
|
||||||
|
material_incomplete: Vec<i32>,
|
||||||
|
pub material_id: u16,
|
||||||
|
pub vertices: PackedVector3Array,
|
||||||
|
pub uv_sets: Vec<Option<PackedVector2Array>>,
|
||||||
|
pub weights: PackedFloat32Array,
|
||||||
|
pub indices: PackedInt32Array,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SurfaceInfo {
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.vertices.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn commit_to_arrays(self) -> VariantArray {
|
||||||
|
let mut arrays = VariantArray::new();
|
||||||
|
arrays.resize(ArrayType::ARRAY_MAX.ord() as usize);
|
||||||
|
arrays.set(
|
||||||
|
ArrayType::ARRAY_VERTEX.ord() as usize,
|
||||||
|
self.vertices.to_variant(),
|
||||||
|
);
|
||||||
|
for (i, uv) in self.uv_sets.into_iter().enumerate() {
|
||||||
|
if let Some(uv) = uv {
|
||||||
|
arrays.set(
|
||||||
|
match i {
|
||||||
|
0 => ArrayType::ARRAY_TEX_UV,
|
||||||
|
1 => ArrayType::ARRAY_TEX_UV2,
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
.ord() as usize,
|
||||||
|
uv.to_variant(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*TODO: surface.set(
|
||||||
|
ArrayType::ARRAY_WEIGHTS.ord() as usize,
|
||||||
|
weights.to_variant(),
|
||||||
|
);*/
|
||||||
|
arrays.set(
|
||||||
|
ArrayType::ARRAY_INDEX.ord() as usize,
|
||||||
|
self.indices.to_variant(),
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
for (i, inc) in self.material_incomplete.into_iter().enumerate() {
|
||||||
|
if inc != 0 {
|
||||||
|
godot_error!(
|
||||||
|
"{} ({}%) incomplete UVs",
|
||||||
|
inc,
|
||||||
|
(inc as f32 / self.vertices.len() as f32) * 100.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
arrays
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn collect_from_layer(layer: &IntermediateLayer, material: &MaterialUvInfo) -> Self {
|
||||||
|
let material_uv_names = [
|
||||||
|
material.diffuse_channel.as_ref(),
|
||||||
|
material.color_channel.as_ref(),
|
||||||
|
];
|
||||||
|
|
||||||
|
let materials_subset = material_uv_names
|
||||||
|
.iter()
|
||||||
|
.map(|it| it.and_then(|it| layer.uv_mappings.iter().find(|(name, _)| name == it)))
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
let mut surface_info = SurfaceInfo {
|
||||||
|
uv_sets: materials_subset
|
||||||
|
.iter()
|
||||||
|
.map(|it| it.map(|_| PackedVector2Array::new()))
|
||||||
|
.collect(),
|
||||||
|
material_incomplete: material_uv_names.iter().map(|_| 0).collect_vec(),
|
||||||
|
..SurfaceInfo::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut surface_polygons = layer.polygons.iter().enumerate().filter(|(id, _)| {
|
||||||
|
layer.material_mappings.get(&(*id as i32)).unwrap_or(&0) == &material.id
|
||||||
|
});
|
||||||
|
|
||||||
|
for (id, poly) in surface_polygons {
|
||||||
|
for index in triangulate(&poly.vert) {
|
||||||
|
let uv = materials_subset
|
||||||
|
.iter()
|
||||||
|
.map(|it| it.and_then(|(_, it)| find_mapping(it, id, index)))
|
||||||
|
.collect_vec();
|
||||||
|
// TODO: let weight = find_mapping(weight_mappings, id, vert);
|
||||||
|
let vert = layer.points.get(index as usize).unwrap();
|
||||||
|
|
||||||
|
surface_info.push_index(vert, &uv, 0f32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
surface_info
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_index(&mut self, vert: &Vector3, uvs: &[Option<Vector2>], weight: f32) {
|
||||||
|
let index = *self
|
||||||
|
.vertex_map
|
||||||
|
.entry(UniqueVertex::from_point(vert, uvs, 0f32, self.material_id))
|
||||||
|
.or_insert_with(|| {
|
||||||
|
self.vertices.push(*vert);
|
||||||
|
for (i, uv) in uvs.iter().enumerate() {
|
||||||
|
if let Some(uv_set) = &mut self.uv_sets[i] {
|
||||||
|
uv_set.push(uv.unwrap_or_else(|| {
|
||||||
|
self.material_incomplete[i] += 1;
|
||||||
|
Vector2::ZERO
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.weights.push(weight);
|
||||||
|
self.vertices.len() as i32 - 1
|
||||||
|
});
|
||||||
|
|
||||||
|
self.indices.push(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
32
rust/mhgd/src/lwo/unique_vertex.rs
Normal file
32
rust/mhgd/src/lwo/unique_vertex.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
use godot::builtin::{Vector2, Vector3};
|
||||||
|
|
||||||
|
#[derive(Hash, Eq, PartialEq)]
|
||||||
|
pub struct UniqueVertex {
|
||||||
|
vert: [[u8; 4]; 3],
|
||||||
|
material_id: u16,
|
||||||
|
uv: Vec<Option<[[u8; 4]; 2]>>,
|
||||||
|
weight: [u8; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UniqueVertex {
|
||||||
|
pub fn from_point(
|
||||||
|
vert: &Vector3,
|
||||||
|
uvs: &[Option<Vector2>],
|
||||||
|
weight: f32,
|
||||||
|
material_id: u16,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
vert: [
|
||||||
|
vert.x.to_ne_bytes(),
|
||||||
|
vert.y.to_ne_bytes(),
|
||||||
|
vert.z.to_ne_bytes(),
|
||||||
|
],
|
||||||
|
material_id,
|
||||||
|
uv: uvs
|
||||||
|
.iter()
|
||||||
|
.map(|it| it.map(|uv| [uv.x.to_ne_bytes(), uv.y.to_ne_bytes()]))
|
||||||
|
.collect(),
|
||||||
|
weight: weight.to_ne_bytes(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user