@@ -41,6 +41,8 @@ namespace cage
4141 Texture *getTextureDummy2d (GraphicsDevice *device);
4242 Texture *getTextureDummyArray (GraphicsDevice *device);
4343 Texture *getTextureDummyCube (GraphicsDevice *device);
44+ GpuBuffer *getBufferDummyUniform (GraphicsDevice *device);
45+ GpuBuffer *getBufferDummyStorage (GraphicsDevice *device);
4446
4547 namespace detail
4648 {
@@ -410,7 +412,7 @@ namespace cage
410412 return HashString (" MaterialTexRegular" );
411413 }
412414
413- CAGE_FORCE_INLINE static Holder<Shader> pickShaderVariant (MultiShader *multiShader, Texture *first, const RenderModel &rm , const RenderModeEnum renderMode )
415+ CAGE_FORCE_INLINE static Holder<Shader> pickShaderVariant (MultiShader *multiShader, Texture *first, const RenderModeEnum renderMode , const MeshRenderFlags meshFlags, const bool skeletalAnimation )
414416 {
415417 CAGE_ASSERT (multiShader);
416418 uint32 variant = 0 ;
@@ -422,9 +424,9 @@ namespace cage
422424 v (materialShaderVariant (first));
423425 if (renderMode != RenderModeEnum::Color)
424426 v (HashString (" DepthOnly" ));
425- if (any (rm. mesh -> flags & MeshRenderFlags::CutOut))
427+ if (any (meshFlags & MeshRenderFlags::CutOut))
426428 v (HashString (" CutOut" ));
427- if (rm. skeletalAnimation )
429+ if (skeletalAnimation)
428430 v (HashString (" SkeletalAnimation" ));
429431 return multiShader->get (variant);
430432 }
@@ -452,7 +454,7 @@ namespace cage
452454 Texture *first = firstTexture (textures);
453455
454456 Holder<MultiShader> multiShader = rm.mesh ->shaderName ? assets->get <MultiShader>(rm.mesh ->shaderName ) : shaderStandard.share ();
455- Holder<Shader> shader = pickShaderVariant (+multiShader, first, rm, renderMode );
457+ Holder<Shader> shader = pickShaderVariant (+multiShader, first, renderMode, rm. mesh -> flags , !!rm. skeletalAnimation );
456458
457459 Holder<GpuBuffer> buffOptions = newGpuBufferUniform (device, " UniOptions" );
458460 {
@@ -542,7 +544,6 @@ namespace cage
542544
543545 void renderIcons (const RenderModeEnum renderMode, const PointerRange<const RenderData> instances) const
544546 {
545- /*
546547 CAGE_ASSERT (!instances.empty ());
547548 const RenderData &rd = instances[0 ];
548549 CAGE_ASSERT (std::holds_alternative<RenderIcon>(rd.data ));
@@ -553,115 +554,83 @@ namespace cage
553554 const Holder<Model> &mesh = std::get<RenderIcon>(rd.data ).mesh ;
554555 const Holder<Texture> &texture = std::get<RenderIcon>(rd.data ).texture ;
555556
556- Holder<Shader> shader = [&]()
557+ Holder<MultiShader> multiShader = mesh->shaderName ? assets->get <MultiShader>(mesh->shaderName ) : shaderIcon.share ();
558+ Holder<Shader> shader = pickShaderVariant (+multiShader, +texture, renderMode, mesh->flags , false );
559+
560+ Holder<GpuBuffer> buffOptions = newGpuBufferUniform (device, " UniOptions" );
557561 {
558- if (mesh->shaderName)
559- {
560- uint32 variant = 0;
561- if (any(mesh->flags & MeshRenderFlags::CutOut))
562- variant += HashString("CutOut");
563- return assets->get<MultiShader>(mesh->shaderName)->get(variant);
564- }
565- else
566- {
567- if (texture->target() == GL_TEXTURE_2D_ARRAY)
568- {
569- if (any(mesh->flags & MeshRenderFlags::CutOut))
570- return shaderIconCutOutAnimated.share();
571- else
572- return shaderIconAnimated.share();
573- }
574- else
575- {
576- if (any(mesh->flags & MeshRenderFlags::CutOut))
577- return shaderIconCutOut.share();
578- else
579- return shaderIcon.share();
580- }
581- }
582- }();
583- renderQueue->bind(shader);
562+ UniOptions uniOptions;
563+ buffOptions->write (uniOptions);
564+ }
584565
585- renderQueue->culling(none(mesh->flags & MeshRenderFlags::TwoSided));
586- renderQueue->depthTest(any(mesh->flags & MeshRenderFlags::DepthTest));
587- renderQueue->depthWrite(any(mesh->flags & MeshRenderFlags::DepthWrite));
588- renderQueue->depthFuncLessEqual();
589- renderQueue->blending(rd.translucent);
590- if (rd.translucent)
591- renderQueue->blendFuncAlphaTransparency();
566+ uniMeshes.clear ();
567+ uniMeshes.reserve (instances.size ());
568+ CAGE_ASSERT (multiShader->customDataCount <= 16 );
569+ uniCustomData.clear ();
570+ if (multiShader->customDataCount )
571+ uniCustomData.reserve (multiShader->customDataCount * instances.size ());
592572
593- switch (texture->target() )
573+ for ( const auto &inst : instances )
594574 {
595- case GL_TEXTURE_2D_ARRAY:
596- renderQueue->bind(texture, CAGE_SHADER_TEXTURE_ALBEDO_ARRAY);
597- break;
598- case GL_TEXTURE_CUBE_MAP:
599- renderQueue->bind(texture, CAGE_SHADER_TEXTURE_ALBEDO_CUBE);
600- break;
601- default:
602- renderQueue->bind(texture, CAGE_SHADER_TEXTURE_ALBEDO);
603- break;
575+ CAGE_ASSERT (std::holds_alternative<RenderIcon>(inst.data ));
576+ CAGE_ASSERT (+std::get<RenderIcon>(inst.data ).mesh == +mesh);
577+ CAGE_ASSERT (+std::get<RenderIcon>(inst.data ).texture == +texture);
578+ uniMeshes.push_back (makeMeshUni (inst));
579+ appendShaderCustomData (inst.e , multiShader->customDataCount );
604580 }
605581
606- // separate instances into draw calls by the limit
607- const uint32 limit = CAGE_SHADER_MAX_MESHES;
608- for (uint32 offset = 0; offset < instances.size(); offset += limit)
609- {
610- const uint32 count = min(limit, numeric_cast<uint32>(instances.size()) - offset);
611- uniMeshes.clear();
612- uniMeshes.reserve(count);
613- CAGE_ASSERT(shader->customDataCount <= 16);
614- uniCustomData.clear();
615- if (shader->customDataCount)
616- uniCustomData.reserve(shader->customDataCount * count);
617-
618- for (const auto &inst : subRange(instances, offset, count))
619- {
620- CAGE_ASSERT(std::holds_alternative<RenderIcon>(inst.data));
621- CAGE_ASSERT(+std::get<RenderIcon>(inst.data).mesh == +mesh);
622- CAGE_ASSERT(+std::get<RenderIcon>(inst.data).texture == +texture);
623- uniMeshes.push_back(makeMeshUni(inst));
624- appendShaderCustomData(inst.e, shader->customDataCount);
625- }
582+ // webgpu does not accept empty buffers
583+ if (uniCustomData.empty ())
584+ uniCustomData.resize (4 );
626585
627- renderQueue->universalUniformArray<const UniMesh>(uniMeshes, CAGE_SHADER_UNIBLOCK_MESHES );
628- if (!uniCustomData.empty())
629- renderQueue->universalUniformArray<const float>(uniCustomData, CAGE_SHADER_UNIBLOCK_CUSTOMDATA);
630- renderQueue->draw(mesh, count );
631- }
586+ Holder<GpuBuffer> buffMeshes = newGpuBufferStorage (device, " UniMeshes " );
587+ buffMeshes-> write (PointerRange< const UniMesh>(uniMeshes));
588+
589+ Holder<GpuBuffer> buffCustom = newGpuBufferStorage (device, " UniCustomData " );
590+ buffCustom-> write (PointerRange< const float >(uniCustomData));
632591
633- renderQueue->checkGlErrorDebug();
634- */
592+ prepareModelBindings (device, assets, +mesh); // todo remove
593+
594+ BindingsCreateConfig bind;
595+ bind.buffers .push_back ({ +buffOptions, 0 });
596+ bind.buffers .push_back ({ +buffMeshes, 1 });
597+ bind.buffers .push_back ({ getBufferDummyStorage (device), 2 });
598+ bind.buffers .push_back ({ +buffCustom, 3 });
599+
600+ DrawConfig draw;
601+ draw.depthTest = any (mesh->flags & MeshRenderFlags::DepthTest) ? wgpu::CompareFunction::LessEqual : wgpu::CompareFunction::Always;
602+ draw.depthWrite = any (mesh->flags & MeshRenderFlags::DepthWrite);
603+ draw.blending = rd.translucent ? BlendingEnum::AlphaTransparency : BlendingEnum::None;
604+ draw.backFaceCulling = none (mesh->flags & MeshRenderFlags::TwoSided);
605+ draw.model = +mesh;
606+ draw.shader = +shader;
607+ draw.bindings = newGpuBindings (device, bind);
608+ draw.instances = instances.size ();
609+ encoder->draw (draw);
635610 }
636611
637612 void renderTexts (const RenderModeEnum renderMode, const PointerRange<const RenderData> instances) const
638613 {
639- /*
640614 CAGE_ASSERT (!instances.empty ());
641615 const RenderData &rd = instances[0 ];
642616 CAGE_ASSERT (std::holds_alternative<RenderText>(rd.data ));
643617
644618 if (renderMode != RenderModeEnum::Color)
645619 return ;
646620
647- renderQueue->depthTest(true);
648- renderQueue->depthWrite(false);
649- renderQueue->culling(true);
650- renderQueue->blending(true);
651- renderQueue->blendFuncAlphaTransparency();
652- renderQueue->bind(shaderText);
653-
654621 for (const auto &it : instances)
655622 {
656623 CAGE_ASSERT (std::holds_alternative<RenderText>(it.data ));
624+ FontRenderConfig cfg;
625+ cfg.transform = viewProj * it.model ;
626+ cfg.color = it.color ;
627+ cfg.queue = +encoder;
628+ cfg.assets = onDemand;
629+ cfg.depthTest = true ;
630+ cfg.guiShader = false ;
657631 const RenderText &t = std::get<RenderText>(it.data );
658- renderQueue->uniform(shaderText, 0, viewProj * it.model);
659- renderQueue->uniform(shaderText, 4, Vec3(it.color)); // todo opacity
660- t.font->render(+renderQueue, onDemand, t.layout);
632+ t.font ->render (t.layout , cfg);
661633 }
662-
663- renderQueue->checkGlErrorDebug();
664- */
665634 }
666635
667636 void renderInstances (const RenderModeEnum renderMode, const PointerRange<const RenderData> instances) const
@@ -1376,14 +1345,15 @@ namespace cage
13761345
13771346 GpuBindings globalBindings;
13781347 {
1348+ GpuBuffer *dummyStorage = getBufferDummyStorage (device);
13791349 Texture *dummyRegular = getTextureDummy2d (device);
13801350 Texture *dummyArray = getTextureDummyArray (device);
13811351 Texture *dummyCube = getTextureDummyCube (device);
13821352 BindingsCreateConfig bind;
13831353 bind.buffers .push_back ({ +buffViewport, 0 });
13841354 bind.buffers .push_back ({ +buffProjection, 1 });
1385- bind.buffers .push_back ({ +buffLights , 2 });
1386- bind.buffers .push_back ({ +buffLights , 3 });
1355+ bind.buffers .push_back ({ dummyStorage , 2 });
1356+ bind.buffers .push_back ({ dummyStorage , 3 });
13871357 bind.textures .push_back ({ dummyRegular, 4 });
13881358 bind.textures .push_back ({ dummyRegular, 6 });
13891359 for (uint32 i = 0 ; i < 8 ; i++)
0 commit comments