Merge branch 'master' of github.com:bkaradzic/bgfx

This commit is contained in:
Бранимир Караџић 2019-01-05 08:16:41 -08:00
commit e743c4e431
21 changed files with 2270 additions and 7 deletions

View File

@ -379,6 +379,9 @@ CODE
- 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
- 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
- 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
- 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan, etc.).
old binding will still work as is, however prefer using the separated bindings as they will be updated to be multi-viewport conformant.
when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call.
- 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
- 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
- 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more.
@ -2534,6 +2537,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
}
}
// FIXME-NAV: The existence of SetNavID/SetNavIDWithRectRel/SetFocusID is incredibly messy and confusing and needs some explanation or refactoring.
void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
@ -4914,6 +4918,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Position child window
if (flags & ImGuiWindowFlags_ChildWindow)
{
IM_ASSERT(parent_window->Active);
window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
parent_window->DC.ChildWindows.push_back(window);
if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
@ -5381,7 +5386,7 @@ void ImGui::FocusWindow(ImGuiWindow* window)
g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
g.NavIdIsAlive = false;
g.NavLayer = ImGuiNavLayer_Main;
//printf("[%05d] FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL);
//IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", g.FrameCount, window ? window->Name : NULL);
}
// Passing NULL allow to disable keyboard focus
@ -6558,7 +6563,7 @@ void ImGui::OpenPopupEx(ImGuiID id)
popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
//printf("[%05d] OpenPopupEx(0x%08X)\n", g.FrameCount, id);
//IMGUI_DEBUG_LOG("OpenPopupEx(0x%08X)\n", g.FrameCount, id);
if (g.OpenPopupStack.Size < current_stack_size + 1)
{
g.OpenPopupStack.push_back(popup_ref);
@ -7348,7 +7353,7 @@ static void ImGui::NavUpdate()
ImGuiContext& g = *GImGui;
g.IO.WantSetMousePos = false;
#if 0
if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
#endif
// Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard)

View File

@ -641,7 +641,7 @@ namespace ImGui
IMGUI_API bool IsMouseDoubleClicked(int button); // did mouse button double-clicked. a double-click returns false in IsMouseClicked(). uses io.MouseDoubleClickTime.
IMGUI_API bool IsMouseReleased(int button); // did mouse button released (went from Down to !Down)
IMGUI_API bool IsMouseDragging(int button = 0, float lock_threshold = -1.0f); // is mouse dragging. if lock_threshold < -1.0f uses io.MouseDraggingThreshold
IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block.
IMGUI_API bool IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip = true); // is mouse hovering given bounding rect (in screen space). clipped by current clipping settings, but disregarding of other consideration of focus/window ordering/popup-block.
IMGUI_API bool IsMousePosValid(const ImVec2* mouse_pos = NULL); //
IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve backup of mouse position at the time of opening popup we have BeginPopup() into
@ -1283,7 +1283,7 @@ struct ImGuiIO
bool KeySuper; // Keyboard modifier pressed: Cmd/Super/Windows
bool KeysDown[512]; // Keyboard keys that are pressed (ideally left in the "native" order your engine has access to keyboard keys, so you can use your own defines/enums for keys).
ImWchar InputCharacters[16+1]; // List of characters input (translated by user from keypress+keyboard state). Fill using AddInputCharacter() helper.
float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs (keyboard keys will be auto-mapped and be written here by ImGui::NewFrame, all values will be cleared back to zero in ImGui::EndFrame)
float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame().
// Functions
IMGUI_API void AddInputCharacter(ImWchar c); // Add new character into InputCharacters[]

View File

@ -101,6 +101,7 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe
#else
#define IM_NEWLINE "\n"
#endif
#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255

View File

