54 inline static const uint N_TEXTURE_TYPES =
67 mutable bool mVertexQuadBufferGenerated =
false;
75 Lines mWireframeLines;
80 std::map<std::string, Texture> mMaterialTextures;
84 std::array<Uniform, N_TEXTURE_TYPES> mTextureSamplerUniforms;
113 swap(mVertexPositionsBuffer,
other.mVertexPositionsBuffer);
114 swap(mVertexNormalsBuffer,
other.mVertexNormalsBuffer);
115 swap(mVertexColorsBuffer,
other.mVertexColorsBuffer);
116 swap(mVertexUVBuffer,
other.mVertexUVBuffer);
117 swap(mVertexWedgeUVBuffer,
other.mVertexWedgeUVBuffer);
118 swap(mVertexTangentsBuffer,
other.mVertexTangentsBuffer);
119 swap(mVertexQuadIndexBuffer,
other.mVertexQuadIndexBuffer);
120 swap(mVertexQuadBuffer,
other.mVertexQuadBuffer);
121 swap(mVertexQuadBufferGenerated,
other.mVertexQuadBufferGenerated);
122 swap(mTriangleIndexBuffer,
other.mTriangleIndexBuffer);
123 swap(mTriangleNormalBuffer,
other.mTriangleNormalBuffer);
124 swap(mTriangleColorBuffer,
other.mTriangleColorBuffer);
125 swap(mEdgeLines,
other.mEdgeLines);
126 swap(mWireframeLines,
other.mWireframeLines);
127 swap(mMaterialTextures,
other.mMaterialTextures);
128 swap(mMeshUniforms,
other.mMeshUniforms);
129 swap(mMaterialUniforms,
other.mMaterialUniforms);
130 swap(mTextureSamplerUniforms,
other.mTextureSamplerUniforms);
135 uint triangleChunksNumber()
const {
return Base::mMaterialChunks.
size(); }
138 void computeQuadVertexBuffers(
140 const bgfx::ViewId viewId)
const
142 if (!mVertexQuadBuffer.isValid() || mVertexQuadBufferGenerated) {
148 VCL_MRB_VERTEX_POSITION_STREAM, bgfx::Access::Read);
150 VCL_MRB_VERTEX_NORMAL_STREAM, bgfx::Access::Read);
152 VCL_MRB_VERTEX_COLOR_STREAM, bgfx::Access::Read);
154 mVertexQuadBuffer.
bindCompute(4, bgfx::Access::Write);
159 pm.getComputeProgram<ComputeProgram::DRAWABLE_MESH_POINTS>(),
164 mVertexQuadBufferGenerated =
true;
172 mVertexPositionsBuffer.bindVertex(
stream++);
174 if (mVertexNormalsBuffer.isValid()) {
175 mVertexNormalsBuffer.bindVertex(
stream++);
178 if (mVertexColorsBuffer.isValid()) {
179 mVertexColorsBuffer.bindVertex(
stream++);
182 if (mVertexUVBuffer.isValid()) {
186 if (mVertexWedgeUVBuffer.isValid()) {
190 if (mVertexTangentsBuffer.isValid()) {
196 void bindVertexQuadBuffer()
const
198 mVertexQuadBuffer.
bind(VCL_MRB_VERTEX_POSITION_STREAM);
199 mVertexQuadIndexBuffer.
bind();
202 void bindIndexBuffers(
206 using enum MRI::Buffers;
209 mTriangleIndexBuffer.
bind();
210 mMeshUniforms.updateFirstChunkIndex(0);
214 mMeshUniforms.updateFirstChunkIndex(
chunk.startIndex);
215 mTriangleIndexBuffer.
bind(
219 mTriangleNormalBuffer.
bind(VCL_MRB_PRIMITIVE_NORMAL_BUFFER);
221 mTriangleColorBuffer.
bind(VCL_MRB_PRIMITIVE_COLOR_BUFFER);
224 void drawEdgeLines(uint viewId)
const { mEdgeLines.
draw(viewId); }
226 void drawWireframeLines(uint viewId)
const { mWireframeLines.
draw(viewId); }
236 for (uint
j = 0;
j < N_TEXTURE_TYPES; ++
j) {
238 const std::string& path =
td.path();
240 const Texture&
tex = mMaterialTextures.at(path);
244 VCL_MRB_TEXTURE0 +
j,
245 mTextureSamplerUniforms[
j].handle(),
276 mMaterialUniforms.update(
278 isPerVertexColorAvailable(
m),
280 isPerVertexTangentAvailable(
m));
289 mMaterialUniforms.update(
291 isPerVertexColorAvailable(
m),
293 isPerVertexTangentAvailable(
m));
299 for (uint
j = 0;
j < N_TEXTURE_TYPES; ++
j) {
302 const std::string& path =
td.path();
304 const Texture&
tex = mMaterialTextures.at(path);
309 mMaterialUniforms.update(
311 isPerVertexColorAvailable(
m),
313 isPerVertexTangentAvailable(
m));
320 if (
m.material(
materialId).alphaMode() == ALPHA_BLEND) {
326 mMaterialUniforms.bind();
333 using enum Lines::ColorToUse;
338 if (
mrs.isEdges(COLOR_USER)) {
342 else if (mrs.
isEdges(COLOR_MESH)) {
346 else if (mrs.
isEdges(COLOR_VERTEX)) {
349 else if (mrs.
isEdges(COLOR_EDGE)) {
354 void updateWireframeSettings(
const MeshRenderSettings& mrs)
357 using enum Lines::ColorToUse;
359 mWireframeLines.
thickness() = mrs.wireframeWidth();
360 mWireframeLines.
setShading(mrs.isWireframe(SHADING_VERT));
362 if (mrs.isWireframe(COLOR_USER)) {
363 mWireframeLines.
generalColor() = mrs.wireframeUserColor();
366 else if (mrs.isWireframe(COLOR_MESH)) {
370 else if (mrs.isWireframe(COLOR_VERTEX)) {
375 void bindUniforms()
const { mMeshUniforms.bind(); }
378 void setVertexPositionsBuffer(
const MeshType& mesh)
380 uint nv = Base::numVerts();
382 auto [buffer, releaseFn] =
383 getAllocatedBufferAndReleaseFn<float>(nv * 3);
385 Base::fillVertexPositions(mesh, buffer);
390 bgfx::Attrib::Position,
392 PrimitiveType::FLOAT,
401 bgfx::VertexLayout layout;
403 .
add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
404 .
add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8,
true)
405 .
add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float)
406 .
add(bgfx::Attrib::TexCoord0, 1, bgfx::AttribType::Float)
411 mesh.vertexNumber() * 4, layout, BGFX_BUFFER_COMPUTE_WRITE);
417 mVertexQuadBufferGenerated =
false;
434 Base::fillVertexQuadIndices(mesh, buffer);
442 void setVertexNormalsBuffer(
const MeshType& mesh)
444 uint
nv = Base::numVerts();
449 Base::fillVertexNormals(mesh, buffer);
454 bgfx::Attrib::Normal,
456 PrimitiveType::FLOAT,
462 void setVertexColorsBuffer(
const MeshType& mesh)
464 uint nv = Base::numVerts();
466 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nv);
468 Base::fillVertexColors(mesh, buffer, Color::Format::ABGR);
473 bgfx::Attrib::Color0,
475 PrimitiveType::UCHAR,
481 void setVertexTexCoordsBuffer(
const MeshType& mesh)
483 uint nv = Base::numVerts();
485 auto [buffer, releaseFn] =
486 getAllocatedBufferAndReleaseFn<float>(nv * 2);
488 Base::fillVertexTexCoords(mesh, buffer);
493 bgfx::Attrib::TexCoord0,
495 PrimitiveType::FLOAT,
500 void setVertexTangentsBuffer(
const MeshType& mesh)
502 uint nv = Base::numVerts();
504 auto [buffer, releaseFn] =
505 getAllocatedBufferAndReleaseFn<float>(nv * 4);
507 Base::fillVertexTangents(mesh, buffer);
509 mVertexTangentsBuffer.
create(
512 bgfx::Attrib::Tangent,
514 PrimitiveType::FLOAT,
519 void setWedgeTexCoordsBuffer(
const MeshType& mesh)
521 uint nv = Base::numVerts();
523 auto [buffer, releaseFn] =
524 getAllocatedBufferAndReleaseFn<float>(nv * 2);
526 Base::fillWedgeTexCoords(mesh, buffer);
528 mVertexWedgeUVBuffer.
create(
531 bgfx::Attrib::TexCoord1,
533 PrimitiveType::FLOAT,
538 void setTriangleIndicesBuffer(
const MeshType& mesh)
540 uint nt = Base::numTris();
542 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nt * 3);
544 Base::fillTriangleIndices(mesh, buffer);
546 mTriangleIndexBuffer.
create(buffer, nt * 3,
true, releaseFn);
549 void setTriangleNormalsBuffer(
const MeshType& mesh)
551 uint nt = Base::numTris();
553 auto [buffer, releaseFn] =
554 getAllocatedBufferAndReleaseFn<float>(nt * 3);
556 Base::fillTriangleNormals(mesh, buffer);
561 PrimitiveType::FLOAT,
566 void setTriangleColorsBuffer(
const MeshType& mesh)
568 uint nt = Base::numTris();
570 auto [buffer, releaseFn] = getAllocatedBufferAndReleaseFn<uint>(nt);
572 Base::fillTriangleColors(mesh, buffer, Color::Format::ABGR);
575 buffer, nt, PrimitiveType::UINT, bgfx::Access::Read, releaseFn);
578 void setEdgeIndicesBuffer(
const MeshType& mesh)
580 computeEdgeLines(mesh);
583 void setWireframeIndicesBuffer(
const MeshType& mesh)
585 computeWireframeLines(mesh);
588 void setTextures(
const MeshType& mesh)
591 auto setTexture = [&](
const Image& img,
592 const std::string& path,
594 const uint size = img.width() * img.height();
597 uint sizeWithMips = bimg::imageGetSize(
605 bimg::TextureFormat::RGBA8) /
609 numMips = bimg::imageGetNumMips(
610 bimg::TextureFormat::RGBA8, img.width(), img.height());
612 auto [buffer, releaseFn] =
613 getAllocatedBufferAndReleaseFn<uint>(sizeWithMips);
615 const uint* tdata =
reinterpret_cast<const uint*
>(img.data());
617 std::copy(tdata, tdata + size, buffer);
620 uint* source = buffer;
623 for (uint mip = 1; mip < numMips; mip++) {
624 dest = source + offset;
625 uint mipSize = (img.width() >> mip) * (img.height() >> mip);
626 bimg::imageRgba8Downsample2x2(
628 img.width() >> (mip - 1),
629 img.height() >> (mip - 1),
631 (img.width() >> (mip - 1)) * 4,
632 (img.width() >> mip) * 4,
640 uint64_t flags = BGFX_TEXTURE_NONE | BGFX_SAMPLER_NONE;
642 if (img.colorSpace() == Image::ColorSpace::SRGB)
643 flags |= BGFX_TEXTURE_SRGB;
654 mMaterialTextures.at(path) = std::move(tex);
657 auto loadImageAndSetTexture =
658 [&](
const std::pair<std::string, uint>& pathPair) {
659 const std::string& path = pathPair.first;
661 uint materialId = pathPair.second / N_TEXTURE_TYPES;
662 uint textureType = pathPair.second % N_TEXTURE_TYPES;
668 txtImg = vcl::loadImage(mesh.meshBasePath() + path);
683 const TextureDescriptor& tex =
684 mesh.material(materialId)
685 .textureDescriptor(textureType);
692 minFilter >= NEAREST_MIPMAP_NEAREST ||
696 setTexture(txtImg, path, hasMips);
700 mMaterialTextures.clear();
708 std::map<std::string, uint> texturePaths;
709 for (uint i = 0; i < mesh.materialsNumber(); ++i) {
710 for (uint j = 0; j < N_TEXTURE_TYPES; ++j) {
712 mesh.material(i).textureDescriptor(j);
713 if (!td.
path().empty()) {
714 texturePaths[td.
path()] = i * N_TEXTURE_TYPES + j;
719 mMaterialTextures[td.
path()] = Texture();
725 std::vector<std::pair<std::string, uint>> texturePathVec;
726 texturePathVec.reserve(texturePaths.size());
727 for (
const auto& tp : texturePaths) {
728 texturePathVec.push_back(tp);
731 parallelFor(texturePathVec, loadImageAndSetTexture);
733 createTextureSamplerUniforms();
737 void setMeshUniforms(
const MeshType& mesh)
739 mMeshUniforms.update(mesh);
740 if constexpr (HasColor<MeshType>) {
741 mMeshColor = mesh.color();
745 void computeEdgeLines(
const MeshType& mesh)
750 const uint nv = Base::numVerts();
751 std::vector<float> positions(nv * 3);
752 Base::fillVertexPositions(mesh, positions.data());
755 const uint ne = Base::numEdges();
756 std::vector<uint> indices(ne * 2);
757 Base::fillEdgeIndices(mesh, indices.data());
760 std::vector<float> normals;
761 if (mVertexNormalsBuffer.isValid()) {
762 normals.resize(nv * 3);
763 Base::fillVertexNormals(mesh, normals.data());
769 std::vector<uint> vcolors;
770 if (mVertexColorsBuffer.isValid()) {
772 Base::fillVertexColors(mesh, vcolors.data(), Color::Format::ABGR);
775 std::vector<uint> ecolors;
781 Base::fillEdgeColors(mesh, ecolors.data(), Color::Format::ABGR);
786 mEdgeLines.
setPoints(positions, indices, normals, vcolors, ecolors);
792 void computeWireframeLines(
const MeshType& mesh)
797 const uint nv = Base::numVerts();
798 std::vector<float> positions(nv * 3);
799 Base::fillVertexPositions(mesh, positions.data());
802 const uint nw = Base::numWireframeLines();
803 std::vector<uint> indices(nw * 2);
804 Base::fillWireframeIndices(mesh, indices.data());
807 std::vector<float> normals;
808 if (mVertexNormalsBuffer.isValid()) {
809 normals.resize(nv * 3);
810 Base::fillVertexNormals(mesh, normals.data());
814 std::vector<uint> vcolors;
815 if (mVertexColorsBuffer.isValid()) {
817 Base::fillVertexColors(mesh, vcolors.data(), Color::Format::ABGR);
820 mWireframeLines.
setPoints(positions, indices, normals, vcolors, {});
825 void createTextureSamplerUniforms()
827 for (uint i = 0; i < mTextureSamplerUniforms.size(); ++i) {
828 mTextureSamplerUniforms[i] = Uniform(
829 Material::TEXTURE_TYPE_NAMES[i].c_str(),
830 bgfx::UniformType::Sampler);
835 std::pair<T*, bgfx::ReleaseFn> getAllocatedBufferAndReleaseFn(uint size)
837 T* buffer =
new T[size];
839 return std::make_pair(buffer, [](
void* ptr,
void*) {
840 delete[]
static_cast<T*
>(ptr);