@@ -77,6 +77,8 @@ namespace Babylon
7777 constexpr uint64_t MULTIPLY = BGFX_STATE_BLEND_FUNC_SEPARATE (BGFX_STATE_BLEND_DST_COLOR , BGFX_STATE_BLEND_ZERO , BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE );
7878 constexpr uint64_t MAXIMIZED = BGFX_STATE_BLEND_FUNC_SEPARATE (BGFX_STATE_BLEND_SRC_ALPHA , BGFX_STATE_BLEND_INV_SRC_COLOR , BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE );
7979 constexpr uint64_t ONEONE = BGFX_STATE_BLEND_FUNC_SEPARATE (BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ZERO , BGFX_STATE_BLEND_ONE );
80+ constexpr uint64_t ONEONE_ONEONE = BGFX_STATE_BLEND_FUNC_SEPARATE (BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE );
81+ constexpr uint64_t LAYER_ACCUMULATE = BGFX_STATE_BLEND_FUNC_SEPARATE (BGFX_STATE_BLEND_SRC_ALPHA , BGFX_STATE_BLEND_INV_SRC_ALPHA , BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_INV_SRC_ALPHA );
8082 constexpr uint64_t PREMULTIPLIED = BGFX_STATE_BLEND_FUNC_SEPARATE (BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_INV_SRC_ALPHA , BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_ONE );
8183 constexpr uint64_t PREMULTIPLIED_PORTERDUFF = BGFX_STATE_BLEND_FUNC_SEPARATE (BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_INV_SRC_ALPHA , BGFX_STATE_BLEND_ONE , BGFX_STATE_BLEND_INV_SRC_ALPHA );
8284 constexpr uint64_t INTERPOLATE = BGFX_STATE_BLEND_FUNC_SEPARATE (BGFX_STATE_BLEND_FACTOR , BGFX_STATE_BLEND_INV_FACTOR , BGFX_STATE_BLEND_FACTOR , BGFX_STATE_BLEND_INV_FACTOR );
@@ -598,6 +600,8 @@ namespace Babylon
598600 StaticValue (" ALPHA_MULTIPLY" , Napi::Number::From (env, AlphaMode::MULTIPLY )),
599601 StaticValue (" ALPHA_MAXIMIZED" , Napi::Number::From (env, AlphaMode::MAXIMIZED )),
600602 StaticValue (" ALPHA_ONEONE" , Napi::Number::From (env, AlphaMode::ONEONE )),
603+ StaticValue (" ALPHA_ONEONE_ONEONE" , Napi::Number::From (env, AlphaMode::ONEONE_ONEONE )),
604+ StaticValue (" ALPHA_LAYER_ACCUMULATE" , Napi::Number::From (env, AlphaMode::LAYER_ACCUMULATE )),
601605 StaticValue (" ALPHA_PREMULTIPLIED" , Napi::Number::From (env, AlphaMode::PREMULTIPLIED )),
602606 StaticValue (" ALPHA_PREMULTIPLIED_PORTERDUFF" , Napi::Number::From (env, AlphaMode::PREMULTIPLIED_PORTERDUFF )),
603607 StaticValue (" ALPHA_INTERPOLATE" , Napi::Number::From (env, AlphaMode::INTERPOLATE )),
@@ -726,6 +730,7 @@ namespace Babylon
726730 InstanceMethod (" resizeImageBitmap" , &NativeEngine::ResizeImageBitmap),
727731
728732 InstanceMethod (" createFrameBuffer" , &NativeEngine::CreateFrameBuffer),
733+ InstanceMethod (" createMultiFrameBuffer" , &NativeEngine::CreateMultiFrameBuffer),
729734
730735 InstanceMethod (" getRenderWidth" , &NativeEngine::GetRenderWidth),
731736 InstanceMethod (" getRenderHeight" , &NativeEngine::GetRenderHeight),
@@ -1912,6 +1917,66 @@ namespace Babylon
19121917 return Napi::Pointer<Graphics::FrameBuffer>::Create (info.Env (), frameBuffer, Napi::NapiPointerDeleter (frameBuffer));
19131918 }
19141919
1920+ Napi::Value NativeEngine::CreateMultiFrameBuffer (const Napi::CallbackInfo& info)
1921+ {
1922+ const auto colorTextures = info[0 ].As <Napi::Array>();
1923+ const uint16_t width = static_cast <uint16_t >(info[1 ].As <Napi::Number>().Uint32Value ());
1924+ const uint16_t height = static_cast <uint16_t >(info[2 ].As <Napi::Number>().Uint32Value ());
1925+ const bool generateStencilBuffer = info[3 ].As <Napi::Boolean>();
1926+ const bool generateDepth = info[4 ].As <Napi::Boolean>();
1927+ const uint32_t samples = info[5 ].IsUndefined () ? 1 : info[5 ].As <Napi::Number>().Uint32Value ();
1928+
1929+ const bgfx::Caps* caps = bgfx::getCaps ();
1930+ const uint32_t colorCount = colorTextures.Length ();
1931+ // One slot per color attachment plus a single depth/stencil attachment. bgfx caps the total via
1932+ // maxFBAttachments; reject out-of-range counts up front rather than relying on the validation assert.
1933+ if (colorCount == 0 || colorCount + 1 > caps->limits .maxFBAttachments )
1934+ {
1935+ throw Napi::Error::New (info.Env (), " Invalid number of color attachments for multi render target frame buffer" );
1936+ }
1937+
1938+ // BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS is 8, so 8 color + 1 depth fits in a fixed array.
1939+ std::array<bgfx::Attachment, 9 > attachments{};
1940+ uint8_t numAttachments = 0 ;
1941+
1942+ for (uint32_t i = 0 ; i < colorCount; ++i)
1943+ {
1944+ const auto texture = colorTextures.Get (i).As <Napi::Pointer<Graphics::Texture>>().Get ();
1945+ attachments[numAttachments++].init (texture->Handle (), bgfx::Access::Write, 0 , 1 , 0
1946+ , 0 != (caps->formats [texture->Format ()] & BGFX_CAPS_FORMAT_TEXTURE_MIP_AUTOGEN ) ? BGFX_RESOLVE_AUTO_GEN_MIPS : BGFX_RESOLVE_NONE
1947+ );
1948+ }
1949+
1950+ bgfx::TextureHandle depthStencilTextureHandle = BGFX_INVALID_HANDLE ;
1951+ int8_t depthStencilAttachmentIndex = -1 ;
1952+ if (generateStencilBuffer || generateDepth)
1953+ {
1954+ auto flags = BGFX_TEXTURE_RT_WRITE_ONLY | RenderTargetSamplesToBgfxMsaaFlag (samples);
1955+ #ifdef ANDROID
1956+ const auto depthStencilFormat{bgfx::TextureFormat::D24S8 };
1957+ #else
1958+ const auto depthStencilFormat{generateStencilBuffer ? bgfx::TextureFormat::D24S8 : bgfx::TextureFormat::D32 };
1959+ #endif
1960+ depthStencilTextureHandle = bgfx::createTexture2D (width, height, false , 1 , depthStencilFormat, flags);
1961+ depthStencilAttachmentIndex = numAttachments;
1962+ attachments[numAttachments++].init (depthStencilTextureHandle, bgfx::Access::Write, 0 , 1 , 0 , BGFX_RESOLVE_NONE );
1963+ }
1964+
1965+ bgfx::FrameBufferHandle frameBufferHandle = bgfx::createFrameBuffer (numAttachments, attachments.data ());
1966+ if (!bgfx::isValid (frameBufferHandle))
1967+ {
1968+ if (bgfx::isValid (depthStencilTextureHandle))
1969+ {
1970+ bgfx::destroy (depthStencilTextureHandle);
1971+ }
1972+
1973+ throw Napi::Error::New (info.Env (), " Failed to create multi render target frame buffer" );
1974+ }
1975+
1976+ Graphics::FrameBuffer* frameBuffer = new Graphics::FrameBuffer (m_deviceContext, frameBufferHandle, width, height, false , generateDepth, generateStencilBuffer, depthStencilAttachmentIndex);
1977+ return Napi::Pointer<Graphics::FrameBuffer>::Create (info.Env (), frameBuffer, Napi::NapiPointerDeleter (frameBuffer));
1978+ }
1979+
19151980 // TODO: This doesn't get called when an Engine instance is disposed.
19161981 void NativeEngine::DeleteFrameBuffer (NativeDataStream::Reader& data)
19171982 {
0 commit comments