diff --git a/README.md b/README.md
index 45585f0..3e73e73 100644
--- a/README.md
+++ b/README.md
@@ -43,16 +43,15 @@
πΊοΈ Supports 2x2, 4x4, 8x8, 16x16 and any custom size maps
-π Support map rotation π
+π Support map rotation
π Supports custom [DTM Providers](#DTM-Providers) π
-πΎ Automatically generates fields π
-π½ Automatically generates farmlands π
-πΏ Automatically generates decorative foliage π
-π² Automatically generates forests π
-π Automatically generates water planes π
+πΎ Automatically generates fields
+π½ Automatically generates farmlands
+πΏ Automatically generates decorative foliage
+π² Automatically generates forests
+π Automatically generates water planes
π Automatically generates splines π
π°οΈ Automatically downloads high resolution satellite images π
-ποΈ Allows to use multiple DTM providers for elevation models π
π Based on real-world data from OpenStreetMap
πΊοΈ Supports [custom OSM maps](/docs/custom_osm.md)
ποΈ Generates height map using SRTM dataset
@@ -73,10 +72,14 @@
πΏ Automatically generates decorative foliage.
π² Automatically generates forests.
+
+π² Allows to select trees for generation.
π Automatically generates water planes.
π Automatically generates splines.
+
+ποΈ Allows customization of the texture schema.
ποΈ True-to-life blueprints for fast and precise modding.
@@ -233,6 +236,8 @@ Tools are divided into categories, which are listed below.
#### For custom schemas
- **Tree Schema Editor** - allows you to view all the supported trees models and select the ones you need on your map. After it, you should click the Show updated schema button and copy the JSON schema to the clipboard. Then you can use it in the Expert settings to generate the map with the selected trees.
+- **Texture Schema Editor** - allows you to view all the supported textures and edit their parameters, such as priority, OSM tags and so on. After editing, you should click the Show updated schema button and copy the JSON schema to the clipboard. Then you can use it in the Expert settings to generate the map with the updated textures.
+
#### For Textures and DEM
- **GeoTIFF windowing** - allows you to upload your GeoTIFF file and select the region of interest to extract it from the image. It's useful when you have high-resolution DEM data and want to create a height map using it.
diff --git a/webui/tools/section.py b/webui/tools/section.py
index 0c3f340..1728840 100644
--- a/webui/tools/section.py
+++ b/webui/tools/section.py
@@ -2,6 +2,7 @@
from tools.background import ConvertImageToObj
from tools.dem import GeoTIFFWindowingTool
+from tools.textures import TextureSchemaEditorTool
from tools.tool import Tool
from tools.trees import TreeSchemaEditorTool
@@ -24,7 +25,7 @@ def add(cls):
class Shemas(Section):
title = "π Schemas"
description = "Tools to work with different schemas."
- tools = [TreeSchemaEditorTool]
+ tools = [TreeSchemaEditorTool, TextureSchemaEditorTool]
class TexturesAndDEM(Section):
diff --git a/webui/tools/textures.py b/webui/tools/textures.py
new file mode 100644
index 0000000..745f172
--- /dev/null
+++ b/webui/tools/textures.py
@@ -0,0 +1,74 @@
+import json
+from typing import Any, NamedTuple
+
+import streamlit as st
+from config import FS25_TEXTURE_SCHEMA_PATH
+from tools.textures_data import TEXTURE_URLS
+from tools.tool import Tool
+
+COLUMNS_PER_ROW = 5
+
+
+class TextureInfo(NamedTuple):
+ name: str
+ data: dict[str, Any]
+ url: str
+
+
+class TextureSchemaEditorTool(Tool):
+ title = "Texture Schema Editor"
+ description = "This tool allows you to edit the texture schema for the map generation. "
+ icon = "π¨"
+
+ def content(self):
+ with open(FS25_TEXTURE_SCHEMA_PATH, "r", encoding="utf-8") as f:
+ self.texture_schema = json.load(f)
+
+ texture_infos = []
+ for texture in self.texture_schema:
+ texture_name = texture["name"]
+ texture_url = TEXTURE_URLS.get(texture_name)
+ if not texture_url:
+ continue
+
+ texture_infos.append(TextureInfo(texture_name, texture, texture_url))
+
+ self.button_container = st.container()
+
+ # Create a grid of images using the number of columns per row
+ self.text_areas = {}
+ for i in range(0, len(texture_infos), COLUMNS_PER_ROW):
+ row = st.columns(COLUMNS_PER_ROW)
+ for j, texture_info in enumerate(texture_infos[i : i + COLUMNS_PER_ROW]):
+ with row[j]:
+ st.image(texture_info.url, use_container_width=True)
+ text_area = st.text_area(
+ texture_info.name,
+ value=json.dumps(texture_info.data, indent=2),
+ key=texture_info.name,
+ height=160,
+ )
+ self.text_areas[texture_info.name] = text_area
+
+ with self.button_container:
+ if st.button("Show updated schema", key="show_updated_texture_schema"):
+ texture_schema = self.read_schema()
+ st.success(
+ "Texture schema was generated, click the copy button to copy it to the "
+ "clipboard. \n"
+ "Then paste it into the texture schema input field in the generation tool."
+ )
+ st.json(texture_schema, expanded=False)
+
+ def read_schema(self) -> list[dict[str, str | int]]:
+ new_schema = []
+ for texture_name, texture_data in self.text_areas.items():
+ try:
+ data = json.loads(texture_data)
+ except json.JSONDecodeError:
+ st.error(f"Error reading schema for texture name: {texture_name}")
+ continue
+
+ new_schema.append(data)
+
+ return new_schema
diff --git a/webui/tools/textures_data.py b/webui/tools/textures_data.py
new file mode 100644
index 0000000..3acc33d
--- /dev/null
+++ b/webui/tools/textures_data.py
@@ -0,0 +1,45 @@
+TEXTURE_URLS = {
+ "asphalt": "https://github.com/user-attachments/assets/a1a5f095-9a14-4b9c-af42-a3399157e17e",
+ "asphaltCracks": "https://github.com/user-attachments/assets/4c124557-0c5e-45f3-906f-937c6a1f284a",
+ "asphaltDirt": "https://github.com/user-attachments/assets/89fb98aa-3bc4-4a45-b2cf-5a7aafe4aa07",
+ "asphaltDusty": "https://github.com/user-attachments/assets/cdbcda8c-5d4c-4f0a-9869-7b11f7cfbade",
+ "asphaltGravel": "https://github.com/user-attachments/assets/3754efbc-bbff-4845-884d-14a176d6b174",
+ "asphaltTwigs": "https://github.com/user-attachments/assets/513aa2a9-e8f5-4b34-858c-ff54d242e684",
+ "concrete": "https://github.com/user-attachments/assets/544737ff-0e83-4a37-9751-efc275f7510d",
+ "concreteGravelSand": "https://github.com/user-attachments/assets/24100801-55b7-45b2-93f1-fb53a07b1d61",
+ "concretePebbles": "https://github.com/user-attachments/assets/ff793ba6-9e54-4f3e-a21e-8e096bf63839",
+ "concreteShattered": "https://github.com/user-attachments/assets/9d0b22ed-4435-4bea-801b-1bda45cddb83",
+ "forestGrass": "https://github.com/user-attachments/assets/6b215423-2034-40fb-a678-eaa075373854",
+ "forestLeaves": "https://github.com/user-attachments/assets/b5bb051f-b647-4faa-b9a3-90ce4a77a48e",
+ "forestNeedels": "https://github.com/user-attachments/assets/91df605e-eda6-4221-a572-8fb84df5c987",
+ "forestRockRoots": "https://github.com/user-attachments/assets/7804a25a-1803-41e4-93d8-b1fcf8b701b1",
+ "grass": "https://github.com/user-attachments/assets/30469cf8-f984-4359-8c0c-8387b44ae519",
+ "grassClovers": "https://github.com/user-attachments/assets/03a7e881-4f8a-46dd-8e2a-672a7d82cf2f",
+ "grassCut": "https://github.com/user-attachments/assets/c54249e8-2deb-46e8-baf5-784d949dfd34",
+ "grassDirtPatchy": "https://github.com/user-attachments/assets/20168e61-585d-43bf-bc07-dca74d652d89",
+ "grassDirtPatchyDry": "https://github.com/user-attachments/assets/90eea824-7d03-4060-8e57-cce29f72ba64",
+ "grassDirtStones": "https://github.com/user-attachments/assets/3acc201a-ee21-4492-a746-150a6e4b310a",
+ "grassFreshMiddle": "https://github.com/user-attachments/assets/2aca54e6-68db-44d3-9c8f-998522ca18ba",
+ "grassFreshShort": "https://github.com/user-attachments/assets/103d6efd-032e-4672-b717-ba64d9f9cd9c",
+ "grassMoss": "https://github.com/user-attachments/assets/8e5a7dff-987c-4772-8531-e237c7aa0cee",
+ "gravel": "https://github.com/user-attachments/assets/d0c8de3f-191c-43a7-899d-902e63b10553",
+ "gravelDirtMoss": "https://github.com/user-attachments/assets/b618bba2-f4a4-4b7b-881f-6462c98fc666",
+ "gravelPebblesMoss": "https://github.com/user-attachments/assets/48332684-6878-4aab-b917-ddaea3338abe",
+ "gravelPebblesMossPatchy": "https://github.com/user-attachments/assets/5e1acd59-7674-470e-b5b0-307ea9b250e1",
+ "gravelSmall": "https://github.com/user-attachments/assets/acf725c6-d295-4c92-bb42-e761bdf2feb1",
+ "mudDark": "https://github.com/user-attachments/assets/c6ce48ab-13c1-4000-a75a-673ebd451149",
+ "mudDarkGrassPatchy": "https://github.com/user-attachments/assets/8c70e8a7-e561-4028-8f23-0e41fb0b4e76",
+ "mudDarkMossPatchy": "https://github.com/user-attachments/assets/e21b538f-c52e-465b-b88a-a93f87d01584",
+ "mudLeaves": "https://github.com/user-attachments/assets/540263bf-807d-4159-99f0-8c1493075834",
+ "mudLight": "https://github.com/user-attachments/assets/58aa1d41-15bd-4d03-8eed-1e20fcb39cf4",
+ "mudPebbles": "https://github.com/user-attachments/assets/e51cac8e-dd4b-4e76-8a8d-7320182fc652",
+ "mudPebblesLight": "https://github.com/user-attachments/assets/6973aaf7-2894-430d-9ba0-ece78e4b55d7",
+ "mudTracks": "https://github.com/user-attachments/assets/d4a222bb-6f2b-459d-8a36-38e1a31a46ba",
+ "pebblesForestGround": "https://github.com/user-attachments/assets/ffb1a80d-1338-4e9e-84db-aa157d894617",
+ "rock": "https://github.com/user-attachments/assets/a1a78285-b7c3-4a2a-b2ec-fbae4898f566",
+ "rockFloorTiles": "https://github.com/user-attachments/assets/7068057b-b2c8-4952-ab88-47afa700c488",
+ "rockFloorTilesPattern": "https://github.com/user-attachments/assets/6be8c2a3-d3c7-4951-82b5-8780068e20c5",
+ "rockForest": "https://github.com/user-attachments/assets/ef7ee19a-c1b9-4371-a5b2-3309118ef981",
+ "rockyForestGround": "https://github.com/user-attachments/assets/5e08392b-ec91-466a-8c46-2a632015c4bb",
+ "sand": "https://github.com/user-attachments/assets/4c79b020-cbc3-40ea-ae7f-04599309ef80",
+}
diff --git a/webui/tools/trees.py b/webui/tools/trees.py
index c4a941a..5a39896 100644
--- a/webui/tools/trees.py
+++ b/webui/tools/trees.py
@@ -54,7 +54,7 @@ def content(self):
self.checkboxes[tree_info] = tree_checkbox
with self.button_container:
- if st.button("Show updated schema"):
+ if st.button("Show updated schema", key="show_updated_tree_schema"):
tree_schema = self.read_schema()
st.success(
"Tree schema was generated, click the copy button to copy it to the "