1#include "Foundation/Logging/Logger.h"
3#include "Components/Core/MeshComponent.h"
4#include "Components/Core/SceneComponent.h"
5#include "Components/Core/TransformComponent.h"
7#include "Systems/Core/TransformSystem.h"
9#include "Resources/Mesh.h"
10#include "Resources/MeshManager.h"
11#include "Resources/VertexFormats.h"
13#include "EntityStore.h"
16#include "PackMeshCommand.h"
18#include <meshoptimizer/meshoptimizer.h>
29 for (
EntityPtr& child : sceneComp->children) {
30 handle(context, cmd, child);
38 glm::mat4 transform(1.f);
41 if (!PackMeshCommand::pack(context, status, transform, meshComp->meshHandle, cmd->packOptions)) {
42 LOG_ERROR(logger,
"Faild to pack mesh: %s", status.c_str());
45 if (!status.empty()) {
46 LOG_DEBUG(logger,
"%s", status.c_str());
50 context->transformSystem->setLocalTransform(trComp, context->transformSystem->getLocalTransform(trComp) * transform);
54 meshComp->setChanged();
61Cogs::Core::PackMeshCommand::PackMeshCommand(
EditorState* state) :
68 for (EntityId entityId : state->selected) {
70 handle(context,
this, entity);
76void Cogs::Core::PackMeshCommand::undo()
78 for (UndoItem& undoItem : undoItems) {
79 if (
EntityPtr entity = undoItem.entity.lock(); entity) {
81 meshComp->meshHandle = undoItem.meshHandle;
82 meshComp->setChanged();
85 LOG_ERROR(logger,
"Failed to undo entity, entity lost its mesh component");
89 LOG_ERROR(logger,
"Failed to undo entity, entity does not exist");
97 glm::vec2 octEncode(
const glm::vec3& n)
99 const float t = std::abs(n.x) + std::abs(n.y) + std::abs(n.z);
100 glm::vec2 p = (1.f / t)*glm::vec2(n);
102 p = glm::vec2((0.f <= p.x ? 1.f : -1.f) * (1.f - std::abs(p.y)),
103 (0.f <= p.y ? 1.f : -1.f) * (1.f - std::abs(p.x)));
109 glm::vec3 octDecode(
const glm::vec2& f)
112 glm::vec3 n = glm::vec3(f.x, f.y, 1.f - std::abs(f.x) - std::abs(f.y));
113 float t = std::max(-n.z, 0.f);
114 n.x += 0.f <= n.x ? -t : t;
115 n.y += 0.f <= n.y ? -t : t;
116 return glm::normalize(n);
119 glm::i16vec2 octEncodei16(
const glm::vec3& n)
122 glm::vec2 enc = glm::clamp(32767.f * octEncode(n), glm::vec2(-32767.f), glm::vec2(32767.f));
123 glm::i16vec2 q[4] = {
124 glm::i16vec2(std::floor(enc.x), floor(enc.y)),
125 glm::i16vec2(std::floor(enc.x), ceil(enc.y)),
126 glm::i16vec2(std::ceil(enc.x), floor(enc.y)),
127 glm::i16vec2(std::ceil(enc.x), ceil(enc.y)),
130 float error = 1.f - std::abs(dot(n, octDecode((1.f / 32767.f) * glm::vec2(q[0]))));
131 for (
size_t i = 1; i < 4; i++) {
132 float e = 1.f - std::abs(dot(n, octDecode((1.f / 32767.f) * glm::vec2(q[i]))));
140 return glm::i16vec2(glm::clamp(glm::round(32767.f * octEncode(n)),
142 glm::vec2(32767.f)));
146 glm::i8vec2 octEncodei8(
const glm::vec3& n)
149 glm::vec2 enc = glm::clamp(127.f * octEncode(n), glm::vec2(-127.f), glm::vec2(127.f));
151 glm::i8vec2(std::floor(enc.x), floor(enc.y)),
152 glm::i8vec2(std::floor(enc.x), ceil(enc.y)),
153 glm::i8vec2(std::ceil(enc.x), floor(enc.y)),
154 glm::i8vec2(std::ceil(enc.x), ceil(enc.y)),
158 float error = 1.f - std::abs(dot(n, octDecode((1.f / 127.f) * glm::vec2(q[0]))));
159 for (
size_t i = 1; i < 4; i++) {
160 float e = 1.f - std::abs(dot(n, octDecode((1.f / 127.f) * glm::vec2(q[i]))));
168 return glm::i8vec2(glm::clamp(glm::round(127.f * octEncode(n)),
174 enum struct PackFormat
176 Pos10un_Nrm8sn_Id16ui,
177 Pos16un_Nrm16sn_Id16ui,
178 Pos16un_Nrm8sn_Id32ui,
179 Pos16un_Nrm8sn_Id32f,
185 namespace Pos10un_Nrm8sn_Id16ui {
200 static_assert(
sizeof(Vtx) == 8);
204 .
offset = uint16_t(offsetof(Vtx, pos)),
205 .format = Cogs::Format::R10G10B10A2_UNORM,
212 .offset = uint16_t(offsetof(Vtx, nrm)),
213 .format = Cogs::Format::R8G8_SNORM,
220 .offset = uint16_t(offsetof(Vtx, tex)),
221 .format = Cogs::Format::R16_UINT,
230 namespace Pos16un_Nrm16sn_Id16ui {
237 static_assert(
sizeof(Vtx) == 12);
241 .
offset = uint16_t(offsetof(Vtx, pos)),
242 .format = Cogs::Format::R16G16B16_UNORM,
249 .offset = uint16_t(offsetof(Vtx, nrm)),
250 .format = Cogs::Format::R16G16_SNORM,
257 .offset = uint16_t(offsetof(Vtx, tex)),
258 .format = Cogs::Format::R16_UINT,
267 namespace Pos16un_Nrm8sn_Id32ui {
274 static_assert(
sizeof(Vtx) == 12);
278 .
offset = uint16_t(offsetof(Vtx, pos)),
279 .format = Cogs::Format::R16G16B16_UNORM,
286 .offset = uint16_t(offsetof(Vtx, nrm)),
287 .format = Cogs::Format::R8G8_SNORM,
294 .offset = uint16_t(offsetof(Vtx, tex)),
295 .format = Cogs::Format::R32_UINT,
304 namespace Pos16un_Nrm8sn_Id32f {
311 static_assert(
sizeof(Vtx) == 12);
315 .
offset = uint16_t(offsetof(Vtx, pos)),
316 .format = Cogs::Format::R16G16B16_UNORM,
323 .offset = uint16_t(offsetof(Vtx, nrm)),
324 .format = Cogs::Format::R8G8_SNORM,
331 .offset = uint16_t(offsetof(Vtx, tex)),
332 .format = Cogs::Format::R32_FLOAT,
341 namespace Pos16un_Nrm8sn {
347 static_assert(
sizeof(Vtx) == 8);
351 .
offset = uint16_t(offsetof(Vtx, pos)),
352 .format = Cogs::Format::R16G16B16_UNORM,
359 .offset = uint16_t(offsetof(Vtx, nrm)),
360 .format = Cogs::Format::R8G8_SNORM,
382 static_assert(
sizeof(Vtx) == 4);
386 .
offset = uint16_t(offsetof(Vtx, pos)),
387 .format = Cogs::Format::R10G10B10A2_UNORM,
400 .format = Cogs::Format::R16_UINT,
413 .format = Cogs::Format::R32_UINT,
426 .format = Cogs::Format::R32_FLOAT,
435 namespace Id32ui_Inst {
439 .format = Cogs::Format::R32_UINT,
450 if (inVertexData.empty())
return;
452 const char* inVertices = (
const char*)inVertexData.data();
453 const size_t inVertexCount = inVertexData.size() / stride;
455 std::vector<uint32_t> permutation(inVertexCount);
456 for (uint32_t i = 0; i < inVertexCount; i++) {
459 std::sort(permutation.begin(), permutation.end(),
460 [inVertices, stride](
const uint32_t& a,
const uint32_t& b) ->
bool
462 return std::memcmp(&inVertices[stride * a], &inVertices[stride * b], stride) < 0;
465 uniqueVertexData.resize(inVertexData.size());
466 char* uniqueVertices = (
char*)uniqueVertexData.data();
467 size_t currentUniqueVertex = 0;
469 uniqueVertexMap.resize(inVertexCount);
470 uniqueVertexMap[permutation[0]] = uint32_t(currentUniqueVertex);
471 std::memcpy(&uniqueVertices[stride * currentUniqueVertex], &inVertices[stride * permutation[0]], stride);
473 for (
size_t i = 1; i < inVertexCount; i++) {
474 if (std::memcmp(&uniqueVertices[stride * currentUniqueVertex], &inVertices[stride * permutation[i]], stride) != 0) {
475 std::memcpy(&uniqueVertices[stride * (++currentUniqueVertex)], &inVertices[stride * permutation[i]], stride);
477 uniqueVertexMap[permutation[i]] = uint32_t(currentUniqueVertex);
480 const size_t uniqueVertexCount = currentUniqueVertex + 1;
482 assert(uniqueVertexCount <= inVertexCount);
483 uniqueVertexData.resize(stride * uniqueVertexCount);
488 std::vector<uint32_t>& uniqueVertexMap,
489 const PackFormat packFmt,
493 const size_t vertexCount,
494 const glm::vec3& posMin,
495 const float invScale,
496 const uint32_t idOffset)
502 float posFormatScale = 0.f;
505 case PackFormat::Pos10un_Nrm8sn_Id16ui: {
506 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos10un_Nrm8sn_Id16ui::Fmt, std::size(Pos10un_Nrm8sn_Id16ui::Fmt));
507 fmtSize = Cogs::getSize(fmtHandle);
508 assert(
sizeof(Pos10un_Nrm8sn_Id16ui::Vtx) == fmtSize);
509 posFormatScale = 1023.f;
511 vertexData.resize(fmtSize * vertexCount,
false);
512 Pos10un_Nrm8sn_Id16ui::Vtx* vtx = (Pos10un_Nrm8sn_Id16ui::Vtx*)vertexData.data();
513 for (
size_t i = 0; i < vertexCount; i++) {
514 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
515 vtx[i].pos_x = uint32_t(p.x);
516 vtx[i].pos_y = uint32_t(p.y);
517 vtx[i].pos_z = uint32_t(p.z);
519 vtx[i].nrm = octEncodei8(glm::normalize(srcNrm[i]));
520 vtx[i].tex = uint16_t(uint32_t(std::max(0.f, srcTex[i].x)) - idOffset);
523 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
527 case PackFormat::Pos16un_Nrm16sn_Id16ui: {
528 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm16sn_Id16ui::Fmt, std::size(Pos16un_Nrm16sn_Id16ui::Fmt));
529 fmtSize = Cogs::getSize(fmtHandle);
530 assert(
sizeof(Pos16un_Nrm16sn_Id16ui::Vtx) == fmtSize);
531 posFormatScale = std::numeric_limits<uint16_t>::max();
533 vertexData.resize(fmtSize * vertexCount,
false);
534 Pos16un_Nrm16sn_Id16ui::Vtx* vtx = (Pos16un_Nrm16sn_Id16ui::Vtx*)vertexData.data();
535 for (
size_t i = 0; i < vertexCount; i++) {
536 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
537 vtx[i].pos = glm::u16vec3(p);
538 vtx[i].nrm = octEncodei16(glm::normalize(srcNrm[i]));
539 vtx[i].tex = uint16_t(uint32_t(std::max(0.f, srcTex[i].x)) - idOffset);
542 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
546 case PackFormat::Pos16un_Nrm8sn_Id32ui: {
547 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn_Id32ui::Fmt, std::size(Pos16un_Nrm8sn_Id32ui::Fmt));
548 fmtSize = Cogs::getSize(fmtHandle);
549 assert(
sizeof(Pos16un_Nrm8sn_Id32ui::Vtx) == fmtSize);
550 posFormatScale = std::numeric_limits<uint16_t>::max();
552 vertexData.resize(fmtSize * vertexCount,
false);
553 Pos16un_Nrm8sn_Id32ui::Vtx* vtx = (Pos16un_Nrm8sn_Id32ui::Vtx*)vertexData.data();
554 for (
size_t i = 0; i < vertexCount; i++) {
555 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
556 vtx[i].pos = glm::u16vec3(p);
557 vtx[i].nrm = octEncodei8(glm::normalize(srcNrm[i]));
558 vtx[i].tex = uint32_t(std::max(0.f, srcTex[i].x)) - idOffset;
561 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
565 case PackFormat::Pos16un_Nrm8sn_Id32f: {
566 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn_Id32f::Fmt, std::size(Pos16un_Nrm8sn_Id32f::Fmt));
567 fmtSize = Cogs::getSize(fmtHandle);
568 assert(
sizeof(Pos16un_Nrm8sn_Id32f::Vtx) == fmtSize);
569 posFormatScale = std::numeric_limits<uint16_t>::max();
571 vertexData.resize(fmtSize * vertexCount,
false);
572 Pos16un_Nrm8sn_Id32f::Vtx* vtx = (Pos16un_Nrm8sn_Id32f::Vtx*)vertexData.data();
573 for (
size_t i = 0; i < vertexCount; i++) {
574 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
575 vtx[i].pos = glm::u16vec3(p);
576 vtx[i].nrm = octEncodei8(glm::normalize(srcNrm[i]));
577 vtx[i].tex = float(uint32_t(std::max(0.f, srcTex[i].x)) - idOffset);
580 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
584 case PackFormat::Pos16un_Nrm8sn: {
585 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn::Fmt, std::size(Pos16un_Nrm8sn::Fmt));
586 fmtSize = Cogs::getSize(fmtHandle);
587 assert(
sizeof(Pos16un_Nrm8sn::Vtx) == fmtSize);
588 posFormatScale = std::numeric_limits<uint16_t>::max();
590 vertexData.resize(fmtSize * vertexCount,
false);
591 Pos16un_Nrm8sn::Vtx* vtx = (Pos16un_Nrm8sn::Vtx*)vertexData.data();
592 for (
size_t i = 0; i < vertexCount; i++) {
593 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
594 vtx[i].pos = glm::u16vec3(p);
595 vtx[i].nrm = octEncodei8(glm::normalize(srcNrm[i]));
597 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
601 case PackFormat::Pos10un: {
602 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos10un::Fmt, std::size(Pos10un::Fmt));
603 fmtSize = Cogs::getSize(fmtHandle);
604 assert(
sizeof(Pos10un::Vtx) == fmtSize);
605 posFormatScale = 1023.f;
606 vertexData.resize(fmtSize * vertexCount,
false);
607 Pos10un::Vtx* vtx = (Pos10un::Vtx*)vertexData.data();
608 for (
size_t i = 0; i < vertexCount; i++) {
609 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
610 vtx[i].pos_x = uint32_t(p.x);
611 vtx[i].pos_y = uint32_t(p.y);
612 vtx[i].pos_z = uint32_t(p.z);
615 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
621 assert(
false &&
"Invalid enum");
628 bool buildIndices(std::vector<uint32_t>& indices,
const std::vector<uint32_t>& uniqueVertexMap,
const Mesh* srcMesh)
635 switch (indexStream.
stride)
638 const uint16_t* srcIndices = (
const uint16_t*)indexStream.data();
639 for (
size_t i = 0; i + 2 < indexStream.
numElements; i += 3) {
640 uint32_t a = uniqueVertexMap[srcIndices[i + 0]];
641 uint32_t b = uniqueVertexMap[srcIndices[i + 1]];
642 uint32_t c = uniqueVertexMap[srcIndices[i + 2]];
643 if (a != b && b != c && a != c) {
644 indices.emplace_back(a);
645 indices.emplace_back(b);
646 indices.emplace_back(c);
652 const uint32_t* srcIndices = (
const uint32_t*)indexStream.data();
653 for (
size_t i = 0; i + 2 < indexStream.
numElements; i += 3) {
654 uint32_t a = uniqueVertexMap[srcIndices[i + 0]];
655 uint32_t b = uniqueVertexMap[srcIndices[i + 1]];
656 uint32_t c = uniqueVertexMap[srcIndices[i + 2]];
657 if (a != b && b != c && a != c) {
658 indices.emplace_back(a);
659 indices.emplace_back(b);
660 indices.emplace_back(c);
666 assert(
false &&
"Illegal index size");
671 size_t inVertexCount = uniqueVertexMap.size();
672 indices.reserve(inVertexCount);
673 for (
size_t i = 0; i + 2 < inVertexCount; i += 3) {
674 uint32_t a = uniqueVertexMap[i + 0];
675 uint32_t b = uniqueVertexMap[i + 1];
676 uint32_t c = uniqueVertexMap[i + 2];
677 if (a != b && b != c && a != c) {
678 indices.emplace_back(a);
679 indices.emplace_back(b);
680 indices.emplace_back(c);
691 const Cogs::Geometry::BoundingBox& bbox,
696 const size_t vertexCount,
697 const std::vector<uint32_t>& indexData,
698 const uint32_t dstIndexTypeSize,
699 const uint32_t idOffset)
702 dstMesh->primitiveType = srcMesh->primitiveType;
705 const size_t posFmtSize = Cogs::getSize(posFmtHandle);
706 assert(posVertexData.size() == posFmtSize * vertexCount);
707 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::Interleaved0, posFmtHandle, 0, vertexCount, posFmtSize,
true); dst !=
nullptr) {
708 std::memcpy(dst, posVertexData.data(), posVertexData.size());
709 dstMesh->unmap(VertexDataType::Interleaved0);
717 const size_t idsFmtSize = Cogs::getSize(idsFmtHandle);
718 assert(idsVertexData.size() == idsFmtSize * vertexCount);
719 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::TexCoords0, idsFmtHandle, 0, vertexCount, idsFmtSize,
true); dst !=
nullptr) {
720 std::memcpy(dst, idsVertexData.data(), idsVertexData.size());
721 dstMesh->unmap(VertexDataType::Interleaved0);
730 Cogs::VertexFormatHandle instanceFmtHandle = Cogs::VertexFormats::createVertexFormat(Id32ui_Inst::Fmt, std::size(Id32ui_Inst::Fmt));
731 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::TexCoords1, instanceFmtHandle, 0, 1, Cogs::getSize(instanceFmtHandle),
true); dst !=
nullptr) {
732 std::memcpy(dst, &idOffset,
sizeof(idOffset));
733 dstMesh->unmap(VertexDataType::TexCoords1);
741 const size_t indexCount = indexData.size();
743 if (uint8_t* ptr = dstMesh->mapStream(VertexDataType::Indexes, 0, indexCount, dstIndexTypeSize,
true); ptr !=
nullptr) {
744 switch (dstIndexTypeSize) {
746 uint16_t* dstIndices = (uint16_t*)ptr;
747 for (
size_t i = 0; i < indexCount; i++) {
748 dstIndices[i] = uint16_t(indexData[i]);
753 std::memcpy(ptr, indexData.data(),
sizeof(uint32_t) * indexCount);
759 dstMesh->unmap(VertexDataType::Indexes);
762 dstMesh->setCount(indexCount);
768 dstMesh->setBounds(bbox);
769 return dstMesh.getHandle();
774 const Cogs::Geometry::BoundingBox& bbox,
779 const size_t vertexCount,
780 const std::vector<uint32_t>& indexData,
781 const uint32_t idOffset)
783 const size_t indexCount = indexData.size();
786 dstMesh->primitiveType = srcMesh->primitiveType;
789 const size_t posFmtSize = Cogs::getSize(posFmtHandle);
790 assert(posVertexData.size() == posFmtSize * vertexCount);
791 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::Interleaved0, posFmtHandle, 0, indexCount, posFmtSize,
true); dst !=
nullptr)
793 const uint8_t* src =
static_cast<const uint8_t*
>(posVertexData.data());
794 for (
size_t i = 0; i < indexCount; i++) {
795 const size_t ix = indexData[i];
796 assert(ix < vertexCount);
797 std::memcpy(dst + posFmtSize * i, src + posFmtSize * ix, posFmtSize);
799 dstMesh->unmap(VertexDataType::Interleaved0);
807 const size_t idsFmtSize = Cogs::getSize(idsFmtHandle);
808 assert(idsVertexData.size() == idsFmtSize * vertexCount);
809 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::TexCoords0, idsFmtHandle, 0, indexCount, idsFmtSize,
true); dst !=
nullptr)
811 const uint8_t* src =
static_cast<const uint8_t*
>(idsVertexData.data());
812 for (
size_t i = 0; i < indexCount; i++) {
813 const size_t ix = indexData[i];
814 assert(ix < vertexCount);
815 std::memcpy(dst + idsFmtSize * i, src + idsFmtSize * ix, idsFmtSize);
817 dstMesh->unmap(VertexDataType::TexCoords0);
826 Cogs::VertexFormatHandle instanceFmtHandle = Cogs::VertexFormats::createVertexFormat(Id32ui_Inst::Fmt, std::size(Id32ui_Inst::Fmt));
827 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::TexCoords1, instanceFmtHandle, 0, 1, Cogs::getSize(instanceFmtHandle),
true); dst !=
nullptr) {
828 std::memcpy(dst, &idOffset,
sizeof(idOffset));
829 dstMesh->unmap(VertexDataType::TexCoords1);
836 dstMesh->setBounds(bbox);
837 return dstMesh.getHandle();
845 bool getMeshStreams(
Context* , std::string& status,
846 size_t& srcVertexCount,
853 if (srcMesh ==
nullptr) {
854 status =
"Empty mesh";
860 if (srcMesh->
hasStream(VertexDataType::Positions)) {
865 status =
"Failed to map mesh positions as float3.";
870 status =
"Mesh does not have positions stream.";
875 if (!options.discardNormals && srcMesh->
hasStream(VertexDataType::Normals)) {
878 status =
"Mesh has less normals than positions.";
883 status =
"Failed to map mesh normals as float3.";
889 if (!options.discardTexCoords && srcMesh->
hasStream(VertexDataType::TexCoords0)) {
892 status =
"Mesh has less texcoords than positions.";
897 status =
"Failed to map mesh normals as float3, ignoring.";
909bool Cogs::Core::PackMeshCommand::pack(
Context* context, std::string& status, glm::mat4& transform,
MeshHandle& h,
const Options& options)
912 size_t srcVertexCount = 0;
916 if (!getMeshStreams(context, status, srcVertexCount, srcPos, srcNrm, srcTex, srcMesh, options)) {
920 const bool hasNormals = srcNrm.
isValid();
921 const bool hasTexCoords = srcTex.
isValid();
924 glm::vec3 posMin(std::numeric_limits<float>::max());
925 glm::vec3 posMax(-std::numeric_limits<float>::max());
926 for (
size_t i = 0; i < srcVertexCount; i++) {
927 posMin = glm::min(posMin, srcPos[i]);
928 posMax = glm::max(posMax, srcPos[i]);
930 glm::vec3 extent = posMax - posMin;
931 float scale = std::max(std::max(extent.x, extent.y), extent.z);
932 if (srcVertexCount == 0) {
933 LOG_WARNING(logger,
"No vertices - skipping scaling");
936 else if (scale <= 0.0f) {
937 LOG_WARNING(logger,
"Zero extent(%f) - skipping scaling", scale);
941 const float invScale = 1.f / scale;
946 if (hasTexCoords && 0 < srcVertexCount) {
947 idMin = std::numeric_limits<uint32_t>::max();
948 for (
size_t i = 0; i < srcVertexCount; i++) {
949 uint32_t
id = uint32_t(std::max(0.f, srcTex[i].x));
950 idMin = std::min(idMin,
id);
951 idMax = std::max(idMax,
id);
956 uint32_t idOffset = 0;
957 PackFormat packFormat;
961 status =
"Mesh with texcoords but no normals are currently not supported, ignoring";
965 switch (options.target)
967 case Target::WebGL1_Low:
968 packFormat = PackFormat::Pos16un_Nrm8sn_Id32f;
971 case Target::WebGL2_Low:
973 if (options.allowIdOffset && (0xFFFFu <= idMax) && ((idMax - idMin) < 0xFFFFu)) {
978 if (((idMax - idOffset) < 0xFFFFu)) {
980 packFormat = PackFormat::Pos10un_Nrm8sn_Id16ui;
984 packFormat = PackFormat::Pos16un_Nrm8sn_Id32ui;
988 case Target::WebGL2_Med:
991 if (options.allowIdOffset && (0xFFFFu <= idMax) && ((idMax - idMin) < 0xFFFFu)) {
996 if (!options.allowSeparateIdStream && ((idMax - idOffset) < 0xFFFFu)) {
997 packFormat = PackFormat::Pos16un_Nrm16sn_Id16ui;
1000 packFormat = PackFormat::Pos16un_Nrm8sn_Id32ui;
1005 assert(
false &&
"Invalid enum");
1011 packFormat = hasNormals ? PackFormat::Pos16un_Nrm8sn : PackFormat::Pos10un;
1017 std::vector<uint32_t> remapping;
1021 if (!buildPackedVertices(posFmtHandle,
1025 srcPos, srcNrm, srcTex, srcVertexCount, posMin, invScale, idOffset))
return false;
1027 size_t posFmtSize = Cogs::getSize(posFmtHandle);
1028 const size_t vertexCount = posData.size() / posFmtSize;
1030 std::vector<uint32_t> indices;
1031 if (!buildIndices(indices, remapping, srcMesh))
return false;
1032 const size_t indexCount = indices.size();
1035 if (options.optimizeTriangleOrder) {
1036 std::vector<uint32_t> indices2(indexCount);
1037 meshopt_optimizeVertexCache(indices2.data(), indices.data(), indexCount, vertexCount);
1038 indices.swap(indices2);
1042 if (options.optimizeVertexOrder) {
1043 tmp.resize(posData.size(),
false);
1044 meshopt_optimizeVertexFetch(tmp.data(), indices.data(), indexCount, posData.data(), vertexCount, posFmtSize);
1049 size_t interleavedIdsOffset = 0;
1052 if (hasTexCoords && options.allowSeparateIdStream) {
1053 switch (packFormat) {
1054 case PackFormat::Pos10un_Nrm8sn_Id16ui:
1055 case PackFormat::Pos16un_Nrm16sn_Id16ui:
1058 case PackFormat::Pos16un_Nrm8sn_Id32ui:
1059 interleavedIdsOffset = offsetof(Pos16un_Nrm8sn_Id32ui::Vtx, tex);
1060 newPosFmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn::Fmt, std::size(Pos16un_Nrm8sn::Fmt));
1061 if (idMax - idOffset < 0xFFFFu) {
1062 idsFmtHandle = Cogs::VertexFormats::createVertexFormat(Id16ui::Fmt, std::size(Id16ui::Fmt));
1065 idsFmtHandle = Cogs::VertexFormats::createVertexFormat(Id32ui::Fmt, std::size(Id32ui::Fmt));
1069 case PackFormat::Pos16un_Nrm8sn_Id32f:
1070 interleavedIdsOffset = offsetof(Pos16un_Nrm8sn_Id32f::Vtx, tex);
1071 newPosFmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn::Fmt, std::size(Pos16un_Nrm8sn::Fmt));
1072 idsFmtHandle = Cogs::VertexFormats::createVertexFormat(Id32f::Fmt, std::size(Id32f::Fmt));
1076 assert(
false &&
"Invalid enum value");
1082 size_t idsFmtSize = 0;
1084 if (newPosFmtHandle && idsFmtHandle) {
1085 const size_t newPosFmtSize = Cogs::getSize(newPosFmtHandle);
1086 idsFmtSize = Cogs::getSize(idsFmtHandle);
1088 tmp.resize(newPosFmtSize * vertexCount,
false);
1089 idsData.resize(idsFmtSize * vertexCount,
false);
1091 char* newPosDataPtr =
static_cast<char*
>(tmp.data());
1092 char* idsDataPtr =
static_cast<char*
>(idsData.data());
1093 const char* posDataPtr =
static_cast<char*
>(posData.data());
1094 for (
size_t i = 0; i < vertexCount; i++) {
1095 std::memcpy(newPosDataPtr + newPosFmtSize * i, posDataPtr + posFmtSize * i, newPosFmtSize);
1096 std::memcpy(idsDataPtr + idsFmtSize * i, posDataPtr + posFmtSize * i + interleavedIdsOffset, idsFmtSize);
1101 posFmtHandle = newPosFmtHandle;
1102 posFmtSize = newPosFmtSize;
1105 const uint32_t indexTypeSize = vertexCount < 0xffffu ? 2 : 4;
1106 const size_t indexedSize = (posFmtSize + idsFmtSize) * vertexCount + indexTypeSize * indexCount;
1107 const size_t unindexedSize = (posFmtSize + idsFmtSize) * indexCount;
1109 bool indexed = indexedSize < unindexedSize;
1112 const Cogs::Geometry::BoundingBox bbox{ glm::vec3(0.f), invScale * extent };
1114 h = buildIndexedMesh(context, srcMesh, bbox, posFmtHandle, posData, idsFmtHandle, idsData, vertexCount, indices, indexTypeSize, idOffset);
1117 h = buildUnindexedMesh(context, srcMesh, bbox, posFmtHandle, posData, idsFmtHandle, idsData, vertexCount, indices, idOffset);
1120 glm::vec3 shift = posMin;
1121 transform = glm::mat4(scale, 0.f, 0.f, 0.f,
1122 0.f, scale, 0.f, 0.f,
1123 0.f, 0.f, scale, 0.f,
1124 shift.x, shift.y, shift.z, 1.f);
ComponentType * getComponent() const
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class EntityStore * store
Entity store.
EntityPtr getEntity(const StringView &name, bool logIfNotFound=true) const
Retrieve a reference to the shared entity pointer to the Entity with the given name.
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
ResourceProxy< Mesh, ResourceManager > ResourceProxy
Type of resource proxy objects, specialized on the type of resource.
Contains information on how the entity behaves in the scene.
std::vector< EntityPtr > children
Contains all child entities owned by this component.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
@ InstanceData
Per instance data.
@ VertexData
Per vertex data.
@ Position
Position semantic.
@ TextureCoordinate
Texture coordinate semantic.
Contains a stream of data used by Mesh resources.
uint32_t numElements
Number of elements of the type given by format contained in data.
uint32_t stride
Element stride.
Base class for Cogs Editor commands.
Wrapper for read-only access to mapped stream data.
bool isValid() const
Returns true if stream mapping successful.
@ IndexesChanged
The index data of the mesh changed.
@ Indexed
The mesh should be drawn indexed, using index data to order the triangle vertexes.
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
bool isIndexed() const
If the mesh uses indexed geometry.
bool hasStream(VertexDataType::EVertexDataType type) const
Check if the Mesh has a DataStream for the given type.
MappedStreamReadOnly< glm::vec3 > mapNormalsReadOnly(const size_t start, const size_t end)
Map the normal stream for read access, range between start and end.
DataStream & getStream(const VertexDataType::EVertexDataType dataType)
Get the stream corresponding to the given dataType.
MappedStreamReadOnly< glm::vec3 > mapPositionsReadOnly(const size_t start, const size_t end)
Map the position stream for read access, range between start and end.
MappedStreamReadOnly< glm::vec2 > mapTexCoordsReadOnly(const size_t start, const size_t end)
Map the texture coordinate stream for read access, range between start and end.
void apply() override
Run the command.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
ResourceType * resolve() const
Resolve the handle, returning a pointer to the actual resource.
Vertex element structure used to describe a single data element in a vertex for the input assembler.
uint16_t offset
Offset in bytes from the vertex position in memory.