@ -488,7 +488,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
// Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.
g.NavActivateId = id; // This is so SetActiveId assign a Nav source
SetActiveID(id, window);
if (!(flags & ImGuiButtonFlags_NoNavFocus))
if ((nav_activated_by_code || nav_activated_by_inputs) && !(flags & ImGuiButtonFlags_NoNavFocus))
SetFocusID(id, window);
g.ActiveIdAllowNavDirFlags = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right) | (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
}
@ -5862,7 +5862,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
g.CurrentTabBar.push_back(tab_bar);
if (tab_bar->CurrFrameVisible == g.FrameCount)
{
//printf("[%05d] BeginTabBarEx already called this frame\n", g.FrameCount);
//IMGUI_DEBUG_LOG("BeginTabBarEx already called this frame\n", g.FrameCount);
IM_ASSERT(0);
return true;
}

View File

@ -0,0 +1,24 @@
$input v_texcoord0
/*
* Copyright 2011-2018 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
/*
* Reference(s):
* - Based on Virtual Texture Demo by Brad Blanchard
* http://web.archive.org/web/20190103162638/http://linedef.com/virtual-texture-demo.html
*/
#include "../common/common.sh"
#include "virtualtexture.sh"
void main()
{
float mipCount = log2(PageTableSize);
float mip = floor(MipLevel(v_texcoord0.xy, VirtualTextureSize) - MipBias);
mip = clamp(mip, 0, mipCount);
vec2 offset = floor(v_texcoord0.xy * PageTableSize);
gl_FragColor = vec4(floor(vec3(offset / exp2(mip), mip)) / 255.0, 1.0);
}

View File

@ -0,0 +1,21 @@
$input v_texcoord0
/*
* Copyright 2011-2018 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
/*
* Reference(s):
* - Based on Virtual Texture Demo by Brad Blanchard
* http://web.archive.org/web/20190103162638/http://linedef.com/virtual-texture-demo.html
*/
#include "../common/common.sh"
#include "virtualtexture.sh"
void main()
{
gl_FragColor = VirtualTexture(v_texcoord0.xy);
}

10
examples/40-svt/makefile Normal file
View File

@ -0,0 +1,10 @@
#
# Copyright 2011-2018 Branimir Karadzic. All rights reserved.
# License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
#
BGFX_DIR=../..
RUNTIME_DIR=$(BGFX_DIR)/examples/runtime
BUILD_DIR=../../.build
include $(BGFX_DIR)/scripts/shader.mk

375
examples/40-svt/svt.cpp Normal file
View File

