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,
183 namespace Pos10un_Nrm8sn_Id16ui {
198 static_assert(
sizeof(Vtx) == 8);
202 .
offset = uint16_t(offsetof(Vtx, pos)),
203 .format = Cogs::Format::R10G10B10A2_UNORM,
210 .offset = uint16_t(offsetof(Vtx, nrm)),
211 .format = Cogs::Format::R8G8_SNORM,
218 .offset = uint16_t(offsetof(Vtx, tex)),
219 .format = Cogs::Format::R16_UINT,
228 namespace Pos16un_Nrm16sn_Id16ui {
235 static_assert(
sizeof(Vtx) == 12);
239 .
offset = uint16_t(offsetof(Vtx, pos)),
240 .format = Cogs::Format::R16G16B16_UNORM,
247 .offset = uint16_t(offsetof(Vtx, nrm)),
248 .format = Cogs::Format::R16G16_SNORM,
255 .offset = uint16_t(offsetof(Vtx, tex)),
256 .format = Cogs::Format::R16_UINT,
265 namespace Pos16un_Nrm8sn_Id32ui {
272 static_assert(
sizeof(Vtx) == 12);
276 .
offset = uint16_t(offsetof(Vtx, pos)),
277 .format = Cogs::Format::R16G16B16_UNORM,
284 .offset = uint16_t(offsetof(Vtx, nrm)),
285 .format = Cogs::Format::R8G8_SNORM,
292 .offset = uint16_t(offsetof(Vtx, tex)),
293 .format = Cogs::Format::R32_UINT,
302 namespace Pos16un_Nrm8sn_Id32f {
309 static_assert(
sizeof(Vtx) == 12);
313 .
offset = uint16_t(offsetof(Vtx, pos)),
314 .format = Cogs::Format::R16G16B16_UNORM,
321 .offset = uint16_t(offsetof(Vtx, nrm)),
322 .format = Cogs::Format::R8G8_SNORM,
329 .offset = uint16_t(offsetof(Vtx, tex)),
330 .format = Cogs::Format::R32_FLOAT,
339 namespace Pos16un_Nrm8sn {
345 static_assert(
sizeof(Vtx) == 8);
349 .
offset = uint16_t(offsetof(Vtx, pos)),
350 .format = Cogs::Format::R16G16B16_UNORM,
357 .offset = uint16_t(offsetof(Vtx, nrm)),
358 .format = Cogs::Format::R8G8_SNORM,
371 .format = Cogs::Format::R16_UINT,
384 .format = Cogs::Format::R32_UINT,
397 .format = Cogs::Format::R32_FLOAT,
406 namespace Id32ui_Inst {
410 .format = Cogs::Format::R32_UINT,
421 if (inVertexData.empty())
return;
423 const char* inVertices = (
const char*)inVertexData.data();
424 const size_t inVertexCount = inVertexData.size() / stride;
426 std::vector<uint32_t> permutation(inVertexCount);
427 for (uint32_t i = 0; i < inVertexCount; i++) {
430 std::sort(permutation.begin(), permutation.end(),
431 [inVertices, stride](
const uint32_t& a,
const uint32_t& b) ->
bool
433 return std::memcmp(&inVertices[stride * a], &inVertices[stride * b], stride) < 0;
436 uniqueVertexData.resize(inVertexData.size());
437 char* uniqueVertices = (
char*)uniqueVertexData.data();
438 size_t currentUniqueVertex = 0;
440 uniqueVertexMap.resize(inVertexCount);
441 uniqueVertexMap[permutation[0]] = uint32_t(currentUniqueVertex);
442 std::memcpy(&uniqueVertices[stride * currentUniqueVertex], &inVertices[stride * permutation[0]], stride);
444 for (
size_t i = 1; i < inVertexCount; i++) {
445 if (std::memcmp(&uniqueVertices[stride * currentUniqueVertex], &inVertices[stride * permutation[i]], stride) != 0) {
446 std::memcpy(&uniqueVertices[stride * (++currentUniqueVertex)], &inVertices[stride * permutation[i]], stride);
448 uniqueVertexMap[permutation[i]] = uint32_t(currentUniqueVertex);
451 const size_t uniqueVertexCount = currentUniqueVertex + 1;
453 assert(uniqueVertexCount <= inVertexCount);
454 uniqueVertexData.resize(stride * uniqueVertexCount);
459 std::vector<uint32_t>& uniqueVertexMap,
460 const PackFormat packFmt,
464 const size_t vertexCount,
465 const glm::vec3& posMin,
466 const float invScale,
467 const uint32_t idOffset)
473 float posFormatScale = 0.f;
476 case PackFormat::Pos10un_Nrm8sn_Id16ui: {
477 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos10un_Nrm8sn_Id16ui::Fmt, std::size(Pos10un_Nrm8sn_Id16ui::Fmt));
478 fmtSize = Cogs::getSize(fmtHandle);
479 assert(
sizeof(Pos10un_Nrm8sn_Id16ui::Vtx) == fmtSize);
480 posFormatScale = 1023.f;
482 vertexData.resize(fmtSize * vertexCount,
false);
483 Pos10un_Nrm8sn_Id16ui::Vtx* vtx = (Pos10un_Nrm8sn_Id16ui::Vtx*)vertexData.data();
484 for (
size_t i = 0; i < vertexCount; i++) {
485 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
486 vtx[i].pos_x = uint32_t(p.x);
487 vtx[i].pos_y = uint32_t(p.y);
488 vtx[i].pos_z = uint32_t(p.z);
490 vtx[i].nrm = octEncodei8(glm::normalize(srcNrm[i]));
491 vtx[i].tex = uint16_t(uint32_t(std::max(0.f, srcTex[i].x)) - idOffset);
494 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
498 case PackFormat::Pos16un_Nrm16sn_Id16ui: {
499 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm16sn_Id16ui::Fmt, std::size(Pos16un_Nrm16sn_Id16ui::Fmt));
500 fmtSize = Cogs::getSize(fmtHandle);
501 assert(
sizeof(Pos16un_Nrm16sn_Id16ui::Vtx) == fmtSize);
502 posFormatScale = std::numeric_limits<uint16_t>::max();
504 vertexData.resize(fmtSize * vertexCount,
false);
505 Pos16un_Nrm16sn_Id16ui::Vtx* vtx = (Pos16un_Nrm16sn_Id16ui::Vtx*)vertexData.data();
506 for (
size_t i = 0; i < vertexCount; i++) {
507 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
508 vtx[i].pos = glm::u16vec3(p);
509 vtx[i].nrm = octEncodei16(glm::normalize(srcNrm[i]));
510 vtx[i].tex = uint16_t(uint32_t(std::max(0.f, srcTex[i].x)) - idOffset);
513 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
517 case PackFormat::Pos16un_Nrm8sn_Id32ui: {
518 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn_Id32ui::Fmt, std::size(Pos16un_Nrm8sn_Id32ui::Fmt));
519 fmtSize = Cogs::getSize(fmtHandle);
520 assert(
sizeof(Pos16un_Nrm8sn_Id32ui::Vtx) == fmtSize);
521 posFormatScale = std::numeric_limits<uint16_t>::max();
523 vertexData.resize(fmtSize * vertexCount,
false);
524 Pos16un_Nrm8sn_Id32ui::Vtx* vtx = (Pos16un_Nrm8sn_Id32ui::Vtx*)vertexData.data();
525 for (
size_t i = 0; i < vertexCount; i++) {
526 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
527 vtx[i].pos = glm::u16vec3(p);
528 vtx[i].nrm = octEncodei8(glm::normalize(srcNrm[i]));
529 vtx[i].tex = uint32_t(std::max(0.f, srcTex[i].x)) - idOffset;
532 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
536 case PackFormat::Pos16un_Nrm8sn_Id32f: {
537 fmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn_Id32f::Fmt, std::size(Pos16un_Nrm8sn_Id32f::Fmt));
538 fmtSize = Cogs::getSize(fmtHandle);
539 assert(
sizeof(Pos16un_Nrm8sn_Id32f::Vtx) == fmtSize);
540 posFormatScale = std::numeric_limits<uint16_t>::max();
542 vertexData.resize(fmtSize * vertexCount,
false);
543 Pos16un_Nrm8sn_Id32f::Vtx* vtx = (Pos16un_Nrm8sn_Id32f::Vtx*)vertexData.data();
544 for (
size_t i = 0; i < vertexCount; i++) {
545 glm::vec3 p = glm::clamp(glm::round(posFormatScale * invScale * (srcPos[i] - posMin)), glm::vec3(0.f), glm::vec3(posFormatScale));
546 vtx[i].pos = glm::u16vec3(p);
547 vtx[i].nrm = octEncodei8(glm::normalize(srcNrm[i]));
548 vtx[i].tex = float(uint32_t(std::max(0.f, srcTex[i].x)) - idOffset);
551 findUniqueVertices(uniqueVertexData, uniqueVertexMap, vertexData, fmtSize);
556 assert(
false &&
"Invalid enum");
563 bool buildIndices(std::vector<uint32_t>& indices,
const std::vector<uint32_t>& uniqueVertexMap,
const Mesh* srcMesh)
570 switch (indexStream.
stride)
573 const uint16_t* srcIndices = (
const uint16_t*)indexStream.data();
574 for (
size_t i = 0; i + 2 < indexStream.
numElements; i += 3) {
575 uint32_t a = uniqueVertexMap[srcIndices[i + 0]];
576 uint32_t b = uniqueVertexMap[srcIndices[i + 1]];
577 uint32_t c = uniqueVertexMap[srcIndices[i + 2]];
578 if (a != b && b != c && a != c) {
579 indices.emplace_back(a);
580 indices.emplace_back(b);
581 indices.emplace_back(c);
587 const uint32_t* srcIndices = (
const uint32_t*)indexStream.data();
588 for (
size_t i = 0; i + 2 < indexStream.
numElements; i += 3) {
589 uint32_t a = uniqueVertexMap[srcIndices[i + 0]];
590 uint32_t b = uniqueVertexMap[srcIndices[i + 1]];
591 uint32_t c = uniqueVertexMap[srcIndices[i + 2]];
592 if (a != b && b != c && a != c) {
593 indices.emplace_back(a);
594 indices.emplace_back(b);
595 indices.emplace_back(c);
601 assert(
false &&
"Illegal index size");
606 size_t inVertexCount = uniqueVertexMap.size();
607 indices.reserve(inVertexCount);
608 for (
size_t i = 0; i + 2 < inVertexCount; i += 3) {
609 uint32_t a = uniqueVertexMap[i + 0];
610 uint32_t b = uniqueVertexMap[i + 1];
611 uint32_t c = uniqueVertexMap[i + 2];
612 if (a != b && b != c && a != c) {
613 indices.emplace_back(a);
614 indices.emplace_back(b);
615 indices.emplace_back(c);
626 const Cogs::Geometry::BoundingBox& bbox,
631 const size_t vertexCount,
632 const std::vector<uint32_t>& indexData,
633 const uint32_t dstIndexTypeSize,
634 const uint32_t idOffset)
637 dstMesh->primitiveType = srcMesh->primitiveType;
640 const size_t posFmtSize = Cogs::getSize(posFmtHandle);
641 assert(posVertexData.size() == posFmtSize * vertexCount);
642 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::Interleaved0, posFmtHandle, 0, vertexCount, posFmtSize,
true); dst !=
nullptr) {
643 std::memcpy(dst, posVertexData.data(), posVertexData.size());
644 dstMesh->unmap(VertexDataType::Interleaved0);
652 const size_t idsFmtSize = Cogs::getSize(idsFmtHandle);
653 assert(idsVertexData.size() == idsFmtSize * vertexCount);
654 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::TexCoords0, idsFmtHandle, 0, vertexCount, idsFmtSize,
true); dst !=
nullptr) {
655 std::memcpy(dst, idsVertexData.data(), idsVertexData.size());
656 dstMesh->unmap(VertexDataType::Interleaved0);
665 Cogs::VertexFormatHandle instanceFmtHandle = Cogs::VertexFormats::createVertexFormat(Id32ui_Inst::Fmt, std::size(Id32ui_Inst::Fmt));
666 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::TexCoords1, instanceFmtHandle, 0, 1, Cogs::getSize(instanceFmtHandle),
true); dst !=
nullptr) {
667 std::memcpy(dst, &idOffset,
sizeof(idOffset));
668 dstMesh->unmap(VertexDataType::TexCoords1);
676 const size_t indexCount = indexData.size();
678 if (uint8_t* ptr = dstMesh->mapStream(VertexDataType::Indexes, 0, indexCount, dstIndexTypeSize,
true); ptr !=
nullptr) {
679 switch (dstIndexTypeSize) {
681 uint16_t* dstIndices = (uint16_t*)ptr;
682 for (
size_t i = 0; i < indexCount; i++) {
683 dstIndices[i] = uint16_t(indexData[i]);
688 std::memcpy(ptr, indexData.data(),
sizeof(uint32_t) * indexCount);
694 dstMesh->unmap(VertexDataType::Indexes);
697 dstMesh->setCount(indexCount);
703 dstMesh->setBounds(bbox);
704 return dstMesh.getHandle();
709 const Cogs::Geometry::BoundingBox& bbox,
714 const size_t vertexCount,
715 const std::vector<uint32_t>& indexData,
716 const uint32_t idOffset)
718 const size_t indexCount = indexData.size();
721 dstMesh->primitiveType = srcMesh->primitiveType;
724 const size_t posFmtSize = Cogs::getSize(posFmtHandle);
725 assert(posVertexData.size() == posFmtSize * vertexCount);
726 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::Interleaved0, posFmtHandle, 0, indexCount, posFmtSize,
true); dst !=
nullptr)
728 const uint8_t* src =
static_cast<const uint8_t*
>(posVertexData.data());
729 for (
size_t i = 0; i < indexCount; i++) {
730 const size_t ix = indexData[i];
731 assert(ix < vertexCount);
732 std::memcpy(dst + posFmtSize * i, src + posFmtSize * ix, posFmtSize);
734 dstMesh->unmap(VertexDataType::Interleaved0);
742 const size_t idsFmtSize = Cogs::getSize(idsFmtHandle);
743 assert(idsVertexData.size() == idsFmtSize * vertexCount);
744 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::TexCoords0, idsFmtHandle, 0, indexCount, idsFmtSize,
true); dst !=
nullptr)
746 const uint8_t* src =
static_cast<const uint8_t*
>(idsVertexData.data());
747 for (
size_t i = 0; i < indexCount; i++) {
748 const size_t ix = indexData[i];
749 assert(ix < vertexCount);
750 std::memcpy(dst + idsFmtSize * i, src + idsFmtSize * ix, idsFmtSize);
752 dstMesh->unmap(VertexDataType::TexCoords0);
761 Cogs::VertexFormatHandle instanceFmtHandle = Cogs::VertexFormats::createVertexFormat(Id32ui_Inst::Fmt, std::size(Id32ui_Inst::Fmt));
762 if (uint8_t* dst = dstMesh->mapStream(VertexDataType::TexCoords1, instanceFmtHandle, 0, 1, Cogs::getSize(instanceFmtHandle),
true); dst !=
nullptr) {
763 std::memcpy(dst, &idOffset,
sizeof(idOffset));
764 dstMesh->unmap(VertexDataType::TexCoords1);
771 dstMesh->setBounds(bbox);
772 return dstMesh.getHandle();
776bool Cogs::Core::PackMeshCommand::pack(
Context* context, std::string& status, glm::mat4& transform,
MeshHandle& h,
const Options& options)
781 if (srcMesh ==
nullptr) {
782 status =
"Empty mesh";
786 size_t srcVertexCount = 0;
789 if (srcMesh->
hasStream(VertexDataType::Positions)) {
794 status =
"Mesh does not have positions stream.";
799 status =
"Failed to map mesh positions as float3.";
804 if (srcMesh->
hasStream(VertexDataType::Normals)) {
807 status =
"Mesh has less normals than positions.";
812 status =
"Mesh does not have normals stream, ignoring";
817 status =
"Failed to map mesh normals as float3.";
822 if (srcMesh->
hasStream(VertexDataType::TexCoords0)) {
825 status =
"Mesh has less texcoords than positions.";
830 status =
"Mesh does not have texcoords stream, ignoring";
835 status =
"Failed to map mesh normals as float3, ignoring.";
840 glm::vec3 posMin(std::numeric_limits<float>::max());
841 glm::vec3 posMax(-std::numeric_limits<float>::max());
842 for (
size_t i = 0; i < srcVertexCount; i++) {
843 posMin = glm::min(posMin, srcPos[i]);
844 posMax = glm::max(posMax, srcPos[i]);
846 glm::vec3 extent = posMax - posMin;
847 float scale = std::max(std::max(extent.x, extent.y), extent.z);
848 if (srcVertexCount == 0) {
849 LOG_WARNING(logger,
"No vertices - skipping scaling");
852 else if (scale <= 0.0f) {
853 LOG_WARNING(logger,
"Zero extent(%f) - skipping scaling", scale);
857 const float invScale = 1.f / scale;
862 if (0 < srcVertexCount) {
863 idMin = std::numeric_limits<uint32_t>::max();
864 for (
size_t i = 0; i < srcVertexCount; i++) {
865 uint32_t
id = uint32_t(std::max(0.f, srcTex[i].x));
866 idMin = std::min(idMin,
id);
867 idMax = std::max(idMax,
id);
872 uint32_t idOffset = 0;
873 PackFormat packFormat;
874 switch (options.target)
876 case Target::WebGL1_Low:
877 packFormat = PackFormat::Pos16un_Nrm8sn_Id32f;
880 case Target::WebGL2_Low:
882 if (options.allowIdOffset && (0xFFFFu <= idMax) && ((idMax - idMin) < 0xFFFFu)) {
887 if (((idMax - idOffset) < 0xFFFFu)) {
889 packFormat = PackFormat::Pos10un_Nrm8sn_Id16ui;
893 packFormat = PackFormat::Pos16un_Nrm8sn_Id32ui;
897 case Target::WebGL2_Med:
900 if (options.allowIdOffset && (0xFFFFu <= idMax) && ((idMax - idMin) < 0xFFFFu)) {
905 if (!options.allowSeparateIdStream && ((idMax - idOffset) < 0xFFFFu)) {
906 packFormat = PackFormat::Pos16un_Nrm16sn_Id16ui;
909 packFormat = PackFormat::Pos16un_Nrm8sn_Id32ui;
914 assert(
false &&
"Invalid enum");
920 std::vector<uint32_t> remapping;
924 if (!buildPackedVertices(posFmtHandle,
928 srcPos, srcNrm, srcTex, srcVertexCount, posMin, invScale, idOffset))
return false;
930 size_t posFmtSize = Cogs::getSize(posFmtHandle);
931 const size_t vertexCount = posData.size() / posFmtSize;
933 std::vector<uint32_t> indices;
934 if (!buildIndices(indices, remapping, srcMesh))
return false;
935 const size_t indexCount = indices.size();
938 if (options.optimizeTriangleOrder) {
939 std::vector<uint32_t> indices2(indexCount);
940 meshopt_optimizeVertexCache(indices2.data(), indices.data(), indexCount, vertexCount);
941 indices.swap(indices2);
945 if (options.optimizeVertexOrder) {
946 tmp.resize(posData.size(),
false);
947 meshopt_optimizeVertexFetch(tmp.data(), indices.data(), indexCount, posData.data(), vertexCount, posFmtSize);
952 size_t interleavedIdsOffset = 0;
955 if (options.allowSeparateIdStream) {
956 switch (packFormat) {
957 case PackFormat::Pos10un_Nrm8sn_Id16ui:
958 case PackFormat::Pos16un_Nrm16sn_Id16ui:
961 case PackFormat::Pos16un_Nrm8sn_Id32ui:
962 interleavedIdsOffset = offsetof(Pos16un_Nrm8sn_Id32ui::Vtx, tex);
963 newPosFmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn::Fmt, std::size(Pos16un_Nrm8sn::Fmt));
964 if (idMax - idOffset < 0xFFFFu) {
965 idsFmtHandle = Cogs::VertexFormats::createVertexFormat(Id16ui::Fmt, std::size(Id16ui::Fmt));
968 idsFmtHandle = Cogs::VertexFormats::createVertexFormat(Id32ui::Fmt, std::size(Id32ui::Fmt));
972 case PackFormat::Pos16un_Nrm8sn_Id32f:
973 interleavedIdsOffset = offsetof(Pos16un_Nrm8sn_Id32f::Vtx, tex);
974 newPosFmtHandle = Cogs::VertexFormats::createVertexFormat(Pos16un_Nrm8sn::Fmt, std::size(Pos16un_Nrm8sn::Fmt));
975 idsFmtHandle = Cogs::VertexFormats::createVertexFormat(Id32f::Fmt, std::size(Id32f::Fmt));
979 assert(
false &&
"Invalid enum value");
985 size_t idsFmtSize = 0;
987 if (newPosFmtHandle && idsFmtHandle) {
988 const size_t newPosFmtSize = Cogs::getSize(newPosFmtHandle);
989 idsFmtSize = Cogs::getSize(idsFmtHandle);
991 tmp.resize(newPosFmtSize * vertexCount,
false);
992 idsData.resize(idsFmtSize * vertexCount,
false);
994 char* newPosDataPtr =
static_cast<char*
>(tmp.data());
995 char* idsDataPtr =
static_cast<char*
>(idsData.data());
996 const char* posDataPtr =
static_cast<char*
>(posData.data());
997 for (
size_t i = 0; i < vertexCount; i++) {
998 std::memcpy(newPosDataPtr + newPosFmtSize * i, posDataPtr + posFmtSize * i, newPosFmtSize);
999 std::memcpy(idsDataPtr + idsFmtSize * i, posDataPtr + posFmtSize * i + interleavedIdsOffset, idsFmtSize);
1004 posFmtHandle = newPosFmtHandle;
1005 posFmtSize = newPosFmtSize;
1008 const uint32_t indexTypeSize = vertexCount < 0xffffu ? 2 : 4;
1009 const size_t indexedSize = (posFmtSize + idsFmtSize) * vertexCount + indexTypeSize * indexCount;
1010 const size_t unindexedSize = (posFmtSize + idsFmtSize) * indexCount;
1012 bool indexed = indexedSize < unindexedSize;
1015 const Cogs::Geometry::BoundingBox bbox{ glm::vec3(0.f), invScale * extent };
1017 h = buildIndexedMesh(context, srcMesh, bbox, posFmtHandle, posData, idsFmtHandle, idsData, vertexCount, indices, indexTypeSize, idOffset);
1020 h = buildUnindexedMesh(context, srcMesh, bbox, posFmtHandle, posData, idsFmtHandle, idsData, vertexCount, indices, idOffset);
1023 glm::vec3 shift = posMin;
1024 transform = glm::mat4(scale, 0.f, 0.f, 0.f,
1025 0.f, scale, 0.f, 0.f,
1026 0.f, 0.f, scale, 0.f,
1027 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.