composite texture - checkerboard
This commit is contained in:
parent
3b9fa5569b
commit
a86741cb3b
|
@ -17,9 +17,10 @@ const ResourceType Animation::TYPE("animation");
|
|||
|
||||
Animation::Animation(const Path& path, ResourceManager& resource_manager, IAllocator& allocator)
|
||||
: Resource(path, resource_manager, allocator)
|
||||
, m_mem(allocator)
|
||||
, m_translations(allocator)
|
||||
, m_rotations(allocator)
|
||||
, m_allocator(allocator, m_path.c_str())
|
||||
, m_mem(m_allocator)
|
||||
, m_translations(m_allocator)
|
||||
, m_rotations(m_allocator)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "engine/allocators.h"
|
||||
#include "engine/hash.h"
|
||||
#include "engine/hash_map.h"
|
||||
#include "engine/resource.h"
|
||||
|
@ -47,70 +48,68 @@ struct BoneMask
|
|||
};
|
||||
|
||||
|
||||
struct Animation final : Resource
|
||||
{
|
||||
public:
|
||||
static const u32 HEADER_MAGIC = 0x5f4c4146; // '_LAF'
|
||||
static const ResourceType TYPE;
|
||||
struct Animation final : Resource {
|
||||
static const u32 HEADER_MAGIC = 0x5f4c4146; // '_LAF'
|
||||
static const ResourceType TYPE;
|
||||
|
||||
public:
|
||||
enum class CurveType : u8 {
|
||||
KEYFRAMED,
|
||||
SAMPLED
|
||||
};
|
||||
enum class CurveType : u8 {
|
||||
KEYFRAMED,
|
||||
SAMPLED
|
||||
};
|
||||
|
||||
enum class Version : u32 {
|
||||
FIRST = 3,
|
||||
enum class Version : u32 {
|
||||
FIRST = 3,
|
||||
|
||||
LAST
|
||||
};
|
||||
LAST
|
||||
};
|
||||
|
||||
struct Header {
|
||||
u32 magic;
|
||||
Version version;
|
||||
Time length;
|
||||
u32 frame_count;
|
||||
};
|
||||
struct Header {
|
||||
u32 magic;
|
||||
Version version;
|
||||
Time length;
|
||||
u32 frame_count;
|
||||
};
|
||||
|
||||
public:
|
||||
Animation(const Path& path, ResourceManager& resource_manager, IAllocator& allocator);
|
||||
Animation(const Path& path, ResourceManager& resource_manager, IAllocator& allocator);
|
||||
|
||||
ResourceType getType() const override { return TYPE; }
|
||||
ResourceType getType() const override { return TYPE; }
|
||||
|
||||
Vec3 getTranslation(Time time, u32 curve_idx) const;
|
||||
Quat getRotation(Time time, u32 curve_idx) const;
|
||||
int getTranslationCurveIndex(BoneNameHash name_hash) const;
|
||||
int getRotationCurveIndex(BoneNameHash name_hash) const;
|
||||
void getRelativePose(Time time, Pose& pose, const Model& model, const BoneMask* mask) const;
|
||||
void getRelativePose(Time time, Pose& pose, const Model& model, float weight, const BoneMask* mask) const;
|
||||
Time getLength() const { return m_length; }
|
||||
Vec3 getTranslation(Time time, u32 curve_idx) const;
|
||||
Quat getRotation(Time time, u32 curve_idx) const;
|
||||
int getTranslationCurveIndex(BoneNameHash name_hash) const;
|
||||
int getRotationCurveIndex(BoneNameHash name_hash) const;
|
||||
void getRelativePose(Time time, Pose& pose, const Model& model, const BoneMask* mask) const;
|
||||
void getRelativePose(Time time, Pose& pose, const Model& model, float weight, const BoneMask* mask) const;
|
||||
Time getLength() const { return m_length; }
|
||||
|
||||
private:
|
||||
void unload() override;
|
||||
bool load(u64 size, const u8* mem) override;
|
||||
private:
|
||||
void unload() override;
|
||||
bool load(u64 size, const u8* mem) override;
|
||||
|
||||
private:
|
||||
Time m_length;
|
||||
struct TranslationCurve
|
||||
{
|
||||
BoneNameHash name;
|
||||
u32 count;
|
||||
const u16* times;
|
||||
const Vec3* pos;
|
||||
};
|
||||
struct RotationCurve
|
||||
{
|
||||
BoneNameHash name;
|
||||
u32 count;
|
||||
const u16* times;
|
||||
const Quat* rot;
|
||||
};
|
||||
Array<TranslationCurve> m_translations;
|
||||
Array<RotationCurve> m_rotations;
|
||||
Array<u8> m_mem;
|
||||
u32 m_frame_count = 0;
|
||||
struct TranslationCurve
|
||||
{
|
||||
BoneNameHash name;
|
||||
u32 count;
|
||||
const u16* times;
|
||||
const Vec3* pos;
|
||||
};
|
||||
|
||||
friend struct AnimationSampler;
|
||||
struct RotationCurve
|
||||
{
|
||||
BoneNameHash name;
|
||||
u32 count;
|
||||
const u16* times;
|
||||
const Quat* rot;
|
||||
};
|
||||
|
||||
TagAllocator m_allocator;
|
||||
Time m_length;
|
||||
Array<TranslationCurve> m_translations;
|
||||
Array<RotationCurve> m_rotations;
|
||||
Array<u8> m_mem;
|
||||
u32 m_frame_count = 0;
|
||||
|
||||
friend struct AnimationSampler;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ struct LUMIX_AUDIO_API AudioDevice
|
|||
|
||||
virtual ~AudioDevice() {}
|
||||
|
||||
static UniquePtr<AudioDevice> create(Engine& engine);
|
||||
static UniquePtr<AudioDevice> create(Engine& engine, IAllocator& allocator);
|
||||
|
||||
virtual BufferHandle createBuffer(const void* data, int size_bytes, int channels, int sample_rate, int flags) = 0;
|
||||
virtual void setEcho(BufferHandle handle,
|
||||
|
|
|
@ -50,7 +50,7 @@ struct AudioSystemImpl final : AudioSystem {
|
|||
|
||||
void init() override
|
||||
{
|
||||
m_device = AudioDevice::create(m_engine);
|
||||
m_device = AudioDevice::create(m_engine, m_allocator);
|
||||
m_manager.create(Clip::TYPE, m_engine.getResourceManager());
|
||||
}
|
||||
|
||||
|
|
|
@ -576,11 +576,10 @@ struct NullAudioDevice final : AudioDevice
|
|||
};
|
||||
|
||||
|
||||
UniquePtr<AudioDevice> AudioDevice::create(Engine& engine)
|
||||
UniquePtr<AudioDevice> AudioDevice::create(Engine& engine, IAllocator& allocator)
|
||||
{
|
||||
UniquePtr<AudioDeviceImpl> device = UniquePtr<AudioDeviceImpl>::create(engine.getAllocator());
|
||||
if (!device->init(engine))
|
||||
{
|
||||
UniquePtr<AudioDeviceImpl> device = UniquePtr<AudioDeviceImpl>::create(allocator);
|
||||
if (!device->init(engine)) {
|
||||
logWarning("Using null device");
|
||||
return UniquePtr<NullAudioDevice>::create(engine.getAllocator());
|
||||
}
|
||||
|
|
|
@ -391,8 +391,7 @@ struct AssetCompilerImpl : AssetCompiler {
|
|||
{
|
||||
auto iter = m_dependencies.find(dependency);
|
||||
if (!iter.isValid()) {
|
||||
IAllocator& allocator = m_app.getAllocator();
|
||||
m_dependencies.insert(dependency, Array<Path>(allocator));
|
||||
m_dependencies.insert(dependency, Array<Path>(m_allocator));
|
||||
iter = m_dependencies.find(dependency);
|
||||
}
|
||||
if (iter.value().indexOf(included_from) < 0) {
|
||||
|
|
|
@ -711,7 +711,7 @@ struct ProfilerUIImpl final : StudioApp::GUIPlugin {
|
|||
|
||||
if (stristr(tag.m_tag.c_str(), m_filter) == 0) return;
|
||||
}
|
||||
if (ImGui::TreeNode(&tag, "%s - %.1f MB", tag.m_tag.c_str(), tag.m_size / 1024.f / 1024.f)) {
|
||||
if (ImGui::TreeNode(&tag, "%s - %.2f MB", tag.m_tag.c_str(), tag.m_size / 1024.f / 1024.f)) {
|
||||
for (const AllocationTag& child : tag.m_child_tags) gui(child);
|
||||
if (tag.m_child_tags.empty() || m_filter[0] || ImGui::TreeNode("allocs", "Allocations - %.1f MB", tag.m_exclusive_size / 1024.f / 1024.f)) {
|
||||
ImGui::Columns(3);
|
||||
|
@ -1476,7 +1476,7 @@ UniquePtr<StudioApp::GUIPlugin> createProfilerUI(StudioApp& app) {
|
|||
allocator = allocator->getParent();
|
||||
} while(allocator);
|
||||
|
||||
return UniquePtr<ProfilerUIImpl>::create(engine.getAllocator(), app, debug_allocator, engine);
|
||||
return UniquePtr<ProfilerUIImpl>::create(app.getAllocator(), app, debug_allocator, engine);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ const ResourceType LuaScript::TYPE("lua_script");
|
|||
|
||||
LuaScript::LuaScript(const Path& path, ResourceManager& resource_manager, IAllocator& allocator)
|
||||
: Resource(path, resource_manager, allocator)
|
||||
, m_source_code(allocator)
|
||||
, m_allocator(allocator, m_path.c_str())
|
||||
, m_source_code(m_allocator)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "engine/allocators.h"
|
||||
#include "engine/resource.h"
|
||||
#include "engine/string.h"
|
||||
|
||||
|
@ -24,6 +25,7 @@ public:
|
|||
static const ResourceType TYPE;
|
||||
|
||||
private:
|
||||
TagAllocator m_allocator;
|
||||
String m_source_code;
|
||||
};
|
||||
|
||||
|
|
|
@ -198,7 +198,12 @@ namespace Lumix
|
|||
|
||||
//physx::PxPvdTransport* transport = physx::PxDefaultPvdFileTransportCreate("physx.pvd");
|
||||
m_pvd_transport = physx::PxDefaultPvdSocketTransportCreate("127.0.0.1", 5425, 100);
|
||||
return m_pvd->connect(*m_pvd_transport, physx::PxPvdInstrumentationFlag::eALL);
|
||||
bool connected = m_pvd->connect(*m_pvd_transport, physx::PxPvdInstrumentationFlag::eALL);
|
||||
if (!connected) {
|
||||
m_pvd_transport->release();
|
||||
m_pvd->release();
|
||||
}
|
||||
return connected;
|
||||
}
|
||||
|
||||
bool cookTriMesh(Span<const Vec3> verts, Span<const u32> indices, IOutputStream& blob) override {
|
||||
|
|
|
@ -63,7 +63,8 @@ enum class CompositeTexture::NodeType : u32 {
|
|||
MAX,
|
||||
SQUARE,
|
||||
TRIANGLE,
|
||||
BLUR
|
||||
BLUR,
|
||||
CHECKERBOARD
|
||||
};
|
||||
|
||||
enum { OUTPUT_FLAG = 1 << 31 };
|
||||
|
@ -1148,11 +1149,13 @@ struct TranslateNode final : CompositeTexture::Node {
|
|||
void serialize(OutputMemoryStream& blob) const override {
|
||||
blob.write(x);
|
||||
blob.write(y);
|
||||
blob.write(wrap);
|
||||
}
|
||||
|
||||
void deserialize(InputMemoryStream& blob) override {
|
||||
blob.read(x);
|
||||
blob.read(y);
|
||||
blob.read(wrap);
|
||||
}
|
||||
|
||||
bool generateInternal() override {
|
||||
|
@ -1161,13 +1164,32 @@ struct TranslateNode final : CompositeTexture::Node {
|
|||
CompositeTexture::Image& in = getInputImage(0);
|
||||
CompositeTexture::Image& out = m_outputs.emplace(in.w, in.h, in.channels, m_allocator);
|
||||
|
||||
for (u32 j = 0; j < in.h; ++j) {
|
||||
for (u32 i = 0; i < in.w; ++i) {
|
||||
memcpy(&out.pixels[(((x + i) % out.w) + ((y + j) % out.h) * out.w) * out.channels]
|
||||
, &in.pixels[(i + j * in.w) * in.channels]
|
||||
, in.channels * sizeof(float));
|
||||
const i32 tx = x < 0 ? -i32(-x % out.w) : x % out.w;
|
||||
const i32 ty = y < 0 ? -i32(-y % out.h) : y % out.h;
|
||||
|
||||
if (wrap) {
|
||||
for (i32 j = 0; j < (i32)in.h; ++j) {
|
||||
const i32 src_y = (j + ty + out.h) % out.h;
|
||||
for (u32 i = 0; i < (i32)in.w; ++i) {
|
||||
const u32 src_x = (i + tx + out.w) % out.w;
|
||||
memcpy(&out.pixels[(i + j * out.w) * out.channels]
|
||||
, &in.pixels[(src_x + src_y * in.w) * in.channels]
|
||||
, in.channels * sizeof(float));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i32 j = 0; j < (i32)in.h; ++j) {
|
||||
const u32 src_y = clamp(j + ty, 0, out.h - 1);
|
||||
for (i32 i = 0; i < (i32)in.w; ++i) {
|
||||
const u32 src_x = clamp(i + tx, 0, out.w - 1);
|
||||
memcpy(&out.pixels[(i + j * out.w) * out.channels]
|
||||
, &in.pixels[(src_x + src_y * in.w) * in.channels]
|
||||
, in.channels * sizeof(float));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1175,12 +1197,14 @@ struct TranslateNode final : CompositeTexture::Node {
|
|||
nodeTitle("Translate");
|
||||
inputSlot();
|
||||
outputSlot();
|
||||
bool res = ImGui::DragInt("X", (i32*)&x, 1, INT_MIN, INT_MAX);
|
||||
res = ImGui::DragInt("Y", (i32*)&y, 1, INT_MIN, INT_MAX) || res;
|
||||
bool res = ImGui::DragInt("X", &x, 1, INT_MIN, INT_MAX);
|
||||
res = ImGui::DragInt("Y", &y, 1, INT_MIN, INT_MAX) || res;
|
||||
res = ImGui::Checkbox("Wrap", &wrap) || res;
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 x = 0, y = 0;
|
||||
i32 x = 0, y = 0;
|
||||
bool wrap = true;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1871,6 +1895,53 @@ struct BlurNode final : CompositeTexture::Node {
|
|||
u32 iterations = 4;
|
||||
};
|
||||
|
||||
struct CheckerboardNode final : CompositeTexture::Node {
|
||||
CheckerboardNode(IAllocator& allocator) : Node(allocator) {}
|
||||
|
||||
CompositeTexture::NodeType getType() const override { return CompositeTexture::NodeType::CHECKERBOARD; }
|
||||
bool hasInputPins() const override { return false; }
|
||||
bool hasOutputPins() const override { return true; }
|
||||
|
||||
void serialize(OutputMemoryStream& blob) const override {
|
||||
blob.write(w);
|
||||
blob.write(h);
|
||||
blob.write(size);
|
||||
}
|
||||
|
||||
void deserialize(InputMemoryStream& blob) override {
|
||||
blob.read(w);
|
||||
blob.read(h);
|
||||
blob.read(size);
|
||||
}
|
||||
|
||||
bool generateInternal() override {
|
||||
CompositeTexture::Image& out = m_outputs.emplace(w, h, 1, m_allocator);
|
||||
for (u32 j = 0; j < h; ++j) {
|
||||
for (u32 i = 0; i < w; ++i) {
|
||||
u32 color = ((i / size) + (j / size)) % 2;
|
||||
out.pixels[i + j * out.w] = (float)color;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gui() override {
|
||||
nodeTitle("Checkerboard");
|
||||
ImGui::BeginGroup();
|
||||
bool res = ImGui::DragInt("Width", (i32*)&w, 1, 1, INT_MAX);
|
||||
res = ImGui::DragInt("Height", (i32*)&h, 1, 1, INT_MAX) || res;
|
||||
res = ImGui::DragInt("Size", (i32*)&size, 1, 1, INT_MAX) || res;
|
||||
ImGui::EndGroup();
|
||||
ImGui::SameLine();
|
||||
outputSlot();
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 w = 256;
|
||||
u32 h = 256;
|
||||
u32 size = 16;
|
||||
};
|
||||
|
||||
struct TriangleNode final : CompositeTexture::Node {
|
||||
TriangleNode(IAllocator& allocator) : Node(allocator) {}
|
||||
|
||||
|
@ -2464,6 +2535,7 @@ CompositeTexture::Node* createNode(CompositeTexture::NodeType type, CompositeTex
|
|||
case CompositeTexture::NodeType::SIMPLEX: node = LUMIX_NEW(allocator, SimplexNode)(allocator); break;
|
||||
case CompositeTexture::NodeType::WAVE_NOISE: node = LUMIX_NEW(allocator, WaveNoiseNode)(allocator); break;
|
||||
case CompositeTexture::NodeType::BLUR: node = LUMIX_NEW(allocator, BlurNode)(allocator); break;
|
||||
case CompositeTexture::NodeType::CHECKERBOARD: node = LUMIX_NEW(allocator, CheckerboardNode)(allocator); break;
|
||||
case CompositeTexture::NodeType::TRIANGLE: node = LUMIX_NEW(allocator, TriangleNode)(allocator); break;
|
||||
case CompositeTexture::NodeType::SQUARE: node = LUMIX_NEW(allocator, SquareNode)(allocator); break;
|
||||
case CompositeTexture::NodeType::CIRCLE: node = LUMIX_NEW(allocator, CircleNode)(allocator); break;
|
||||
|
@ -2776,6 +2848,7 @@ struct CompositeTextureEditorWindow : StudioApp::GUIPlugin, NodeEditor {
|
|||
void visitNodeTypes(INodeTypeVisitor& visitor) {
|
||||
if (visitor.beginCategory("Generate")) {
|
||||
visitor
|
||||
.visitType("Checkerboard", CompositeTexture::NodeType::CHECKERBOARD)
|
||||
.visitType("Circle", CompositeTexture::NodeType::CIRCLE, 'O')
|
||||
.visitType("Circular splatter", CompositeTexture::NodeType::CIRCULAR_SPLATTER)
|
||||
.visitType("Gradient", CompositeTexture::NodeType::GRADIENT)
|
||||
|
|
|
@ -1832,22 +1832,20 @@ struct ModelPlugin final : AssetBrowser::Plugin, AssetCompiler::IPlugin
|
|||
}
|
||||
|
||||
|
||||
~ModelPlugin()
|
||||
{
|
||||
~ModelPlugin() {
|
||||
if (m_downscale_program) m_pipeline->getRenderer().getEndFrameDrawStream().destroy(m_downscale_program);
|
||||
jobs::wait(&m_subres_signal);
|
||||
auto& engine = m_app.getEngine();
|
||||
engine.destroyWorld(*m_world);
|
||||
|
||||
Engine& engine = m_app.getEngine();
|
||||
if (m_world) engine.destroyWorld(*m_world);
|
||||
m_pipeline.reset();
|
||||
engine.destroyWorld(*m_tile.world);
|
||||
if (m_tile.world) engine.destroyWorld(*m_tile.world);
|
||||
m_tile.pipeline.reset();
|
||||
}
|
||||
|
||||
void init() {
|
||||
Engine& engine = m_app.getEngine();
|
||||
m_renderer = static_cast<Renderer*>(engine.getSystemManager().getSystem("renderer"));
|
||||
createPreviewWorld();
|
||||
createTileWorld();
|
||||
m_viewport.is_ortho = true;
|
||||
m_viewport.near = 0.f;
|
||||
m_viewport.far = 1000.f;
|
||||
|
@ -2038,8 +2036,8 @@ struct ModelPlugin final : AssetBrowser::Plugin, AssetCompiler::IPlugin
|
|||
}
|
||||
|
||||
|
||||
void createPreviewWorld()
|
||||
{
|
||||
void createPreviewWorld() {
|
||||
ASSERT(!m_world);
|
||||
Engine& engine = m_app.getEngine();
|
||||
m_world = &engine.createWorld(false);
|
||||
PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
|
||||
|
@ -2068,6 +2066,7 @@ struct ModelPlugin final : AssetBrowser::Plugin, AssetCompiler::IPlugin
|
|||
|
||||
void showPreview(Model& model)
|
||||
{
|
||||
if (!m_world) createPreviewWorld();
|
||||
auto* render_module = static_cast<RenderModule*>(m_world->getModule(MODEL_INSTANCE_TYPE));
|
||||
if (!render_module) return;
|
||||
if (!model.isReady()) return;
|
||||
|
@ -2853,8 +2852,8 @@ struct ModelPlugin final : AssetBrowser::Plugin, AssetCompiler::IPlugin
|
|||
}
|
||||
|
||||
|
||||
void renderTile(PrefabResource* prefab)
|
||||
{
|
||||
void renderTile(PrefabResource* prefab) {
|
||||
if (!m_tile.world) createTileWorld();
|
||||
Engine& engine = m_app.getEngine();
|
||||
|
||||
EntityMap entity_map(m_app.getAllocator());
|
||||
|
@ -2868,8 +2867,8 @@ struct ModelPlugin final : AssetBrowser::Plugin, AssetCompiler::IPlugin
|
|||
}
|
||||
|
||||
|
||||
void renderPrefabSecondStage()
|
||||
{
|
||||
void renderPrefabSecondStage() {
|
||||
if (!m_tile.world) createTileWorld();
|
||||
AABB aabb({0, 0, 0}, {0, 0, 0});
|
||||
float radius = 1;
|
||||
World& world = *m_tile.world;
|
||||
|
@ -2989,6 +2988,7 @@ struct ModelPlugin final : AssetBrowser::Plugin, AssetCompiler::IPlugin
|
|||
|
||||
void renderTile(Model* model, const DVec3* in_pos, const Quat* in_rot)
|
||||
{
|
||||
if (!m_tile.world) createTileWorld();
|
||||
RenderModule* render_module = (RenderModule*)m_tile.world->getModule(MODEL_INSTANCE_TYPE);
|
||||
if (!render_module) return;
|
||||
|
||||
|
@ -3093,7 +3093,7 @@ struct ModelPlugin final : AssetBrowser::Plugin, AssetCompiler::IPlugin
|
|||
StudioApp& m_app;
|
||||
Renderer* m_renderer = nullptr;
|
||||
gpu::TextureHandle m_preview;
|
||||
World* m_world;
|
||||
World* m_world = nullptr;
|
||||
Viewport m_viewport;
|
||||
UniquePtr<Pipeline> m_pipeline;
|
||||
EntityPtr m_mesh = INVALID_ENTITY;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
#include "gpu.h"
|
||||
#include "engine/page_allocator.h"
|
||||
#include "engine/allocators.h"
|
||||
#include "engine/array.h"
|
||||
#include "engine/hash.h"
|
||||
#include "engine/hash_map.h"
|
||||
#include "engine/log.h"
|
||||
#include "engine/math.h"
|
||||
#include "engine/page_allocator.h"
|
||||
#include "engine/stream.h"
|
||||
#include "engine/sync.h"
|
||||
#include "engine/os.h"
|
||||
|
@ -113,9 +114,9 @@ struct WindowContext {
|
|||
};
|
||||
|
||||
struct GL {
|
||||
GL(IAllocator& allocator) : allocator(allocator) {}
|
||||
GL(IAllocator& allocator) : allocator(allocator, "gl") {}
|
||||
|
||||
IAllocator& allocator;
|
||||
TagAllocator allocator;
|
||||
u32 frame = 0;
|
||||
RENDERDOC_API_1_0_2* rdoc_api;
|
||||
WindowContext contexts[64];
|
||||
|
|
Loading…
Reference in a new issue