652 lines
22 KiB
C++
652 lines
22 KiB
C++
#include "MetaCoreRender/MetaCoreImGuiHelper.h"
|
|
#include "MetaCoreRender/MetaCoreRuntimeUiRenderer.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
#include <imgui.h>
|
|
|
|
#include <filament/Camera.h>
|
|
#include <filament/Fence.h>
|
|
#include <filament/IndexBuffer.h>
|
|
#include <filament/Material.h>
|
|
#include <filament/MaterialInstance.h>
|
|
#include <filament/RenderableManager.h>
|
|
#include <filament/Scene.h>
|
|
#include <filament/Texture.h>
|
|
#include <filament/TextureSampler.h>
|
|
#include <filament/TransformManager.h>
|
|
#include <filament/VertexBuffer.h>
|
|
|
|
#include <utils/EntityManager.h>
|
|
|
|
using namespace filament::math;
|
|
using namespace filament;
|
|
using namespace utils;
|
|
|
|
using MinFilter = TextureSampler::MinFilter;
|
|
using MagFilter = TextureSampler::MagFilter;
|
|
|
|
namespace MetaCore {
|
|
|
|
MetaCoreImGuiHelper::MetaCoreImGuiHelper(Engine* engine, filament::View* view, const std::filesystem::path& fontPath,
|
|
ImGuiContext *imGuiContext)
|
|
: mEngine(engine), mView(view), mScene(engine->createScene()),
|
|
mImGuiContext(imGuiContext ? imGuiContext : ImGui::CreateContext()),
|
|
mOwnsImGuiContext(imGuiContext == nullptr) {
|
|
|
|
ImGui::SetCurrentContext(mImGuiContext);
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
|
|
// 加载我们编译好的材质
|
|
std::ifstream file("uiBlit.filamat", std::ios::binary);
|
|
if (!file.is_open()) {
|
|
file.open("../uiBlit.filamat", std::ios::binary);
|
|
}
|
|
if (!file.is_open()) {
|
|
file.open("build/uiBlit.filamat", std::ios::binary);
|
|
}
|
|
|
|
if (!file.is_open()) {
|
|
std::cerr << "MetaCoreImGuiHelper: Failed to open uiBlit.filamat from any expected location!" << std::endl;
|
|
}
|
|
|
|
std::vector<char> buffer((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
|
|
|
if (buffer.empty()) {
|
|
std::cerr << "MetaCoreImGuiHelper: Material buffer is empty! Skipping material creation to avoid crash." << std::endl;
|
|
mMaterial2d = nullptr;
|
|
} else {
|
|
mMaterial2d = Material::Builder()
|
|
.package(buffer.data(), buffer.size())
|
|
.build(*engine);
|
|
}
|
|
|
|
if (!fontPath.empty() && std::filesystem::exists(fontPath)) {
|
|
io.Fonts->AddFontFromFileTTF(fontPath.string().c_str(), 16.0f, nullptr, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
|
}
|
|
createAtlasTexture(engine);
|
|
|
|
utils::EntityManager& em = utils::EntityManager::get();
|
|
mCameraEntity = em.create();
|
|
mCamera = mEngine->createCamera(mCameraEntity);
|
|
|
|
view->setCamera(mCamera);
|
|
view->setPostProcessingEnabled(false);
|
|
view->setBlendMode(View::BlendMode::TRANSLUCENT);
|
|
view->setShadowingEnabled(false);
|
|
|
|
// 绑定场景
|
|
view->setScene(mScene);
|
|
|
|
mRenderable = em.create();
|
|
mScene->addEntity(mRenderable);
|
|
|
|
ImGui::StyleColorsDark();
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::createAtlasTexture(Engine* engine) {
|
|
if (mTexture) {
|
|
engine->destroy(mTexture);
|
|
}
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
unsigned char* pixels;
|
|
int width, height;
|
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
|
size_t size = (size_t) (width * height * 4);
|
|
|
|
Texture::PixelBufferDescriptor pb(
|
|
pixels, size,
|
|
Texture::Format::RGBA, Texture::Type::UBYTE);
|
|
|
|
mTexture = Texture::Builder()
|
|
.width((uint32_t) width)
|
|
.height((uint32_t) height)
|
|
.levels((uint8_t) 1)
|
|
.format(Texture::InternalFormat::RGBA8)
|
|
.sampler(Texture::Sampler::SAMPLER_2D)
|
|
.build(*engine);
|
|
|
|
mTexture->setImage(*engine, 0, std::move(pb));
|
|
|
|
mSampler = TextureSampler(MinFilter::LINEAR, MagFilter::LINEAR);
|
|
if (mMaterial2d) {
|
|
mMaterial2d->setDefaultParameter("albedo", mTexture, mSampler);
|
|
}
|
|
|
|
}
|
|
|
|
MetaCoreImGuiHelper::~MetaCoreImGuiHelper() {
|
|
if (mView != nullptr) {
|
|
mView->setScene(nullptr);
|
|
mView->setCamera(nullptr);
|
|
}
|
|
if (mScene != nullptr) {
|
|
mScene->remove(mRenderable);
|
|
}
|
|
|
|
for (auto& mi : mMaterial2dInstances) {
|
|
if (mi != nullptr) {
|
|
mEngine->destroy(mi);
|
|
}
|
|
}
|
|
mMaterial2dInstances.clear();
|
|
|
|
if (mMaterial2d != nullptr) {
|
|
mEngine->destroy(mMaterial2d);
|
|
mMaterial2d = nullptr;
|
|
}
|
|
if (mTexture != nullptr) {
|
|
mEngine->destroy(mTexture);
|
|
mTexture = nullptr;
|
|
}
|
|
if (mWhiteTexture != nullptr) {
|
|
mEngine->destroy(mWhiteTexture);
|
|
mWhiteTexture = nullptr;
|
|
}
|
|
|
|
for (auto& vb : mVertexBuffers) {
|
|
if (vb != nullptr) {
|
|
mEngine->destroy(vb);
|
|
}
|
|
}
|
|
mVertexBuffers.clear();
|
|
for (auto& ib : mIndexBuffers) {
|
|
if (ib != nullptr) {
|
|
mEngine->destroy(ib);
|
|
}
|
|
}
|
|
mIndexBuffers.clear();
|
|
|
|
for (auto* texture : mImGuiTextures) {
|
|
if (texture != nullptr) {
|
|
mEngine->destroy(texture);
|
|
}
|
|
}
|
|
mImGuiTextures.clear();
|
|
for (auto& [handle, textureState] : mRuntimeUiTextures) {
|
|
(void)handle;
|
|
if (textureState.Texture != nullptr) {
|
|
mEngine->destroy(textureState.Texture);
|
|
textureState.Texture = nullptr;
|
|
}
|
|
}
|
|
mRuntimeUiTextures.clear();
|
|
|
|
if (mScene != nullptr) {
|
|
mEngine->destroy(mScene);
|
|
mScene = nullptr;
|
|
}
|
|
mEngine->destroy(mRenderable);
|
|
if (mCamera != nullptr) {
|
|
mEngine->destroyCameraComponent(mCameraEntity);
|
|
mCamera = nullptr;
|
|
}
|
|
|
|
EntityManager& em = utils::EntityManager::get();
|
|
em.destroy(mRenderable);
|
|
em.destroy(mCameraEntity);
|
|
|
|
if (mImGuiContext == ImGui::GetCurrentContext()) {
|
|
ImGui::SetCurrentContext(nullptr);
|
|
}
|
|
if (mOwnsImGuiContext) {
|
|
ImGui::DestroyContext(mImGuiContext);
|
|
}
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::setDisplaySize(int width, int height, float scaleX, float scaleY,
|
|
bool flipVertical) {
|
|
if (width <= 0 || height <= 0) {
|
|
return;
|
|
}
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
io.DisplaySize = ImVec2(width, height);
|
|
io.DisplayFramebufferScale.x = scaleX;
|
|
io.DisplayFramebufferScale.y = scaleY;
|
|
mFlipVertical = flipVertical;
|
|
|
|
if (flipVertical) {
|
|
mCamera->setProjection(Camera::Projection::ORTHO, 0.0, double(width),
|
|
0.0, double(height), 0.0, 1.0);
|
|
} else {
|
|
mCamera->setProjection(Camera::Projection::ORTHO, 0.0, double(width),
|
|
double(height), 0.0, 0.0, 1.0);
|
|
}
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::render(float timeStepInSeconds, Callback imguiCommands) {
|
|
ImGui::SetCurrentContext(mImGuiContext);
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
io.DeltaTime = timeStepInSeconds;
|
|
|
|
ImGui::NewFrame();
|
|
imguiCommands(mEngine, mView);
|
|
ImGui::Render();
|
|
|
|
processImGuiCommands(ImGui::GetDrawData(), ImGui::GetIO());
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::processImGuiCommands(ImDrawData* commands, const ImGuiIO& io) {
|
|
ImGui::SetCurrentContext(mImGuiContext);
|
|
|
|
mHasSynced = false;
|
|
auto& rcm = mEngine->getRenderableManager();
|
|
|
|
int fbwidth = (int)(io.DisplaySize.x * io.DisplayFramebufferScale.x);
|
|
int fbheight = (int)(io.DisplaySize.y * io.DisplayFramebufferScale.y);
|
|
if (fbwidth == 0 || fbheight == 0)
|
|
return;
|
|
commands->ScaleClipRects(io.DisplayFramebufferScale);
|
|
|
|
createBuffers(commands->CmdListsCount);
|
|
|
|
size_t nPrims = 0;
|
|
for (int cmdListIndex = 0; cmdListIndex < commands->CmdListsCount; cmdListIndex++) {
|
|
const ImDrawList* cmds = commands->CmdLists[cmdListIndex];
|
|
nPrims += cmds->CmdBuffer.size();
|
|
}
|
|
|
|
auto rbuilder = RenderableManager::Builder(nPrims);
|
|
rbuilder.boundingBox({{ 0, 0, 0 }, { 10000, 10000, 10000 }}).culling(false);
|
|
|
|
rcm.destroy(mRenderable);
|
|
int bufferIndex = 0;
|
|
int primIndex = 0;
|
|
int material2dIndex = 0;
|
|
|
|
for (int cmdListIndex = 0; cmdListIndex < commands->CmdListsCount; cmdListIndex++) {
|
|
const ImDrawList* cmds = commands->CmdLists[cmdListIndex];
|
|
populateVertexData(bufferIndex,
|
|
cmds->VtxBuffer.Size * sizeof(ImDrawVert), cmds->VtxBuffer.Data,
|
|
cmds->IdxBuffer.Size * sizeof(ImDrawIdx), cmds->IdxBuffer.Data);
|
|
|
|
for (const auto& pcmd : cmds->CmdBuffer) {
|
|
if (pcmd.UserCallback) {
|
|
pcmd.UserCallback(cmds, &pcmd);
|
|
} else {
|
|
auto texture = (Texture const*)pcmd.GetTexID();
|
|
MaterialInstance* materialInstance;
|
|
|
|
if (material2dIndex == mMaterial2dInstances.size()) {
|
|
if (mMaterial2d) {
|
|
mMaterial2dInstances.push_back(mMaterial2d->createInstance());
|
|
} else {
|
|
mMaterial2dInstances.push_back(nullptr);
|
|
}
|
|
}
|
|
materialInstance = mMaterial2dInstances[material2dIndex++];
|
|
|
|
if (materialInstance) {
|
|
auto scissorLeft = static_cast<uint32_t>(std::max(0.0f, pcmd.ClipRect.x));
|
|
auto scissorBottom = static_cast<uint32_t>(std::max(0.0f,
|
|
mFlipVertical ? pcmd.ClipRect.y : (fbheight - pcmd.ClipRect.w)));
|
|
auto scissorWidth = static_cast<uint32_t>(pcmd.ClipRect.z - pcmd.ClipRect.x);
|
|
auto scissorHeight = static_cast<uint32_t>(pcmd.ClipRect.w - pcmd.ClipRect.y);
|
|
|
|
materialInstance->setScissor(scissorLeft, scissorBottom, scissorWidth, scissorHeight);
|
|
|
|
if (texture) {
|
|
TextureSampler sampler(MinFilter::LINEAR, MagFilter::LINEAR);
|
|
materialInstance->setParameter("albedo", texture, sampler);
|
|
} else {
|
|
materialInstance->setParameter("albedo", mTexture, mSampler);
|
|
}
|
|
|
|
rbuilder
|
|
.geometry(primIndex, RenderableManager::PrimitiveType::TRIANGLES,
|
|
mVertexBuffers[bufferIndex], mIndexBuffers[bufferIndex],
|
|
pcmd.IdxOffset, pcmd.ElemCount)
|
|
.blendOrder(primIndex, primIndex)
|
|
.material(primIndex, materialInstance);
|
|
primIndex++;
|
|
}
|
|
}
|
|
}
|
|
bufferIndex++;
|
|
}
|
|
if (commands->CmdListsCount > 0) {
|
|
rbuilder.build(*mEngine, mRenderable);
|
|
}
|
|
}
|
|
|
|
filament::Texture* MetaCoreImGuiHelper::getWhiteTexture() {
|
|
if (mWhiteTexture != nullptr) {
|
|
return mWhiteTexture;
|
|
}
|
|
|
|
const std::uint8_t whitePixel[4] = {255, 255, 255, 255};
|
|
void* whitePixelData = malloc(sizeof(whitePixel));
|
|
if (whitePixelData == nullptr) {
|
|
return nullptr;
|
|
}
|
|
std::memcpy(whitePixelData, whitePixel, sizeof(whitePixel));
|
|
|
|
Texture::PixelBufferDescriptor whitePixelBuffer(
|
|
whitePixelData,
|
|
sizeof(whitePixel),
|
|
Texture::Format::RGBA,
|
|
Texture::Type::UBYTE,
|
|
[](void* buffer, size_t, void*) {
|
|
free(buffer);
|
|
},
|
|
nullptr);
|
|
|
|
mWhiteTexture = Texture::Builder()
|
|
.width(1)
|
|
.height(1)
|
|
.levels(1)
|
|
.format(Texture::InternalFormat::RGBA8)
|
|
.sampler(Texture::Sampler::SAMPLER_2D)
|
|
.build(*mEngine);
|
|
mWhiteTexture->setImage(*mEngine, 0, std::move(whitePixelBuffer));
|
|
return mWhiteTexture;
|
|
}
|
|
|
|
filament::Texture* MetaCoreImGuiHelper::syncRuntimeUiTexture(const MetaCoreRuntimeUiFrame& frame, std::uint64_t handle) {
|
|
if (handle == 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
const auto textureIterator = std::find_if(
|
|
frame.Textures.begin(),
|
|
frame.Textures.end(),
|
|
[handle](const MetaCoreRuntimeUiTexture& texture) {
|
|
return texture.Handle == handle;
|
|
});
|
|
if (textureIterator == frame.Textures.end()) {
|
|
return nullptr;
|
|
}
|
|
|
|
const MetaCoreRuntimeUiTexture& texture = *textureIterator;
|
|
if (texture.Width <= 0 || texture.Height <= 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
const std::size_t expectedByteCount =
|
|
static_cast<std::size_t>(texture.Width) * static_cast<std::size_t>(texture.Height) * 4U;
|
|
if (expectedByteCount == 0 || texture.Rgba.size() < expectedByteCount) {
|
|
return nullptr;
|
|
}
|
|
|
|
RuntimeUiTextureState& state = mRuntimeUiTextures[handle];
|
|
if (state.Texture != nullptr &&
|
|
state.Width == texture.Width &&
|
|
state.Height == texture.Height &&
|
|
state.Revision == texture.Revision) {
|
|
return state.Texture;
|
|
}
|
|
|
|
if (state.Texture != nullptr) {
|
|
mEngine->destroy(state.Texture);
|
|
state.Texture = nullptr;
|
|
}
|
|
|
|
void* pixelData = malloc(expectedByteCount);
|
|
if (pixelData == nullptr) {
|
|
return nullptr;
|
|
}
|
|
std::memcpy(pixelData, texture.Rgba.data(), expectedByteCount);
|
|
|
|
Texture::PixelBufferDescriptor pixelBuffer(
|
|
pixelData,
|
|
expectedByteCount,
|
|
Texture::Format::RGBA,
|
|
Texture::Type::UBYTE,
|
|
[](void* buffer, size_t, void*) {
|
|
free(buffer);
|
|
},
|
|
nullptr);
|
|
|
|
state.Texture = Texture::Builder()
|
|
.width(static_cast<uint32_t>(texture.Width))
|
|
.height(static_cast<uint32_t>(texture.Height))
|
|
.levels(1)
|
|
.format(Texture::InternalFormat::RGBA8)
|
|
.sampler(Texture::Sampler::SAMPLER_2D)
|
|
.build(*mEngine);
|
|
state.Texture->setImage(*mEngine, 0, std::move(pixelBuffer));
|
|
state.Width = texture.Width;
|
|
state.Height = texture.Height;
|
|
state.Revision = texture.Revision;
|
|
return state.Texture;
|
|
}
|
|
|
|
bool MetaCoreImGuiHelper::processRuntimeUiFrame(const MetaCoreRuntimeUiFrame& frame, int width, int height) {
|
|
ImGui::SetCurrentContext(mImGuiContext);
|
|
|
|
mHasSynced = false;
|
|
auto& rcm = mEngine->getRenderableManager();
|
|
rcm.destroy(mRenderable);
|
|
|
|
if (width <= 0 || height <= 0) {
|
|
return false;
|
|
}
|
|
if (frame.Commands.empty() || frame.Vertices.empty() || frame.Indices.empty()) {
|
|
return true;
|
|
}
|
|
if (frame.Vertices.size() > static_cast<std::size_t>(std::numeric_limits<std::uint16_t>::max())) {
|
|
return false;
|
|
}
|
|
|
|
std::unordered_set<std::uint64_t> activeTextureHandles;
|
|
activeTextureHandles.reserve(frame.Textures.size());
|
|
for (const MetaCoreRuntimeUiTexture& texture : frame.Textures) {
|
|
if (texture.Handle != 0) {
|
|
activeTextureHandles.insert(texture.Handle);
|
|
}
|
|
}
|
|
for (auto iterator = mRuntimeUiTextures.begin(); iterator != mRuntimeUiTextures.end();) {
|
|
if (activeTextureHandles.contains(iterator->first)) {
|
|
++iterator;
|
|
continue;
|
|
}
|
|
if (iterator->second.Texture != nullptr) {
|
|
mEngine->destroy(iterator->second.Texture);
|
|
}
|
|
iterator = mRuntimeUiTextures.erase(iterator);
|
|
}
|
|
|
|
createBuffers(1);
|
|
|
|
std::vector<ImDrawVert> vertices;
|
|
vertices.reserve(frame.Vertices.size());
|
|
for (const MetaCoreRuntimeUiDrawVertex& vertex : frame.Vertices) {
|
|
ImDrawVert converted{};
|
|
converted.pos = ImVec2(vertex.X, vertex.Y);
|
|
converted.uv = ImVec2(vertex.U, vertex.V);
|
|
converted.col = IM_COL32(vertex.R, vertex.G, vertex.B, vertex.A);
|
|
vertices.push_back(converted);
|
|
}
|
|
|
|
std::vector<std::uint16_t> indices;
|
|
indices.reserve(frame.Indices.size());
|
|
for (const std::uint32_t index : frame.Indices) {
|
|
if (index > static_cast<std::uint32_t>(std::numeric_limits<std::uint16_t>::max())) {
|
|
return false;
|
|
}
|
|
indices.push_back(static_cast<std::uint16_t>(index));
|
|
}
|
|
|
|
populateVertexData(
|
|
0,
|
|
vertices.size() * sizeof(ImDrawVert),
|
|
vertices.data(),
|
|
indices.size() * sizeof(std::uint16_t),
|
|
indices.data());
|
|
|
|
std::size_t primitiveCount = 0;
|
|
for (const MetaCoreRuntimeUiDrawCommand& command : frame.Commands) {
|
|
if (command.IndexCount == 0 ||
|
|
command.VertexCount == 0 ||
|
|
command.VertexOffset + command.VertexCount > frame.Vertices.size() ||
|
|
command.IndexOffset + command.IndexCount > frame.Indices.size()) {
|
|
continue;
|
|
}
|
|
++primitiveCount;
|
|
}
|
|
if (primitiveCount == 0) {
|
|
return true;
|
|
}
|
|
|
|
auto rbuilder = RenderableManager::Builder(primitiveCount);
|
|
rbuilder.boundingBox({{ 0, 0, 0 }, { 10000, 10000, 10000 }}).culling(false);
|
|
|
|
int primitiveIndex = 0;
|
|
int material2dIndex = 0;
|
|
for (const MetaCoreRuntimeUiDrawCommand& command : frame.Commands) {
|
|
if (command.IndexCount == 0 ||
|
|
command.VertexCount == 0 ||
|
|
command.VertexOffset + command.VertexCount > frame.Vertices.size() ||
|
|
command.IndexOffset + command.IndexCount > frame.Indices.size()) {
|
|
continue;
|
|
}
|
|
|
|
if (material2dIndex == static_cast<int>(mMaterial2dInstances.size())) {
|
|
if (mMaterial2d) {
|
|
mMaterial2dInstances.push_back(mMaterial2d->createInstance());
|
|
} else {
|
|
mMaterial2dInstances.push_back(nullptr);
|
|
}
|
|
}
|
|
MaterialInstance* materialInstance = mMaterial2dInstances[material2dIndex++];
|
|
if (!materialInstance) {
|
|
continue;
|
|
}
|
|
|
|
if (command.ScissorEnabled) {
|
|
const int left = std::clamp(command.ScissorLeft, 0, width);
|
|
const int top = std::clamp(command.ScissorTop, 0, height);
|
|
const int right = std::clamp(command.ScissorRight, left, width);
|
|
const int bottom = std::clamp(command.ScissorBottom, top, height);
|
|
materialInstance->setScissor(
|
|
static_cast<uint32_t>(left),
|
|
static_cast<uint32_t>(height - bottom),
|
|
static_cast<uint32_t>(right - left),
|
|
static_cast<uint32_t>(bottom - top));
|
|
} else {
|
|
materialInstance->unsetScissor();
|
|
}
|
|
|
|
filament::Texture* runtimeTexture = syncRuntimeUiTexture(frame, command.TextureHandle);
|
|
filament::Texture* fallbackTexture = getWhiteTexture();
|
|
materialInstance->setParameter(
|
|
"albedo",
|
|
runtimeTexture != nullptr ? runtimeTexture : (fallbackTexture != nullptr ? fallbackTexture : mTexture),
|
|
mSampler);
|
|
|
|
rbuilder
|
|
.geometry(primitiveIndex, RenderableManager::PrimitiveType::TRIANGLES,
|
|
mVertexBuffers[0], mIndexBuffers[0],
|
|
static_cast<std::uint32_t>(command.IndexOffset),
|
|
static_cast<std::uint32_t>(command.IndexCount))
|
|
.blendOrder(primitiveIndex, static_cast<std::uint16_t>(primitiveIndex))
|
|
.material(primitiveIndex, materialInstance);
|
|
++primitiveIndex;
|
|
}
|
|
|
|
if (primitiveIndex > 0) {
|
|
rbuilder.build(*mEngine, mRenderable);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::createVertexBuffer(size_t bufferIndex, size_t capacity) {
|
|
syncThreads();
|
|
if (bufferIndex < mVertexBuffers.size() && mVertexBuffers[bufferIndex]) {
|
|
mEngine->destroy(mVertexBuffers[bufferIndex]);
|
|
}
|
|
|
|
mVertexBuffers[bufferIndex] = VertexBuffer::Builder()
|
|
.vertexCount(capacity)
|
|
.bufferCount(1)
|
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT2, 0,
|
|
sizeof(ImDrawVert))
|
|
.attribute(VertexAttribute::UV0, 0, VertexBuffer::AttributeType::FLOAT2,
|
|
sizeof(filament::math::float2), sizeof(ImDrawVert))
|
|
.attribute(VertexAttribute::COLOR, 0, VertexBuffer::AttributeType::UBYTE4,
|
|
2 * sizeof(filament::math::float2), sizeof(ImDrawVert))
|
|
.normalized(VertexAttribute::COLOR)
|
|
.build(*mEngine);
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::createIndexBuffer(size_t bufferIndex, size_t capacity) {
|
|
syncThreads();
|
|
if (bufferIndex < mIndexBuffers.size() && mIndexBuffers[bufferIndex]) {
|
|
mEngine->destroy(mIndexBuffers[bufferIndex]);
|
|
}
|
|
|
|
mIndexBuffers[bufferIndex] = IndexBuffer::Builder()
|
|
.indexCount(capacity)
|
|
.bufferType(IndexBuffer::IndexType::USHORT)
|
|
.build(*mEngine);
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::createBuffers(int numRequiredBuffers) {
|
|
if (numRequiredBuffers > mVertexBuffers.size()) {
|
|
size_t previousSize = mVertexBuffers.size();
|
|
mVertexBuffers.resize(numRequiredBuffers, nullptr);
|
|
for (size_t i = previousSize; i < mVertexBuffers.size(); i++) {
|
|
createVertexBuffer(i, 1000);
|
|
}
|
|
}
|
|
if (numRequiredBuffers > mIndexBuffers.size()) {
|
|
size_t previousSize = mIndexBuffers.size();
|
|
mIndexBuffers.resize(numRequiredBuffers, nullptr);
|
|
for (size_t i = previousSize; i < mIndexBuffers.size(); i++) {
|
|
createIndexBuffer(i, 5000);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::populateVertexData(size_t bufferIndex, size_t vbSizeInBytes, void* vbImguiData,
|
|
size_t ibSizeInBytes, void* ibImguiData)
|
|
{
|
|
size_t requiredVertCount = vbSizeInBytes / sizeof(ImDrawVert);
|
|
size_t capacityVertCount = mVertexBuffers[bufferIndex]->getVertexCount();
|
|
if (requiredVertCount > capacityVertCount) {
|
|
createVertexBuffer(bufferIndex, requiredVertCount);
|
|
}
|
|
size_t nVbBytes = requiredVertCount * sizeof(ImDrawVert);
|
|
void* vbFilamentData = malloc(nVbBytes);
|
|
memcpy(vbFilamentData, vbImguiData, nVbBytes);
|
|
mVertexBuffers[bufferIndex]->setBufferAt(*mEngine, 0,
|
|
VertexBuffer::BufferDescriptor(vbFilamentData, nVbBytes,
|
|
[](void* buffer, size_t size, void* user) {
|
|
free(buffer);
|
|
}, /* user = */ nullptr));
|
|
|
|
size_t requiredIndexCount = ibSizeInBytes / 2;
|
|
size_t capacityIndexCount = mIndexBuffers[bufferIndex]->getIndexCount();
|
|
if (requiredIndexCount > capacityIndexCount) {
|
|
createIndexBuffer(bufferIndex, requiredIndexCount);
|
|
}
|
|
size_t nIbBytes = requiredIndexCount * 2;
|
|
void* ibFilamentData = malloc(nIbBytes);
|
|
memcpy(ibFilamentData, ibImguiData, nIbBytes);
|
|
mIndexBuffers[bufferIndex]->setBuffer(*mEngine,
|
|
IndexBuffer::BufferDescriptor(ibFilamentData, nIbBytes,
|
|
[](void* buffer, size_t size, void* user) {
|
|
free(buffer);
|
|
}, /* user = */ nullptr));
|
|
}
|
|
|
|
void MetaCoreImGuiHelper::syncThreads() {
|
|
#if UTILS_HAS_THREADING
|
|
if (!mHasSynced) {
|
|
Fence::waitAndDestroy(mEngine->createFence());
|
|
mHasSynced = true;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
} // namespace MetaCore
|