diff --git a/doc/en/block-models.md b/doc/en/block-models.md index c6fe7f19e..ba2f75858 100644 --- a/doc/en/block-models.md +++ b/doc/en/block-models.md @@ -1,4 +1,7 @@ -# Block Models +# Block Models (depricated) + +> ![WARNING] +> The `model-primitives` property is deprecated. Use the [VCM format](vcm.md) for a textual description of the model's primitives. Block model may be created with following properties: diff --git a/doc/ru/block-models.md b/doc/ru/block-models.md index 660f5d37e..a7ae6636c 100644 --- a/doc/ru/block-models.md +++ b/doc/ru/block-models.md @@ -1,4 +1,7 @@ -# Модели блоков +# Модели блоков (устарело) + +> ![WARNING] +> Свойство `model-primitives` является устаревшим, используйте [формат VCM](vcm.md) для текстового описания модели из примитивов. Создание собственной модели блока может быть реализовано при указании у блока свойств: ```js diff --git a/doc/ru/vcm.md b/doc/ru/vcm.md index 379e0328d..8943a19a0 100644 --- a/doc/ru/vcm.md +++ b/doc/ru/vcm.md @@ -20,15 +20,32 @@ В отличие от XML в корне может находиться несколько элементов. -На данный момент существует два вида примитивов: box и rect, а также, part (описывает часть примитива, такую как, например, сторона куба). +На данный момент существует три вида примитивов: tri, box и rect, а также, part (описывает часть примитива, такую как, например, сторона куба). > [!NOTE] > По-умолчанию текстурные координаты определяются размерами примитивов. > При размерах более 1.0 результат не определён и может измениться в последующих обновлениях. > Используйте `region` или `region-scale` для ручной настройки. +### Свойства `tri` + +Примитив описывает треугольник. + +- `a` - точка A. Пример: `a (0,0,0)` +- `b` - точка B. Пример: `b (1,0,0)` +- `c` - точка С. Пример: `c (1,1,0)` +- `uv` - нормализованные текстурные координаты точек (6 чисел, по 2 на точку). Пример: `uv (0,0, 1,0, 1,1)` +- `texture` - отображаемая текстура. По-умолчанию: `$0`. Пример: `texture "blocks:sand"` +- `region` - UV регион в границах выбранной текстуры, определяется позициями противоположных углов квадрата нормализованных текстурных координат. Пример: `region (0,0,1,1)` +- `region-scale` вектор-множитель для UV региона. Пример: `region-scale (0.5,1)` +- `shading` определяет возможность затенения на примитиве. Пример: `shading off` + +Текстурные координаты по-умолчанию не зависят от формы из размера, в отличие от других примитивов. + ### Свойства `rect` +Примитив описывает параллелограмм через векторы right и up. + - `from` - точка начала примитива. Пример: `from (0,0.5,0.125)` - `right` - вектор X, также определяющий ширину примитива. Пример: `right (1,0,0)` - `up` - вектор Y, также определяющий высоту примитива. Пример: `up (0,1,0)` @@ -40,6 +57,8 @@ ### Свойства `box` +Примитив описывает прямоугольный параллелепипед. + - `from` - точка начала примитива. Пример: `from (0,0,0)` - `to` - противоположная от начала точка. Пример: `to (1,1,1)` - `origin` - точка, относительно которой будет применено вращение. По-умолчанию: центр примитива. Пример: `origin (0.5,0.5,0.5)` @@ -48,7 +67,9 @@ - `shading` определяет возможность затенения на примитиве. Пример: `shading off` - `delete` удаляет стороны по именам (top, bottom, east, west, north, south) -### Свойства `part` (в `box`) +### Свойства `part` (вложен в `box`) + +Примитив описывает свойства сторон прямоугольного параллелепипеда с указанными тегами (top/bottom/north/south/east/west). - `tags` - определяет то, на какаие из сторон будут применены свойства. Пример: `tags (top,bottom)` - `texture` - отображаемая текстура. По-умолчанию: `$индекс_стороны`. diff --git a/src/coders/vcm.cpp b/src/coders/vcm.cpp index b7d93b578..5bf54ee99 100644 --- a/src/coders/vcm.cpp +++ b/src/coders/vcm.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "xml.hpp" #include "util/stringutil.hpp" @@ -71,6 +72,42 @@ static void perform_rect(const xmlelement& root, model::Model& model) { ); } +static void perform_triangle(const xmlelement& root, model::Model& model) { + auto pointA = root.attr("a").asVec3(); + auto pointB = root.attr("b").asVec3(); + auto pointC = root.attr("c").asVec3(); + + glm::vec2 uvs[3] {{0, 0}, {1, 0}, {1, 1}}; + + bool shading = true; + if (root.has("shading")) { + shading = to_boolean(root.attr("shading")); + } + + glm::vec3 ba = pointB - pointA; + glm::vec3 ca = pointC - pointA; + glm::vec3 normal = glm::normalize(glm::cross(ba, ca)); + + if (root.has("uv")) { + root.attr("uv").asNumbers(glm::value_ptr(uvs[0]), 6); + } else { + UVRegion region {}; + if (root.has("region")) { + region.set(root.attr("region").asVec4()); + } + if (root.has("region-scale")) { + region.scale(root.attr("region-scale").asVec2()); + } + for (auto& uv : uvs) { + uv = region.apply(uv); + } + } + + std::string texture = root.attr("texture", "$0").getText(); + auto& mesh = model.addMesh(texture, shading); + mesh.addTriangle(pointA, pointB, pointC, normal, uvs[0], uvs[1], uvs[2]); +} + static void perform_box(const xmlelement& root, model::Model& model) { auto from = root.attr("from").asVec3(); auto to = root.attr("to").asVec3(); @@ -181,6 +218,8 @@ static std::unique_ptr load_model(const xmlelement& root) { perform_rect(*elem, model); } else if (tag == "box") { perform_box(*elem, model); + } else if (tag == "tri") { + perform_triangle(*elem, model); } } diff --git a/src/coders/xml.cpp b/src/coders/xml.cpp index 0763fa430..4efabc959 100644 --- a/src/coders/xml.cpp +++ b/src/coders/xml.cpp @@ -105,6 +105,19 @@ glm::vec4 Attribute::asColor() const { } } +int Attribute::asNumbers(float* dst, size_t dstSize) const { + size_t pos = 0; + size_t count = 0; + while (pos < text.length() && count < dstSize) { + size_t end = text.find(',', pos); + dst[count++] = util::parse_double( + text, pos, std::min(end - pos, text.length() - pos) + ); + pos = end + 1; + } + return count; +} + Node::Node(std::string tag) : tag(std::move(tag)) { } diff --git a/src/coders/xml.hpp b/src/coders/xml.hpp index 24cf0fbdc..4954caa17 100644 --- a/src/coders/xml.hpp +++ b/src/coders/xml.hpp @@ -29,6 +29,7 @@ namespace xml { glm::vec3 asVec3() const; glm::vec4 asVec4() const; glm::vec4 asColor() const; + int asNumbers(float* dst, size_t dstSize) const; }; /// @brief XML element class. Text element has tag 'text' and attribute diff --git a/src/graphics/commons/Model.cpp b/src/graphics/commons/Model.cpp index 386ae1cce..e7c247868 100644 --- a/src/graphics/commons/Model.cpp +++ b/src/graphics/commons/Model.cpp @@ -41,6 +41,20 @@ void Mesh::addPlane( ); } +void Mesh::addTriangle( + const glm::vec3& a, + const glm::vec3& b, + const glm::vec3& c, + const glm::vec3& norm, + const glm::vec2& uvA, + const glm::vec2& uvB, + const glm::vec2& uvC +) { + vertices.push_back({a, uvA, norm}); + vertices.push_back({b, uvB, norm}); + vertices.push_back({c, uvC, norm}); +} + void Mesh::addRect( const glm::vec3& pos, const glm::vec3& right, diff --git a/src/graphics/commons/Model.hpp b/src/graphics/commons/Model.hpp index bbb0d398f..67618ed38 100644 --- a/src/graphics/commons/Model.hpp +++ b/src/graphics/commons/Model.hpp @@ -39,6 +39,15 @@ namespace model { const glm::vec3& up, const glm::vec3& norm, const UVRegion& region + ); + void addTriangle( + const glm::vec3& a, + const glm::vec3& b, + const glm::vec3& c, + const glm::vec3& norm, + const glm::vec2& uvA, + const glm::vec2& uvB, + const glm::vec2& uvC ); void addBox(const glm::vec3& pos, const glm::vec3& size); void addBox(