diff --git a/assets/textures/bulkhead.jpg b/assets/textures/bulkhead.jpg new file mode 100644 index 0000000..1eda455 Binary files /dev/null and b/assets/textures/bulkhead.jpg differ diff --git a/assets/textures/bulkhead.jpg.import b/assets/textures/bulkhead.jpg.import new file mode 100644 index 0000000..21ad7d4 --- /dev/null +++ b/assets/textures/bulkhead.jpg.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bvhxix1d6ka2i" +path="res://.godot/imported/bulkhead.jpg-778442090b553bb4d930d2a7bb2227d2.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/bulkhead.jpg" +dest_files=["res://.godot/imported/bulkhead.jpg-778442090b553bb4d930d2a7bb2227d2.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/textures/door.jpg b/assets/textures/door.jpg new file mode 100644 index 0000000..cc4d720 Binary files /dev/null and b/assets/textures/door.jpg differ diff --git a/assets/textures/door.jpg.import b/assets/textures/door.jpg.import new file mode 100644 index 0000000..c59f293 --- /dev/null +++ b/assets/textures/door.jpg.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://3ekppwafyxd1" +path="res://.godot/imported/door.jpg-b8c4b8bf4ee1820b8867f07c9c81a77c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/door.jpg" +dest_files=["res://.godot/imported/door.jpg-b8c4b8bf4ee1820b8867f07c9c81a77c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/textures/door_face.jpg b/assets/textures/door_face.jpg new file mode 100644 index 0000000..271f661 Binary files /dev/null and b/assets/textures/door_face.jpg differ diff --git a/assets/textures/door_face.jpg.import b/assets/textures/door_face.jpg.import new file mode 100644 index 0000000..12725e6 --- /dev/null +++ b/assets/textures/door_face.jpg.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://eg5m5mny4ux4" +path="res://.godot/imported/door_face.jpg-b63d50391bbbef15207e9296b1e81a7c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/door_face.jpg" +dest_files=["res://.godot/imported/door_face.jpg-b63d50391bbbef15207e9296b1e81a7c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/textures/door_src.jpg b/assets/textures/door_src.jpg new file mode 100644 index 0000000..cc4d720 Binary files /dev/null and b/assets/textures/door_src.jpg differ diff --git a/assets/textures/door_src.jpg.import b/assets/textures/door_src.jpg.import new file mode 100644 index 0000000..32bd91e --- /dev/null +++ b/assets/textures/door_src.jpg.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://b4pyrvfdghrrl" +path="res://.godot/imported/door_src.jpg-2b798f391ba5ad155c846627d24b7f25.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/door_src.jpg" +dest_files=["res://.godot/imported/door_src.jpg-2b798f391ba5ad155c846627d24b7f25.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/textures/floor.jpg b/assets/textures/floor.jpg new file mode 100644 index 0000000..ca175f4 Binary files /dev/null and b/assets/textures/floor.jpg differ diff --git a/assets/textures/floor.jpg.import b/assets/textures/floor.jpg.import new file mode 100644 index 0000000..8c3d765 --- /dev/null +++ b/assets/textures/floor.jpg.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://tktukrgw3bot" +path="res://.godot/imported/floor.jpg-1a2c086730eaa37e4b6f8081270af11c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/floor.jpg" +dest_files=["res://.godot/imported/floor.jpg-1a2c086730eaa37e4b6f8081270af11c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/textures/greeble.jpg b/assets/textures/greeble.jpg new file mode 100644 index 0000000..28dd0d4 Binary files /dev/null and b/assets/textures/greeble.jpg differ diff --git a/assets/textures/greeble.jpg.import b/assets/textures/greeble.jpg.import new file mode 100644 index 0000000..6ac21dc --- /dev/null +++ b/assets/textures/greeble.jpg.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ceijjpvl5xo4r" +path="res://.godot/imported/greeble.jpg-55b0e1aa001c0f3b89fdb2c9b1188b95.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/greeble.jpg" +dest_files=["res://.godot/imported/greeble.jpg-55b0e1aa001c0f3b89fdb2c9b1188b95.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/assets/textures/wall.jpg b/assets/textures/wall.jpg new file mode 100644 index 0000000..1dc9f18 Binary files /dev/null and b/assets/textures/wall.jpg differ diff --git a/assets/textures/wall.jpg.import b/assets/textures/wall.jpg.import new file mode 100644 index 0000000..ab7956b --- /dev/null +++ b/assets/textures/wall.jpg.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://duqv3irxdi3v4" +path="res://.godot/imported/wall.jpg-8e8b3ad92a15e41a3c6423a65a989ffb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/wall.jpg" +dest_files=["res://.godot/imported/wall.jpg-8e8b3ad92a15e41a3c6423a65a989ffb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/src/interactables.gd b/src/interactables.gd index 4c8a177..3b4efc7 100644 --- a/src/interactables.gd +++ b/src/interactables.gd @@ -7,6 +7,7 @@ class Door extends StaticBody3D: var height := 3.0 var width := 2.4 var tint := Color(0.95, 0.5, 0.1) + var face_tex: Texture2D = null var base_y := 0.0 var _tw: Tween @@ -18,10 +19,14 @@ class Door extends StaticBody3D: mi.mesh = m mi.position.y = height / 2.0 var mat := StandardMaterial3D.new() - mat.albedo_color = tint - mat.emission_enabled = true - mat.emission = tint - mat.emission_energy_multiplier = 0.3 + if face_tex: + mat.albedo_color = Color.WHITE + mat.albedo_texture = face_tex + else: + mat.albedo_color = tint + mat.emission_enabled = true + mat.emission = tint + mat.emission_energy_multiplier = 0.3 mi.material_override = mat add_child(mi) var col := CollisionShape3D.new() diff --git a/src/main.gd b/src/main.gd index 9cdef24..bed04df 100644 --- a/src/main.gd +++ b/src/main.gd @@ -110,6 +110,50 @@ func mat(col: Color) -> StandardMaterial3D: return _mats[col] +var _texs := {} + + +func seamless_tex(path: String) -> ImageTexture: + # mirror-fold 2x2 so any image tiles without seams + # ponytail: runtime load+fold; bake to imported textures if load time ever matters + if _texs.has(path): + return _texs[path] + var img := Image.load_from_file(ProjectSettings.globalize_path(path)) + img.convert(Image.FORMAT_RGB8) + var w := img.get_width() + var h := img.get_height() + var out := Image.create(w * 2, h * 2, false, Image.FORMAT_RGB8) + var r := Rect2i(0, 0, w, h) + out.blit_rect(img, r, Vector2i(0, 0)) + var fx: Image = img.duplicate() + fx.flip_x() + out.blit_rect(fx, r, Vector2i(w, 0)) + var fy: Image = img.duplicate() + fy.flip_y() + out.blit_rect(fy, r, Vector2i(0, h)) + var fxy: Image = fx.duplicate() + fxy.flip_y() + out.blit_rect(fxy, r, Vector2i(w, h)) + out.generate_mipmaps() + _texs[path] = ImageTexture.create_from_image(out) + return _texs[path] + + +func surface_mat(file: String, tile_m: float, col := Color.WHITE) -> StandardMaterial3D: + var path := "res://assets/textures/" + file + if not FileAccess.file_exists(path): + return struct_mat(Color(0.5, 0.52, 0.58)) # fallback: grid grey-box + var key := "t" + file + str(tile_m) + if not _mats.has(key): + var m := StandardMaterial3D.new() + m.albedo_color = col + m.albedo_texture = seamless_tex(path) + m.uv1_triplanar = true + m.uv1_scale = Vector3.ONE / tile_m + _mats[key] = m + return _mats[key] + + func struct_mat(col: Color) -> StandardMaterial3D: var key := "g" + str(col) if not _mats.has(key): @@ -134,12 +178,21 @@ func glow(col: Color, energy := 0.7) -> StandardMaterial3D: return _mats[key] -func box(pos: Vector3, size: Vector3, col: Color, parent: Node3D = null, grid := false) -> CSGBox3D: +const SURF := {"wall": ["wall.jpg", 3.0], "floor": ["floor.jpg", 2.0], + "bulk": ["bulkhead.jpg", 3.0], "greeble": ["greeble.jpg", 2.2]} + + +func box(pos: Vector3, size: Vector3, col: Color, parent: Node3D = null, grid := false, surf := "") -> CSGBox3D: var b := CSGBox3D.new() b.size = size b.position = pos b.use_collision = true - b.material = struct_mat(col) if grid else mat(col) + if surf: + b.material = surface_mat(SURF[surf][0], SURF[surf][1]) + elif grid: + b.material = struct_mat(col) + else: + b.material = mat(col) (parent if parent else self).add_child(b) return b @@ -157,13 +210,24 @@ func sign3d(text: String, pos: Vector3, rot_y := PI, size := 30, col := Color(0. func divider(z: float) -> void: var c := Color(0.45, 0.46, 0.52) - box(Vector3(-2.6, 2, z), Vector3(2.8, 4, 0.3), c, null, true) - box(Vector3(2.6, 2, z), Vector3(2.8, 4, 0.3), c, null, true) - box(Vector3(0, 3.5, z), Vector3(2.4, 1, 0.3), c, null, true) + box(Vector3(-2.6, 2, z), Vector3(2.8, 4, 0.3), c, null, true, "bulk") + box(Vector3(2.6, 2, z), Vector3(2.8, 4, 0.3), c, null, true, "bulk") + box(Vector3(0, 3.5, z), Vector3(2.4, 1, 0.3), c, null, true, "bulk") + + +func raw_tex(path: String) -> ImageTexture: + if _texs.has(path): + return _texs[path] + var img := Image.load_from_file(ProjectSettings.globalize_path(path)) + img.generate_mipmaps() + _texs[path] = ImageTexture.create_from_image(img) + return _texs[path] func make_door(z: float) -> Node3D: var d := I.Door.new() + if FileAccess.file_exists("res://assets/textures/door_face.jpg"): + d.face_tex = raw_tex("res://assets/textures/door_face.jpg") d.position = Vector3(0, 0, z) add_child(d) return d @@ -199,7 +263,7 @@ func _build_env() -> void: var o := OmniLight3D.new() o.position = Vector3(0, 3.4, z) o.omni_range = 10.0 - o.light_energy = 1.1 + o.light_energy = 1.35 o.light_color = Color(1.0, 0.96, 0.88) add_child(o) for p in [Vector3(8, 6.5, 22), Vector3(6.4, 3.2, 25.8), Vector3(-5.0, 3.0, 24)]: @@ -213,31 +277,31 @@ func _build_env() -> void: func _build_geometry() -> void: var wall := Color(0.5, 0.52, 0.58) # floor - box(Vector3(3, -0.15, 22.5), Vector3(18.6, 0.3, 46), Color(0.62, 0.62, 0.65), null, true) + box(Vector3(3, -0.15, 22.5), Vector3(18.6, 0.3, 46), Color(0.62, 0.62, 0.65), null, true, "floor") # left wall x=-4.15, niche gap z 23.4..24.6 - box(Vector3(-4.15, 2, 11.45), Vector3(0.3, 4, 23.9), wall, null, true) - box(Vector3(-4.15, 2, 33.55), Vector3(0.3, 4, 17.9), wall, null, true) + box(Vector3(-4.15, 2, 11.45), Vector3(0.3, 4, 23.9), wall, null, true, "wall") + box(Vector3(-4.15, 2, 33.55), Vector3(0.3, 4, 17.9), wall, null, true, "wall") # relay niche (behind left wall) + bars - box(Vector3(-5.8, 2, 24), Vector3(0.3, 4, 1.6), wall, null, true) - box(Vector3(-5.0, 2, 23.4), Vector3(1.6, 4, 0.3), wall, null, true) - box(Vector3(-5.0, 2, 24.6), Vector3(1.6, 4, 0.3), wall, null, true) + box(Vector3(-5.8, 2, 24), Vector3(0.3, 4, 1.6), wall, null, true, "greeble") + box(Vector3(-5.0, 2, 23.4), Vector3(1.6, 4, 0.3), wall, null, true, "wall") + box(Vector3(-5.0, 2, 24.6), Vector3(1.6, 4, 0.3), wall, null, true, "wall") box(Vector3(-4.15, 1, 23.8), Vector3(0.1, 2, 0.1), Color(0.15, 0.15, 0.15)) box(Vector3(-4.15, 1, 24.2), Vector3(0.1, 2, 0.1), Color(0.15, 0.15, 0.15)) # right wall x=4.15: gaps for drum bay (z 20..24) and bonus bay (z 25..26.6) - box(Vector3(4.15, 2, 9.75), Vector3(0.3, 4, 20.5), wall, null, true) - box(Vector3(4.15, 2, 24.5), Vector3(0.3, 4, 1.0), wall, null, true) - box(Vector3(4.15, 2, 34.55), Vector3(0.3, 4, 15.9), wall, null, true) + box(Vector3(4.15, 2, 9.75), Vector3(0.3, 4, 20.5), wall, null, true, "wall") + box(Vector3(4.15, 2, 24.5), Vector3(0.3, 4, 1.0), wall, null, true, "wall") + box(Vector3(4.15, 2, 34.55), Vector3(0.3, 4, 15.9), wall, null, true, "wall") # bonus bay shell - box(Vector3(8.65, 2, 25.8), Vector3(0.3, 4, 3.0), wall, null, true) - box(Vector3(6.4, 2, 24.9), Vector3(4.4, 4, 0.3), wall, null, true) - box(Vector3(6.4, 2, 26.7), Vector3(4.4, 4, 0.3), wall, null, true) + box(Vector3(8.65, 2, 25.8), Vector3(0.3, 4, 3.0), wall, null, true, "greeble") + box(Vector3(6.4, 2, 24.9), Vector3(4.4, 4, 0.3), wall, null, true, "wall") + box(Vector3(6.4, 2, 26.7), Vector3(4.4, 4, 0.3), wall, null, true, "wall") # drum bay outer shell - box(Vector3(12.15, 3.5, 22), Vector3(0.3, 8, 6), wall, null, true) - box(Vector3(8, 3.5, 19.3), Vector3(8, 8, 0.3), wall, null, true) - box(Vector3(8, 3.5, 24.7), Vector3(8, 8, 0.3), wall, null, true) + box(Vector3(12.15, 3.5, 22), Vector3(0.3, 8, 6), wall, null, true, "greeble") + box(Vector3(8, 3.5, 19.3), Vector3(8, 8, 0.3), wall, null, true, "greeble") + box(Vector3(8, 3.5, 24.7), Vector3(8, 8, 0.3), wall, null, true, "greeble") # end walls - box(Vector3(0, 2, -0.5), Vector3(8.6, 4, 0.3), wall, null, true) - box(Vector3(0, 2, 44.5), Vector3(8.6, 4, 0.3), wall, null, true) + box(Vector3(0, 2, -0.5), Vector3(8.6, 4, 0.3), wall, null, true, "bulk") + box(Vector3(0, 2, 44.5), Vector3(8.6, 4, 0.3), wall, null, true, "bulk") # dividers + doors for z in [8.0, 16.0, 26.0, 34.0, 40.0]: divider(z) @@ -298,11 +362,11 @@ func _build_objects() -> void: drum.position = Vector3(8, 3.5, 22) add_child(drum) var dc := Color(0.42, 0.38, 0.3) - box(Vector3(0, -3.2, 0), Vector3(6.8, 0.4, 4.4), dc, drum) - box(Vector3(3.2, 0, 0), Vector3(0.4, 6.8, 4.4), dc, drum) - box(Vector3(-3.2, 0, 0), Vector3(0.4, 6.8, 4.4), dc, drum) - box(Vector3(0, 0, 2.2), Vector3(6.8, 6.8, 0.4), dc, drum) - box(Vector3(0, 0, -2.2), Vector3(6.8, 6.8, 0.4), dc, drum) + box(Vector3(0, -3.2, 0), Vector3(6.8, 0.4, 4.4), dc, drum, false, "bulk") + box(Vector3(3.2, 0, 0), Vector3(0.4, 6.8, 4.4), dc, drum, false, "bulk") + box(Vector3(-3.2, 0, 0), Vector3(0.4, 6.8, 4.4), dc, drum, false, "bulk") + box(Vector3(0, 0, 2.2), Vector3(6.8, 6.8, 0.4), dc, drum, false, "bulk") + box(Vector3(0, 0, -2.2), Vector3(6.8, 6.8, 0.4), dc, drum, false, "bulk") box(Vector3(-2.6, 2.3, 0), Vector3(1.0, 0.15, 1.0), dc, drum) # shelf var crate := I.Pickup.new() crate.kind = "crate" diff --git a/test/integration.gd.uid b/test/integration.gd.uid new file mode 100644 index 0000000..429a481 --- /dev/null +++ b/test/integration.gd.uid @@ -0,0 +1 @@ +uid://dplolvpcgpla2