@ -0,0 +1,375 @@
/*
* Copyright 2018 Aleš Mlakar. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
/*
* Reference(s):
* - Sparse Virtual Textures by Sean Barrett
* http://web.archive.org/web/20190103162611/http://silverspaceship.com/src/svt/
* - Based on Virtual Texture Demo by Brad Blanchard
* http://web.archive.org/web/20190103162638/http://linedef.com/virtual-texture-demo.html
* - Mars texture
* http://web.archive.org/web/20190103162730/http://www.celestiamotherlode.net/catalog/mars.php
*/
#include "common.h"
#include "bgfx_utils.h"
#include "imgui/imgui.h"
#include "camera.h"
#include "bounds.h"
#include "vt.h"
namespace
{
struct PosTexcoordVertex
{
float m_x;
float m_y;
float m_z;
float m_u;
float m_v;
static void init()
{
ms_decl
.begin()
.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
.end();
};
static bgfx::VertexDecl ms_decl;
};
bgfx::VertexDecl PosTexcoordVertex::ms_decl;
static const float s_planeScale = 50.0f;
static PosTexcoordVertex s_vplaneVertices[] =
{
{ -s_planeScale, 0.0f, s_planeScale, 1.0f, 1.0f },
{ s_planeScale, 0.0f, s_planeScale, 1.0f, 0.0f },
{ -s_planeScale, 0.0f, -s_planeScale, 0.0f, 1.0f },
{ s_planeScale, 0.0f, -s_planeScale, 0.0f, 0.0f },
};
static const uint16_t s_planeIndices[] =
{
0, 1, 2,
1, 3, 2,
};
class ExampleSVT : public entry::AppI
{
public:
ExampleSVT(const char* _name, const char* _description)
: entry::AppI(_name, _description)
{
}
void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
{
Args args(_argc, _argv);
m_width = _width;
m_height = _height;
m_debug = BGFX_DEBUG_TEXT;
m_reset = BGFX_RESET_VSYNC;
bgfx::Init init;
init.type = args.m_type;
init.vendorId = args.m_pciId;
init.resolution.width = m_width;
init.resolution.height = m_height;
init.resolution.reset = m_reset;
bgfx::init(init);
// Enable m_debug text.
bgfx::setDebug(m_debug);
// Set views clear state (first pass to 0, second pass to some background color)
for (uint16_t i = 0; i < 2; ++i)
{
bgfx::setViewClear(i
, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
, i == 0 ? 0 : 0x101050ff
, 1.0f
, 0
);
}
// Create vertex stream declaration.
PosTexcoordVertex::init();
// Create static vertex buffer.
m_vbh = bgfx::createVertexBuffer(
bgfx::makeRef(s_vplaneVertices, sizeof(s_vplaneVertices))
, PosTexcoordVertex::ms_decl
);
m_ibh = bgfx::createIndexBuffer(
bgfx::makeRef(s_planeIndices, sizeof(s_planeIndices))
);
// Create program from shaders.
m_vt_unlit = loadProgram("vs_vt_generic", "fs_vt_unlit");
m_vt_mip = loadProgram("vs_vt_generic", "fs_vt_mip");
// Imgui.
imguiCreate();
m_timeOffset = bx::getHPCounter();
// Get renderer capabilities info.
m_caps = bgfx::getCaps();
m_scrollArea = 0;
// Create and setup camera
cameraCreate();
cameraSetPosition({ 0.0f, 5.0f, 0.0f });
cameraSetVerticalAngle(0.0f);
// Set VirtualTexture system allocator
vt::VirtualTexture::setAllocator(&m_vtAllocator);
// Create Virtual texture info
m_vti = new vt::VirtualTextureInfo();
m_vti->m_virtualTextureSize = 8192; // The actual size will be read from the tile data file
m_vti->m_tileSize = 128;
m_vti->m_borderSize = 1;
// Generate tile data file (if not yet created)
{
vt::TileGenerator tileGenerator(m_vti);
tileGenerator.generate("textures/8k_mars.jpg");
}
// Load tile data file
auto tileDataFile = new vt::TileDataFile("temp/8k_mars.jpg.vt", m_vti);
tileDataFile->readInfo();
// Create virtual texture and feedback buffer
m_vt = new vt::VirtualTexture(tileDataFile, m_vti, 2048, 1);
m_feedbackBuffer = new vt::FeedbackBuffer(m_vti, 64, 64);
}
virtual int shutdown() override
{
// Cleanup.
bgfx::frame();
cameraDestroy();
imguiDestroy();
bgfx::destroy(m_ibh);
bgfx::destroy(m_vbh);
bgfx::destroy(m_vt_unlit);
bgfx::destroy(m_vt_mip);
delete m_vti;
delete m_vt;
delete m_feedbackBuffer;
// Shutdown bgfx.
bgfx::shutdown();
return 0;
}
bool update() override
{
if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState))
{
imguiBeginFrame(
m_mouseState.m_mx
, m_mouseState.m_my
, (m_mouseState.m_buttons[entry::MouseButton::Left] ? IMGUI_MBUT_LEFT : 0)
| (m_mouseState.m_buttons[entry::MouseButton::Right] ? IMGUI_MBUT_RIGHT : 0)
| (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
, m_mouseState.m_mz
, uint16_t(m_width)
, uint16_t(m_height)
);
showExampleDialog(this);
int64_t now = bx::getHPCounter();
static int64_t last = now;
const int64_t frameTime = now - last;
last = now;
const double freq = double(bx::getHPFrequency());
const float deltaTime = float(frameTime / freq);
float time = (float)((now - m_timeOffset) / freq);
if ((BGFX_CAPS_TEXTURE_BLIT | BGFX_CAPS_TEXTURE_READ_BACK) != (bgfx::getCaps()->supported & (BGFX_CAPS_TEXTURE_BLIT | BGFX_CAPS_TEXTURE_READ_BACK)))
{
// When texture read-back or blit is not supported by GPU blink!
bool blink = uint32_t(time*3.0f) & 1;
bgfx::dbgTextPrintf(0, 0, blink ? 0x4f : 0x04, " Texture read-back and/or blit not supported by GPU. ");
// Set view 0 default viewport.
bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height));
// This dummy draw call is here to make sure that view 0 is cleared
// if no other draw calls are submitted to view 0.
bgfx::touch(0);
}
else
{
ImGui::SetNextWindowPos(
ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
, ImGuiCond_FirstUseEver
);
ImGui::SetNextWindowSize(
ImVec2(m_width / 5.0f, m_height - 10.0f)
, ImGuiCond_FirstUseEver
);
ImGui::Begin("Settings"
, NULL
, 0
);
//ImGui::SliderFloat("intensity", &m_intensity, 0.0f, 3.0f);
auto showBorders = m_vt->isShowBoardersEnabled();
if (ImGui::Checkbox("Show borders", &showBorders))
{
m_vt->enableShowBoarders(showBorders);
}
auto colorMipLevels = m_vt->isColorMipLevelsEnabled();
if (ImGui::Checkbox("Color mip levels", &colorMipLevels))
{
m_vt->enableColorMipLevels(colorMipLevels);
}
auto uploadsperframe = m_vt->getUploadsPerFrame();
if (ImGui::InputInt("Updates per frame", &uploadsperframe, 1, 2))
{
uploadsperframe = bx::clamp(uploadsperframe, 1, 100);
m_vt->setUploadsPerFrame(uploadsperframe);
}
ImGui::ImageButton(m_vt->getAtlastTexture(), ImVec2(m_width / 5.0f - 16.0f, m_width / 5.0f - 16.0f));
ImGui::ImageButton(bgfx::getTexture(m_feedbackBuffer->getFrameBuffer()), ImVec2(m_width / 5.0f - 16.0f, m_width / 5.0f - 16.0f));
ImGui::End();
// Update camera.
cameraUpdate(deltaTime, m_mouseState);
float view[16];
cameraGetViewMtx(view);
float proj[16];
bx::mtxProj(proj, 60.0f, float(m_width) / float(m_height), 0.1f, 1000.0f, m_caps->homogeneousDepth);
// Setup views
for (uint16_t i = 0; i < 2; ++i)
{
uint16_t viewWidth = 0;
uint16_t viewHeight = 0;
// Setup pass, first pass is into mip-map feedback buffer, second pass is on screen
if (i == 0)
{
bgfx::setViewFrameBuffer(i, m_feedbackBuffer->getFrameBuffer());
viewWidth = uint16_t(m_feedbackBuffer->getWidth());
viewHeight = uint16_t(m_feedbackBuffer->getHeight());
}
else
{
bgfx::FrameBufferHandle invalid = BGFX_INVALID_HANDLE;
bgfx::setViewFrameBuffer(i, invalid);
viewWidth = uint16_t(m_width);
viewHeight = uint16_t(m_height);
}
bgfx::setViewRect(i, 0, 0, viewWidth, viewHeight);
bgfx::setViewTransform(i, view, proj);
float mtx[16];
bx::mtxIdentity(mtx);
// Set identity transform for draw call.
bgfx::setTransform(mtx);
// Set vertex and index buffer.
bgfx::setVertexBuffer(0, m_vbh);
bgfx::setIndexBuffer(m_ibh);
// Set render states.
bgfx::setState(0
| BGFX_STATE_WRITE_RGB
| BGFX_STATE_WRITE_A
| BGFX_STATE_WRITE_Z
| BGFX_STATE_DEPTH_TEST_LESS
);
// Set virtual texture uniforms
m_vt->setUniforms();
// Submit primitive for rendering to first pass (to feedback buffer, where mip levels and tile x/y will be rendered
if (i == 0)
{
bgfx::submit(i, m_vt_mip);
// Download previous frame feedback info
m_feedbackBuffer->download();
// Update and upload new requests
m_vt->update(m_feedbackBuffer->getRequests(), 4);
// Clear feedback
m_feedbackBuffer->clear();
// Copy new frame feedback buffer
m_feedbackBuffer->copy(3);
}
else
{
// Submit primitive for rendering to second pass (to back buffer, where virtual texture page table and atlas will be used)
bgfx::submit(i, m_vt_unlit);
}
}
}
imguiEndFrame();
// Advance to next frame. Rendering thread will be kicked to
// process submitted rendering primitives.
bgfx::frame();
return true;
}
return false;
}
bgfx::VertexBufferHandle m_vbh;
bgfx::IndexBufferHandle m_ibh;
bgfx::ProgramHandle m_vt_unlit;
bgfx::ProgramHandle m_vt_mip;
uint32_t m_width;
uint32_t m_height;
uint32_t m_debug;
uint32_t m_reset;
int32_t m_scrollArea;
entry::MouseState m_mouseState;
const bgfx::Caps* m_caps;
int64_t m_timeOffset;
bx::DefaultAllocator m_vtAllocator;
vt::VirtualTextureInfo* m_vti;
vt::VirtualTexture* m_vt;
vt::FeedbackBuffer* m_feedbackBuffer;
};
} // namespace
ENTRY_IMPLEMENT_MAIN(ExampleSVT, "40-svt", "Sparse Virtual Textures.");

