colobot/colobot-base/graphics/model/model_mesh.cpp

462 lines
11 KiB
C++
Raw Normal View History

/*
* This file is part of the Colobot: Gold Edition source code
2023-08-06 21:15:48 +00:00
* Copyright (C) 2001-2023, Daniel Roux, EPSITEC SA & TerranovaTeam
2015-08-22 14:40:02 +00:00
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://gnu.org/licenses
*/
#include "graphics/model/model_mesh.h"
#include <array>
2015-08-02 09:40:47 +00:00
namespace Gfx
{
CVertexProxy::CVertexProxy(CModelPart* part, size_t index)
: m_part(part), m_index(index)
{
}
const glm::vec3& CVertexProxy::GetPosition() const
{
return m_part->m_positions.array[m_index];
}
void CVertexProxy::SetPosition(const glm::vec3& position) const
{
m_part->m_positions.array[m_index] = position;
}
const glm::u8vec4& CVertexProxy::GetColor() const
{
return m_part->m_colors.array[m_index];
}
void CVertexProxy::SetColor(const glm::u8vec4& color) const
{
m_part->m_colors.array[m_index] = color;
}
const glm::vec2& CVertexProxy::GetUV1() const
{
return m_part->m_uvs1.array[m_index];
}
void CVertexProxy::SetUV1(const glm::vec2& uv) const
{
m_part->m_uvs1.array[m_index] = uv;
}
const glm::vec2& CVertexProxy::GetUV2() const
{
return m_part->m_uvs2.array[m_index];
}
void CVertexProxy::SetUV2(const glm::vec2& uv) const
{
m_part->m_uvs2.array[m_index] = uv;
}
const glm::vec3& CVertexProxy::GetNormal() const
{
return m_part->m_normals.array[m_index];
}
void CVertexProxy::SetNormal(const glm::vec3& normal) const
{
m_part->m_normals.array[m_index] = normal;
}
const glm::vec4& CVertexProxy::GetTangent() const
{
return m_part->m_tangents.array[m_index];
}
void CVertexProxy::SetTangent(const glm::vec4& tangent) const
{
m_part->m_tangents.array[m_index] = tangent;
}
const glm::u8vec4& CVertexProxy::GetBoneIndices() const
{
return m_part->m_boneIndices.array[m_index];
}
void CVertexProxy::SetBoneIndices(const glm::u8vec4& indices) const
{
m_part->m_boneIndices.array[m_index] = indices;
}
const glm::vec4& CVertexProxy::GetBoneWeights() const
{
return m_part->m_boneWeights.array[m_index];
}
void CVertexProxy::SetBoneWeights(const glm::vec4& weights) const
{
m_part->m_boneWeights.array[m_index] = weights;
}
CModelPart::CModelPart(const Material& material, size_t vertices, size_t indices)
: m_material(material) {
m_positions.array.resize(vertices);
m_indices.array.resize(indices);
}
const Material& CModelPart::GetMaterial() const
{
return m_material;
}
void CModelPart::SetVertices(size_t count)
{
m_positions.array.resize(count);
if (m_colors.enabled) m_colors.array.resize(count);
if (m_uvs1.enabled) m_uvs1.array.resize(count);
if (m_uvs2.enabled) m_uvs2.array.resize(count);
if (m_normals.enabled) m_normals.array.resize(count);
if (m_tangents.enabled) m_tangents.array.resize(count);
if (m_boneIndices.enabled) m_boneIndices.array.resize(count);
if (m_boneWeights.enabled) m_boneWeights.array.resize(count);
}
void CModelPart::SetIndices(size_t count)
{
2023-05-08 23:42:48 +00:00
m_indices.enabled = count > 0;
m_indices.array.resize(count);
}
bool CModelPart::Has(VertexAttribute array) const
{
switch (array)
{
case VertexAttribute::POSITION:
return true;
case VertexAttribute::COLOR:
return m_colors.enabled;
case VertexAttribute::UV1:
return m_uvs1.enabled;
case VertexAttribute::UV2:
return m_uvs2.enabled;
case VertexAttribute::NORMAL:
return m_normals.enabled;
case VertexAttribute::TANGENT:
return m_tangents.enabled;
case VertexAttribute::BONE_INDICES:
return m_boneIndices.enabled;
case VertexAttribute::BONE_WEIGHTS:
return m_boneWeights.enabled;
default:
return false;
}
}
void CModelPart::Add(VertexAttribute attribute)
{
switch (attribute)
{
case VertexAttribute::COLOR:
m_colors.enabled = true;
m_colors.array.resize(m_positions.array.size());
break;
case VertexAttribute::UV1:
m_uvs1.enabled = true;
m_uvs1.array.resize(m_positions.array.size());
break;
case VertexAttribute::UV2:
m_uvs2.enabled = true;
m_uvs2.array.resize(m_positions.array.size());
break;
case VertexAttribute::NORMAL:
m_normals.enabled = true;
m_normals.array.resize(m_positions.array.size());
break;
case VertexAttribute::TANGENT:
m_tangents.enabled = true;
m_tangents.array.resize(m_positions.array.size());
break;
case VertexAttribute::BONE_INDICES:
m_boneIndices.enabled = true;
m_boneIndices.array.resize(m_positions.array.size());
break;
case VertexAttribute::BONE_WEIGHTS:
m_boneWeights.enabled = true;
m_boneWeights.array.resize(m_positions.array.size());
2023-05-08 23:42:48 +00:00
return;
}
}
void CModelPart::Remove(VertexAttribute attribute)
{
switch (attribute)
{
case VertexAttribute::COLOR:
m_colors.enabled = false;
m_colors.array.resize(0);
return;
case VertexAttribute::UV1:
m_uvs1.enabled = false;
m_uvs1.array.resize(0);
return;
case VertexAttribute::UV2:
m_uvs2.enabled = false;
m_uvs2.array.resize(0);
return;
case VertexAttribute::NORMAL:
m_normals.enabled = false;
m_normals.array.resize(0);
return;
case VertexAttribute::TANGENT:
m_tangents.enabled = false;
m_tangents.array.resize(0);
return;
case VertexAttribute::BONE_INDICES:
m_boneIndices.enabled = false;
m_boneIndices.array.resize(0);
return;
case VertexAttribute::BONE_WEIGHTS:
m_boneWeights.enabled = false;
m_boneWeights.array.resize(0);
return;
}
}
bool CModelPart::IsIndexed() const
{
return m_indices.enabled;
}
size_t CModelPart::GetVertexCount() const
{
return m_positions.array.size();
}
size_t CModelPart::GetIndexCount() const
{
return m_indices.array.size();
}
const std::vector<unsigned int>& CModelPart::GetIndices() const
{
return m_indices.array;
}
CVertexProxy CModelPart::GetVertex(size_t index)
{
return CVertexProxy(this, index);
}
std::uint32_t CModelPart::GetIndex(size_t index)
{
return m_indices.array[index];
}
void CModelPart::AddVertex(const Vertex3D& vertex)
{
m_positions.array.push_back(vertex.position);
if (m_colors.enabled) m_colors.array.push_back(vertex.color);
if (m_uvs1.enabled) m_uvs1.array.push_back(vertex.uv);
if (m_uvs2.enabled) m_uvs2.array.push_back(vertex.uv2);
if (m_normals.enabled) m_normals.array.push_back(vertex.normal);
if (m_tangents.enabled) m_tangents.array.push_back({ 1.0f, 0.0f, 0.0f, 1.0f });
if (m_boneIndices.enabled) m_boneIndices.array.push_back({ 0, 0, 0, 0 });
if (m_boneWeights.enabled) m_boneWeights.array.push_back({ 1.0f, 0.0f, 0.0f, 0.0f });
}
void CModelPart::AddIndex(unsigned int index)
{
if (m_indices.enabled) m_indices.array.push_back(index);
}
2023-05-08 23:42:48 +00:00
void CModelPart::SetIndex(size_t index, unsigned int value)
{
m_indices.array[index] = value;
}
void CModelPart::GetTriangles(std::vector<Gfx::ModelTriangle>& triangles)
{
size_t n = IsIndexed()
? GetIndexCount()
: GetVertexCount();
for (size_t i = 0; i < n - 2; i += 3)
{
std::array<Gfx::Vertex3D, 3> verts;
for (size_t j = 0; j < 3; j++)
{
size_t index = IsIndexed()
? GetIndex(i + j)
: i + j;
auto vertex = GetVertex(index);
verts[j].position = vertex.GetPosition();
2023-05-08 23:42:48 +00:00
if (Has(VertexAttribute::COLOR)) verts[j].color = vertex.GetColor();
else verts[j].color = { 255, 255, 255, 255 };
if (Has(VertexAttribute::UV1)) verts[j].uv = vertex.GetUV1();
else verts[j].uv = { 0, 0 };
if (Has(VertexAttribute::UV2)) verts[j].uv2 = vertex.GetUV2();
else verts[j].uv2 = { 0, 0 };
if (Has(VertexAttribute::NORMAL)) verts[j].normal = vertex.GetNormal();
else verts[j].normal = { 0, 0, 1 };
}
triangles.push_back({ verts[0], verts[1], verts[2], GetMaterial() });
}
}
void CModelMesh::AddTriangle(const ModelTriangle& triangle)
{
for (auto& part : m_parts)
{
if (part->GetMaterial() == triangle.material)
{
part->AddVertex(triangle.p1);
part->AddVertex(triangle.p2);
part->AddVertex(triangle.p3);
return;
}
}
auto part = std::make_unique<CModelPart>(triangle.material, 0, 0);
part->Add(VertexAttribute::COLOR);
part->Add(VertexAttribute::UV1);
part->Add(VertexAttribute::UV2);
part->Add(VertexAttribute::NORMAL);
part->AddVertex(triangle.p1);
part->AddVertex(triangle.p2);
part->AddVertex(triangle.p3);
m_parts.push_back(std::move(part));
}
void CModelMesh::AddTriangle(const Triangle& triangle, const Material& material)
{
for (auto& part : m_parts)
{
if (part->GetMaterial() == material)
{
part->AddVertex(triangle.p1);
part->AddVertex(triangle.p2);
part->AddVertex(triangle.p3);
return;
}
}
auto part = std::make_unique<CModelPart>(material, 0, 0);
part->Add(VertexAttribute::COLOR);
part->Add(VertexAttribute::UV1);
part->Add(VertexAttribute::UV2);
part->Add(VertexAttribute::NORMAL);
part->AddVertex(triangle.p1);
part->AddVertex(triangle.p2);
part->AddVertex(triangle.p3);
m_parts.push_back(std::move(part));
}
size_t CModelMesh::GetPartCount() const
{
return m_parts.size();
}
CModelPart* CModelMesh::GetPart(size_t index) const
{
return m_parts[index].get();
}
CModelPart* CModelMesh::AddPart(const Material& material)
{
for (auto& part : m_parts)
{
if (part->GetMaterial() == material)
{
return part.get();
}
}
auto part = std::make_unique<CModelPart>(material, 0, 0);
m_parts.push_back(std::move(part));
return m_parts.back().get();
}
const glm::vec3& CModelMesh::GetPosition() const
{
return m_position;
}
void CModelMesh::SetPosition(const glm::vec3& position)
{
m_position = position;
}
const glm::vec3& CModelMesh::GetRotation() const
{
return m_rotation;
}
void CModelMesh::SetRotation(const glm::vec3& rotation)
{
m_rotation = rotation;
}
const glm::vec3& CModelMesh::GetScale() const
{
return m_scale;
}
void CModelMesh::SetScale(const glm::vec3& scale)
{
m_scale = scale;
}
const std::string& CModelMesh::GetParent() const
{
return m_parent;
}
void CModelMesh::SetParent(const std::string& parent)
{
m_parent = parent;
}
std::vector<ModelTriangle> CModelMesh::GetTriangles() const
{
std::vector<ModelTriangle> triangles;
for (const auto& part : m_parts)
{
part->GetTriangles(triangles);
}
return triangles;
}
} // namespace Gfx