View File

@ -0,0 +1,4 @@
vec2 v_texcoord0 : TEXCOORD0 = vec2(0.0, 0.0);
vec3 a_position : POSITION;
vec2 a_texcoord0 : TEXCOORD0;

View File

@ -0,0 +1,86 @@
/*
* Copyright 2011-2018 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
/*
* Reference(s):
* - Based on Virtual Texture Demo by Brad Blanchard
* http://web.archive.org/web/20190103162638/http://linedef.com/virtual-texture-demo.html
*/
uniform vec4 u_vt_settings_1;
uniform vec4 u_vt_settings_2;
#define VirtualTextureSize u_vt_settings_1.x
#define AtlasScale u_vt_settings_1.y
#define BorderScale u_vt_settings_1.z
#define BorderOffset u_vt_settings_1.w
#define MipBias u_vt_settings_2.x
#define PageTableSize u_vt_settings_2.y
SAMPLER2D(s_vt_page_table, 0);
SAMPLER2D(s_vt_texture_atlas, 1);
// This function estimates mipmap levels
float MipLevel( vec2 uv, float size )
{
vec2 dx = dFdx( uv * size );
vec2 dy = dFdy( uv * size );
float d = max( dot( dx, dx ), dot( dy, dy ) );
return max( 0.5 * log2( d ), 0 );
}
// This function samples the page table and returns the page's
// position and mip level.
vec3 SampleTable( vec2 uv, float mip )
{
vec2 offset = fract( uv * PageTableSize ) / PageTableSize;
return texture2DLod( s_vt_page_table, uv - offset, mip ).xyz;
}
// This functions samples from the texture atlas and returns the final color
vec4 SampleAtlas( vec3 page, vec2 uv )
{
float mipsize = exp2( floor( page.z * 255.0 + 0.5 ) );
uv = fract( uv * PageTableSize / mipsize );
uv *= BorderScale;
uv += BorderOffset;
vec2 offset = floor( page.xy * 255 + 0.5 );
return texture2D( s_vt_texture_atlas, ( offset + uv ) * AtlasScale );
}
// Ugly brute force trilinear, look up twice and mix
vec4 VirtualTextureTrilinear( vec2 uv )
{
float miplevel = MipLevel( uv, VirtualTextureSize );
miplevel = clamp( miplevel, 0, log2( PageTableSize )-1 );
float mip1 = floor( miplevel );
float mip2 = mip1 + 1;
float mipfrac = miplevel - mip1;
vec3 page1 = SampleTable( uv, mip1 );
vec3 page2 = SampleTable( uv, mip2 );
vec4 sample1 = SampleAtlas( page1, uv );
vec4 sample2 = SampleAtlas( page2, uv );
return mix( sample1, sample2, mipfrac );
}
// Simple bilinear
vec4 VirtualTexture( vec2 uv )
{
float mip = floor( MipLevel( uv, VirtualTextureSize ) );
mip = clamp( mip, 0, log2( PageTableSize ) );
vec3 page = SampleTable( uv, mip );
return SampleAtlas( page, uv );
}

View File

@ -0,0 +1,16 @@
$input a_position, a_texcoord0
$output v_texcoord0
/*
* Copyright 2011-2018 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
#include "../common/common.sh"
void main()
{
vec3 wpos = mul(u_model[0], vec4(a_position, 1.0) ).xyz;
gl_Position = mul(u_viewProj, vec4(wpos, 1.0) );
v_texcoord0 = a_texcoord0;
}

1281
examples/40-svt/vt.cpp Normal file

File diff suppressed because it is too large Load Diff

439
examples/40-svt/vt.h Normal file
View File

@ -0,0 +1,439 @@
/*
* Copyright 2018 Aleš Mlakar. All rights reserved.
* License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
*/
/*
* Reference(s):
* - Sparse Virtual Textures by Sean Barrett
* http://web.archive.org/web/20190103162611/http://silverspaceship.com/src/svt/
* - Based on Virtual Texture Demo by Brad Blanchard
* http://web.archive.org/web/20190103162638/http://linedef.com/virtual-texture-demo.html
* - Mars texture
* http://web.archive.org/web/20190103162730/http://www.celestiamotherlode.net/catalog/mars.php
*/
#pragma once
#include "common.h"
#include "bgfx_utils.h"
#include "bimg/decode.h"
#include <tinystl/allocator.h>
#include <tinystl/unordered_set.h>
#include <tinystl/vector.h>
#include <functional>
namespace vt
{
// Forward declarations
class PageCache;
class TextureAtlas;
class TileDataFile;
// Point
struct Point
{
int m_x, m_y;
};
// Rect
struct Rect
{
int minX() const
{
return m_x;
}
int minY() const
{
return m_y;
}
int maxX() const
{
return m_x + m_width;
}
int maxY() const
{
return m_y + m_height;
}
bool contains(const Point& p) const
{
return p.m_x >= minX() && p.m_y >= minY() && p.m_x < maxX() && p.m_y < maxY();
}
int m_x, m_y, m_width, m_height;
};
// Color
struct Color
{
uint8_t m_r, m_g, m_b, m_a;
};
// Page
struct Page
{
operator size_t() const;
int m_x;
int m_y;
int m_mip;
};
// PageCount
struct PageCount
{
Page m_page;
int m_count;
PageCount(Page _page, int _count);
int compareTo(const PageCount& other) const;
};
// VirtualTextureInfo
struct VirtualTextureInfo
{
VirtualTextureInfo();
int GetPageSize() const;
int GetPageTableSize() const;
int m_virtualTextureSize = 0;
int m_tileSize = 0;
int m_borderSize = 0;
};
// StagingPool
class StagingPool
{
public:
StagingPool(int _width, int _height, int _count, bool _readBack);
~StagingPool();
void grow(int count);
bgfx::TextureHandle getTexture();
void next();
private:
tinystl::vector<bgfx::TextureHandle> m_stagingTextures;
int m_stagingTextureIndex;
int m_width;
int m_height;
uint64_t m_flags;
};
// PageIndexer
struct PageIndexer
{
public:
PageIndexer(VirtualTextureInfo* _info);
int getIndexFromPage(Page page);
Page getPageFromIndex(int index);
bool isValid(Page page);
int getCount() const;
int getMipCount() const;
private:
VirtualTextureInfo* m_info;
int m_mipcount;
int m_count;
tinystl::vector<int> m_offsets; // This stores the offsets to the first page of the start of a mipmap level
tinystl::vector<int> m_sizes; // This stores the sizes of various mip levels
tinystl::vector<Page> m_reverse;
};
// SimpleImage
struct SimpleImage
{
SimpleImage(int _width, int _height, int _channelCount, uint8_t _clearValue = 0);
SimpleImage(int _width, int _height, int _channelCount, tinystl::vector<uint8_t>& _data);
void copy(Point dest_offset, SimpleImage& src, Rect src_rect);
void clear(uint8_t clearValue = 0);
void fill(Rect rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
static void mipmap(uint8_t* source, int size, int channels, uint8_t* dest);
int m_width = 0;
int m_height = 0;
int m_channelCount = 0;
tinystl::vector<uint8_t> m_data;
};
// Quadtree
struct Quadtree
{
Quadtree(Rect _rect, int _level);
~Quadtree();
void add(Page request, Point mapping);
void remove(Page request);
void write(SimpleImage& image, int miplevel);
Rect getRectangle(int index);
void write(Quadtree* node, SimpleImage& image, int miplevel);
static Quadtree* findPage(Quadtree* node, Page request, int* index);
Rect m_rectangle;
int m_level;
Point m_mapping;
Quadtree* m_children[4];
};
// PageTable
class PageTable
{
public:
PageTable(PageCache* _cache, VirtualTextureInfo* _info, PageIndexer* _indexer);
~PageTable();
void update(bgfx::ViewId blitViewId);
bgfx::TextureHandle getTexture();
private:
VirtualTextureInfo* m_info;
bgfx::TextureHandle m_texture;
PageIndexer* m_indexer;
Quadtree* m_quadtree;
bool m_quadtreeDirty;
tinystl::vector<SimpleImage*> m_images;
tinystl::vector<bgfx::TextureHandle> m_stagingTextures;
};
// PageLoader
class PageLoader
{
public:
struct ReadState
{
Page m_page;
tinystl::vector<uint8_t> m_data;
};
PageLoader(TileDataFile* _tileDataFile, PageIndexer* _indexer, VirtualTextureInfo* _info);
void submit(Page request);
void loadPage(ReadState& state);
void onPageLoadComplete(ReadState& state);
void copyBorder(uint8_t* image);
void copyColor(uint8_t* image, Page request);
std::function<void(Page, uint8_t*)> loadComplete;
bool m_colorMipLevels;
bool m_showBorders;
private:
TileDataFile* m_tileDataFile;
PageIndexer* m_indexer;
VirtualTextureInfo* m_info;
};
// PageCache
class PageCache
{
public:
PageCache(TextureAtlas* _atlas, PageLoader* _loader, int _count);
bool touch(Page page);
bool request(Page request, bgfx::ViewId blitViewId);
void clear();
void loadComplete(Page page, uint8_t* data);
// These callbacks are used to notify the other systems
std::function<void(Page, Point)> removed;
std::function<void(Page, Point)> added;
private:
TextureAtlas* m_atlas;
PageLoader* m_loader;
int m_count;
struct LruPage
{
Page m_page;
Point m_point;
bool operator==(const Page& other) const
{
return m_page == other;
}
};
int m_current; // This is used for generating the texture atlas indices before the lru is full
tinystl::unordered_set<Page> m_lru_used;
tinystl::vector<LruPage> m_lru;
tinystl::unordered_set<Page> m_loading;
bgfx::ViewId m_blitViewId;
};
// TextureAtlas
class TextureAtlas
{
public:
TextureAtlas(VirtualTextureInfo* _info, int count, int uploadsperframe);
~TextureAtlas();
void setUploadsPerFrame(int count);
void uploadPage(Point pt, uint8_t* data, bgfx::ViewId blitViewId);
bgfx::TextureHandle getTexture();
private:
VirtualTextureInfo* m_info;
bgfx::TextureHandle m_texture;
StagingPool m_stagingPool;
};
// FeedbackBuffer
class FeedbackBuffer
{
public:
FeedbackBuffer(VirtualTextureInfo* _info, int _width, int _height);
~FeedbackBuffer();
void clear();
void copy(bgfx::ViewId viewId);
void download();
// This function validates the pages and adds the page's parents
// We do this so that we can fall back to them if we run out of memory
void addRequestAndParents(Page request);
const tinystl::vector<int>& getRequests() const;
bgfx::FrameBufferHandle getFrameBuffer();
int getWidth() const;
int getHeight() const;
private:
VirtualTextureInfo* m_info;
PageIndexer* m_indexer;
int m_width = 0;
int m_height = 0;
StagingPool m_stagingPool;
bgfx::TextureHandle m_lastStagingTexture;
bgfx::FrameBufferHandle m_feedbackFrameBuffer;
// This stores the pages by index. The int value is number of requests.
tinystl::vector<int> m_requests;
tinystl::vector<uint8_t> m_downloadBuffer;
};
// VirtualTexture
class VirtualTexture
{
public:
VirtualTexture(TileDataFile* _tileDataFile, VirtualTextureInfo* _info, int _atlassize, int _uploadsperframe, int _mipBias = 4);
~VirtualTexture();
int getMipBias() const;
void setMipBias(int value);
void setUploadsPerFrame(int count);
int getUploadsPerFrame() const;
void enableShowBoarders(bool enable);
bool isShowBoardersEnabled() const;
void enableColorMipLevels(bool enable);
bool isColorMipLevelsEnabled() const;
bgfx::TextureHandle getAtlastTexture();
bgfx::TextureHandle getPageTableTexture();
void clear();
void update(const tinystl::vector<int>& requests, bgfx::ViewId blitViewId);
void setUniforms();
static void setAllocator(bx::AllocatorI* allocator);
static bx::AllocatorI* getAllocator();
private:
TileDataFile* m_tileDataFile;
VirtualTextureInfo* m_info;
PageIndexer* m_indexer;
PageTable* m_pageTable;
TextureAtlas* m_atlas;
PageLoader* m_loader;
PageCache* m_cache;
int m_atlasCount;
int m_uploadsPerFrame;
tinystl::vector<PageCount> m_pagesToLoad;
int m_mipBias;
bgfx::UniformHandle u_vt_settings_1;
bgfx::UniformHandle u_vt_settings_2;
bgfx::UniformHandle s_vt_page_table;
bgfx::UniformHandle s_vt_texture_atlas;
static bx::AllocatorI* s_allocator;
};
// TileDataFile
class TileDataFile
{
public:
TileDataFile(const bx::FilePath& filename, VirtualTextureInfo* _info, bool _readWrite = false);
~TileDataFile();
void readInfo();
void writeInfo();
void readPage(int index, uint8_t* data);
void writePage(int index, uint8_t* data);
private:
VirtualTextureInfo* m_info;
int m_size;
FILE* m_file;
};
// TileGenerator
class TileGenerator
{
public:
TileGenerator(VirtualTextureInfo* _info);
~TileGenerator();
bool generate(const bx::FilePath& filename);
private:
void CopyTile(SimpleImage& image, Page request);
private:
VirtualTextureInfo* m_info;
PageIndexer* m_indexer;
TileDataFile* m_tileDataFile;
int m_tilesize;
int m_pagesize;
bimg::ImageContainer* m_sourceImage;
SimpleImage* m_page1Image;
SimpleImage* m_page2Image;
SimpleImage* m_2xtileImage;
SimpleImage* m_4xtileImage;
SimpleImage* m_tileImage;
};
} // namespace vt

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 MiB

View File

@ -449,6 +449,7 @@ or _OPTIONS["with-combined-examples"] then
, "37-gpudrivenrendering"
, "38-bloom"
, "39-assao"
, "40-svt"
)
-- C99 source doesn't compile under WinRT settings