Last active
October 22, 2018 13:20
-
-
Save PredatorMF/18c8f50d72296f427eb6b2bdfa729dad to your computer and use it in GitHub Desktop.
Urho3D TurboBadger integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Urho3D/UI/Window.h> | |
#include <Urho3D/Core/Context.h> | |
#include <Urho3D/Core/Object.h> | |
#include <Urho3D/Core/CoreEvents.h> | |
#include <Urho3D/UI/UI.h> | |
#include <Urho3D/UI/UIElement.h> | |
#include <Urho3D/UI/UIEvents.h> | |
#include <Urho3D/Input/Input.h> | |
#include <Urho3D/Graphics/Graphics.h> | |
#include <Urho3D/Graphics/GraphicsEvents.h> | |
#include <Urho3D/Graphics/VertexBuffer.h> | |
#include <Urho3D/Graphics/Texture2D.h> | |
#include <Urho3D/Resource/ResourceCache.h> | |
#include <Urho3D/IO/FileSystem.h> | |
#include <Urho3D/Input/InputEvents.h> | |
#include <tb_font_renderer.h> | |
#include <tb_widgets.h> | |
#include <tb_bitmap_fragment.h> | |
#include <tb_system.h> | |
#include <tb_msg.h> | |
#include <tb_language.h> | |
#include <animation/tb_animation.h> | |
#include <animation/tb_widget_animation.h> | |
#include "STB/stb_image.h" | |
#include <SDL/SDL.h> | |
#include "gui/tb_ui_renderer.h" | |
#define QAL_VAL 0x60000000 // value to offset qualifier keys from all other keys in the same hash map | |
#ifdef TB_FONT_RENDERER_TBBF | |
void register_tbbf_font_renderer(); | |
#endif | |
#ifdef TB_FONT_RENDERER_STB | |
void register_stb_font_renderer(); | |
#endif | |
#ifdef TB_FONT_RENDERER_FREETYPE | |
void register_freetype_font_renderer(); | |
#endif | |
namespace Urho3D { | |
namespace { | |
static Context* g_context = 0; | |
} // namespace | |
UTBBitmap::UTBBitmap(TBUI* renderer) | |
: renderer_(renderer), width_(0), height_(0) { | |
} | |
UTBBitmap::~UTBBitmap() { | |
renderer_->FlushBitmap(this); | |
texture_.Reset(); | |
} | |
bool UTBBitmap::Init(int width, int height, tb::uint32 *data) { | |
texture_ = SharedPtr<Texture2D>(new Texture2D(renderer_->GetContext())); | |
width_ = width; | |
height_ = height; | |
// set texture format | |
texture_->SetMipsToSkip(QUALITY_LOW, 0); | |
texture_->SetNumLevels(1); | |
texture_->SetSize(width_, height_, Graphics::GetRGBAFormat()); | |
// set uv modes | |
texture_->SetAddressMode(COORD_U, ADDRESS_WRAP); | |
texture_->SetAddressMode(COORD_V, ADDRESS_WRAP), | |
texture_->SetBorderColor(Color(0.0f, 0.0f, 0.0f, 0.0f)); | |
SetData(data); | |
return true; | |
} | |
void UTBBitmap::SetData(tb::uint32 *_pdata) { | |
renderer_->FlushBitmap(this); | |
texture_->SetData(0, 0, 0, width_, height_, _pdata); | |
} | |
UTBMultiTexture::UTBMultiTexture(Context* context) | |
: Texture2D(context), vs_(0), ps_(0) { | |
} | |
class TBUIRootWidget : public tb::TBWidget { | |
public: | |
// For safe typecasting | |
TBOBJECT_SUBCLASS(TBUIRootWidget, tb::TBWidget) | |
TBUIRootWidget(TBUI* renderer) : renderer_(renderer) {} | |
virtual void OnInvalid() { | |
renderer_->OnRootRepaint(); | |
}; | |
TBUI* GetRenderer() { return renderer_; } | |
private: | |
TBUI* renderer_; | |
}; | |
// static | |
TBUI* TBUI::_instance = 0; | |
// static | |
TBUI* TBUI::Instance() { | |
return _instance; | |
} | |
TBUI::TBUI(Context* context) | |
: Object(context) | |
, TBRendererBatcher() | |
, needs_repaint_(false) | |
, mouse_buttons_(0) { | |
_instance = this; | |
g_context = context; | |
// Do 10 repaints at the beginning | |
repaint_count_hack_ = 10; | |
// init tb core | |
tb_core_init(this); | |
root_ = new TBUIRootWidget(this); | |
root_->Invalidate(); | |
root_->InvalidateStates(); | |
vertexBuffer_ = new VertexBuffer(context_); | |
Graphics* graphics = GetSubsystem<Graphics>(); | |
OnResizeWin(graphics->GetWidth(), graphics->GetHeight()); | |
} | |
TBUI::~TBUI() { | |
_instance = 0; | |
vertex_data_.Clear(); | |
batches_.Clear(); | |
uKeytoTBkeyMap.Clear(); | |
tb::TBWidgetsAnimationManager::Shutdown(); | |
// shutdown | |
tb::tb_core_shutdown(); | |
delete root_; | |
} | |
tb::TBWidget& TBUI::Root() { | |
return *root_; | |
} | |
void TBUI::OnResizeWin(int width, int height) { | |
m_screen_rect = tb::TBRect(0, 0, width, height); | |
root_->SetRect(m_screen_rect); | |
} | |
void TBUI::Init() { | |
ResourceCache* cache = GetSubsystem<ResourceCache>(); | |
// load resources | |
LoadDefaultResources(); | |
// map keys | |
CreateKeyMap(); | |
// register handlers | |
RegisterHandlers(); | |
} | |
void TBUI::Shutdown() { | |
} | |
void TBUI::LoadDefaultResources() { | |
using namespace tb; | |
g_tb_lng->Load("TBUI/resources/language/lng_en.tb.txt"); | |
// Load the default skin, and override skin that contains the graphics specific to the demo. | |
g_tb_skin->Load("TBUI/resources/default_skin/skin.tb.txt"); | |
// **README** | |
// - define TB_FONT_RENDERER_FREETYPE in tb_config.h for non-demo | |
#ifdef TB_FONT_RENDERER_TBBF | |
register_tbbf_font_renderer(); | |
#endif | |
#ifdef TB_FONT_RENDERER_STB | |
register_stb_font_renderer(); | |
#endif | |
#ifdef TB_FONT_RENDERER_FREETYPE | |
register_freetype_font_renderer(); | |
#endif | |
// Add fonts we can use to the font manager. | |
#if defined(TB_FONT_RENDERER_STB) || defined(TB_FONT_RENDERER_FREETYPE) | |
g_font_manager->AddFontInfo("Fonts/Roboto-Regular.ttf", "Roboto"); | |
g_font_manager->AddFontInfo("Fonts/Roboto-Bold.ttf", "Roboto-Bold"); | |
g_font_manager->AddFontInfo("Fonts/fontawesome-webfont.ttf", "fa"); | |
#endif | |
#ifdef TB_FONT_RENDERER_TBBF | |
g_font_manager->AddFontInfo("TBUI/resources/default_font/segoe_white_with_shadow.tb.txt", "Segoe"); | |
g_font_manager->AddFontInfo("TBUI/fonts/neon.tb.txt", "Neon"); | |
g_font_manager->AddFontInfo("TBUI/fonts/orangutang.tb.txt", "Orangutang"); | |
g_font_manager->AddFontInfo("TBUI/fonts/orange.tb.txt", "Orange"); | |
#endif | |
// Set the default font description for widgets to one of the fonts we just added | |
TBFontDescription fd; | |
#if !defined(TB_FONT_RENDERER_FREETYPE) | |
fd.SetID(TBIDC("Segoe")); | |
#else | |
fd.SetID(TBIDC("Roboto")); | |
#endif | |
fd.SetSize(g_tb_skin->GetDimensionConverter()->DpToPx(14)); | |
g_font_manager->SetDefaultFontDescription(fd); | |
// Create the font now. | |
TBFontFace *font = g_font_manager->CreateFontFace(g_font_manager->GetDefaultFontDescription()); | |
// Render some glyphs in one go now since we know we are going to use them. It would work fine | |
// without this since glyphs are rendered when needed, but with some extra updating of the glyph bitmap. | |
if (font) { | |
font->RenderGlyphs(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~•·åäöÅÄÖ"); | |
} | |
root_->SetSkinBg(TBIDC("background")); | |
TBWidgetsAnimationManager::Init(); | |
} | |
void TBUI::CreateKeyMap() { | |
using namespace tb; | |
// special keys | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_UP, TB_KEY_UP)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_DOWN, TB_KEY_DOWN)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_LEFT, TB_KEY_LEFT)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_RIGHT, TB_KEY_RIGHT)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_PAGEUP, TB_KEY_PAGE_UP)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_PAGEDOWN, TB_KEY_PAGE_DOWN)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_HOME, TB_KEY_HOME)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_END, TB_KEY_END)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_TAB, TB_KEY_TAB)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_BACKSPACE, TB_KEY_BACKSPACE)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_INSERT, TB_KEY_INSERT)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_DELETE, TB_KEY_DELETE)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_RETURN, TB_KEY_ENTER)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_ESCAPE, TB_KEY_ESC)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F1, TB_KEY_F1)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F2, TB_KEY_F2)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F3, TB_KEY_F3)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F4, TB_KEY_F4)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F5, TB_KEY_F5)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F6, TB_KEY_F6)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F7, TB_KEY_F7)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F8, TB_KEY_F8)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F9, TB_KEY_F9)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F10, TB_KEY_F10)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F11, TB_KEY_F11)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(KEY_F12, TB_KEY_F12)); | |
// qualifiers: add QAL_VAL to qual keys to separate their range from rest of the keys | |
uKeytoTBkeyMap.Insert(Pair<int, int>(QUAL_SHIFT + QAL_VAL, TB_SHIFT)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(QUAL_CTRL + QAL_VAL, TB_CTRL)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(QUAL_ALT + QAL_VAL, TB_ALT)); | |
uKeytoTBkeyMap.Insert(Pair<int, int>(QUAL_ANY + QAL_VAL, TB_SUPER)); | |
} | |
tb::TBBitmap* TBUI::CreateBitmap(int width, int height, tb::uint32 *data) { | |
using namespace tb; | |
UTBBitmap *bitmap = new UTBBitmap(this); | |
if (!bitmap->Init(width, height, data)) | |
{ | |
delete bitmap; | |
return nullptr; | |
} | |
return bitmap; | |
} | |
void TBUI::RenderBatch(Batch* batch) { | |
using namespace tb; | |
if (!batch->vertex_count) | |
return; | |
Texture2D* texture = NULL; | |
if (batch->bitmap) { | |
auto* tbuibitmap = (UTBBitmap*)batch->bitmap; | |
if (tbuibitmap->texture_) | |
texture = tbuibitmap->texture_; | |
} | |
UIBatch b(0, BLEND_ALPHA, scissor_, texture, &vertex_data_); | |
unsigned begin = b.vertexData_->Size(); | |
b.vertexData_->Resize(begin + batch->vertex_count * UI_VERTEX_SIZE); | |
float* dest = &(b.vertexData_->At(begin)); | |
b.vertexEnd_ = b.vertexData_->Size(); | |
for (int i = 0; i < batch->vertex_count; i++) { | |
Vertex* v = &batch->vertex[i]; | |
dest[0] = v->x; | |
dest[1] = v->y; | |
dest[2] = 0.0f; | |
((unsigned&)dest[3]) = v->col; | |
dest[4] = v->u; | |
dest[5] = v->v; | |
dest += UI_VERTEX_SIZE; | |
} | |
UIBatch::AddOrMerge(b, batches_); | |
} | |
void TBUI::SetClipRect(const tb::TBRect &rect) { | |
scissor_.top_ = rect.y; | |
scissor_.bottom_ = rect.y + rect.h; | |
scissor_.left_ = rect.x; | |
scissor_.right_ = rect.x + rect.w; | |
} | |
void TBUI::BeginPaint(int render_target_w, int render_target_h) { | |
vertex_data_.Clear(); | |
batches_.Clear(); | |
TBRendererBatcher::BeginPaint(render_target_w, render_target_h); | |
} | |
void TBUI::EndPaint() { | |
TBRendererBatcher::EndPaint(); | |
// Update quad geometry into the vertex buffer | |
// Resize the vertex buffer first if too small or much too large | |
unsigned numVertices = vertex_data_.Size() / UI_VERTEX_SIZE; | |
if (vertexBuffer_->GetVertexCount() < numVertices || vertexBuffer_->GetVertexCount() > numVertices * 2) | |
vertexBuffer_->SetSize(numVertices, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true); | |
if (!vertex_data_.Empty()) | |
vertexBuffer_->SetData(&vertex_data_[0]); | |
else | |
vertexBuffer_->SetSize(0, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true); | |
} | |
void TBUI::Render() { | |
if (batches_.Empty()) { | |
return; | |
} | |
Graphics* graphics = GetSubsystem<Graphics>(); | |
IntVector2 size; | |
size.x_ = graphics->GetWidth(); | |
size.y_ = graphics->GetHeight(); | |
bool scissorEnabled = true; | |
IntRect rect(0, 0, size.x_, size.y_); | |
Vector2 invScreenSize(1.0f / (float)size.x_, 1.0f / (float)size.y_); | |
Vector2 scale(2.0f * invScreenSize.x_, -2.0f * invScreenSize.y_); | |
Vector2 offset(-1.0f, 1.0f); | |
Matrix4 projection(Matrix4::IDENTITY); | |
projection.m00_ = scale.x_; | |
projection.m03_ = offset.x_; | |
projection.m11_ = scale.y_; | |
projection.m13_ = offset.y_; | |
projection.m22_ = 1.0f; | |
projection.m23_ = 0.0f; | |
projection.m33_ = 1.0f; | |
graphics->ClearParameterSources(); | |
graphics->SetColorWrite(true); | |
graphics->SetCullMode(CULL_NONE); | |
graphics->SetDepthTest(CMP_ALWAYS); | |
graphics->SetDepthWrite(false); | |
graphics->SetFillMode(FILL_SOLID); | |
graphics->SetStencilTest(false); | |
graphics->SetViewport(rect); | |
graphics->SetVertexBuffer(vertexBuffer_); | |
ShaderVariation* noTextureVS = graphics->GetShader(VS, "Imgui", "VERTEXCOLOR"); | |
ShaderVariation* diffTextureVS = graphics->GetShader(VS, "Imgui", "DIFFMAP VERTEXCOLOR"); | |
ShaderVariation* noTexturePS = graphics->GetShader(PS, "Imgui", "VERTEXCOLOR"); | |
ShaderVariation* diffTexturePS = graphics->GetShader(PS, "Imgui", "DIFFMAP VERTEXCOLOR"); | |
ShaderVariation* diffMaskTexturePS = graphics->GetShader(PS, "Imgui", "DIFFMAP ALPHAMASK VERTEXCOLOR"); | |
ShaderVariation* alphaTexturePS = graphics->GetShader(PS, "Imgui", "ALPHAMAP VERTEXCOLOR"); | |
unsigned alphaFormat = Graphics::GetAlphaFormat(); | |
for (auto batch: batches_) { | |
if (batch.vertexStart_ == batch.vertexEnd_) | |
continue; | |
ShaderVariation* ps; | |
ShaderVariation* vs; | |
bool is_multitexture = false; | |
if (batch.texture_) | |
is_multitexture = batch.texture_->IsInstanceOf<UTBMultiTexture>(); | |
if (!batch.texture_) { | |
ps = noTexturePS; | |
vs = noTextureVS; | |
} else { | |
// if texture is Texture2D | |
if (!is_multitexture) { | |
// If texture contains only an alpha channel, use alpha shader (for fonts) | |
vs = diffTextureVS; | |
if (batch.texture_->GetFormat() == alphaFormat) | |
ps = alphaTexturePS; | |
else if (batch.blendMode_ != BLEND_ALPHA && batch.blendMode_ != BLEND_ADDALPHA && batch.blendMode_ != BLEND_PREMULALPHA) | |
ps = diffMaskTexturePS; | |
else | |
ps = diffTexturePS; | |
} else { | |
// when texture is UTBMultiTexture and has custom shaders | |
UTBMultiTexture* multitexture = batch.texture_->Cast<UTBMultiTexture>(); | |
vs = multitexture->vs_ ? multitexture->vs_ : diffTextureVS; | |
ps = multitexture->ps_ ? multitexture->ps_ : diffTexturePS; | |
} | |
} | |
graphics->SetShaders(vs, ps); | |
if (graphics->NeedParameterUpdate(SP_OBJECT, this)) | |
graphics->SetShaderParameter(VSP_MODEL, Matrix3x4::IDENTITY); | |
if (graphics->NeedParameterUpdate(SP_CAMERA, this)) | |
graphics->SetShaderParameter(VSP_VIEWPROJ, projection); | |
bool need_material_update = graphics->NeedParameterUpdate(SP_MATERIAL, this); | |
if (need_material_update) | |
graphics->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f)); | |
graphics->SetBlendMode(batch.blendMode_); | |
graphics->SetScissorTest(scissorEnabled, batch.scissor_); | |
if (!batch.texture_ || !batch.texture_->IsInstanceOf<UTBMultiTexture>()) { | |
graphics->SetTexture(0, batch.texture_); | |
} else if (is_multitexture) { | |
UTBMultiTexture* multitexture = batch.texture_->Cast<UTBMultiTexture>(); | |
// apply shader parameters | |
for (auto param : multitexture->shader_parameters_) { | |
graphics->SetShaderParameter(param.first_, param.second_); | |
} | |
// apply textures | |
for (auto it = multitexture->additional_textures_.Begin(); it != multitexture->additional_textures_.End(); ++it) { | |
graphics->SetTexture(it->first_, it->second_); | |
} | |
} | |
graphics->Draw(TRIANGLE_LIST, batch.vertexStart_ / UI_VERTEX_SIZE, (batch.vertexEnd_ - batch.vertexStart_) / | |
UI_VERTEX_SIZE); | |
} | |
} | |
void TBUI::OnRootRepaint() { | |
if (!needs_repaint_) { | |
needs_repaint_ = true; | |
} | |
} | |
void TBUI::RegisterHandlers() { | |
// timer | |
SubscribeToEvent(E_UPDATE, URHO3D_HANDLER(TBUI, HandleUpdate)); | |
// screen resize and renderer | |
SubscribeToEvent(E_SCREENMODE, URHO3D_HANDLER(TBUI, HandleScreenMode)); | |
// input | |
SubscribeToEvent(E_SDLRAWINPUT, URHO3D_HANDLER(TBUI, OnRawEvent)); | |
} | |
void TBUI::HandleUpdate(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
// msg timer | |
double t = TBMessageHandler::GetNextMessageFireTime(); | |
if (t != TB_NOT_SOON && t <= TBSystem::GetTimeMS()) { | |
TBMessageHandler::ProcessMessages(); | |
} | |
} | |
void TBUI::HandleScreenMode(StringHash eventType, VariantMap& eventData) { | |
using namespace ScreenMode; | |
OnResizeWin(eventData[P_WIDTH].GetInt(), eventData[P_HEIGHT].GetInt()); | |
} | |
void TBUI::HandleEndFrame(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
TBAnimationManager::Update(); | |
TBWidgetValue *continuous_repaint_val = g_value_group.GetValue(TBIDC("continous-repaint")); | |
bool continuous_repaint = continuous_repaint_val ? !!continuous_repaint_val->GetInt() : 0; | |
if (continuous_repaint || (repaint_count_hack_ > 0) || needs_repaint_ || TBAnimationManager::HasAnimationsRunning()) { | |
if (repaint_count_hack_ > 0 && !needs_repaint_) | |
repaint_count_hack_--; | |
root_->InvokeProcessStates(); | |
root_->InvokeProcess(); | |
tb::TBRect root_rect(root_->GetRect()); | |
scissor_ = Urho3D::IntRect(0, 0, root_rect.w, root_rect.h); | |
BeginPaint(root_rect.w, root_rect.h); | |
root_->InvokePaint(TBWidget::PaintProps()); | |
// If animations are running, reinvalidate immediately | |
if (TBAnimationManager::HasAnimationsRunning()) { | |
root_->Invalidate(); | |
} | |
EndPaint(); | |
needs_repaint_ = false; | |
} | |
Render(); | |
} | |
void TBUI::HandleMouseButtonDown(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
using namespace MouseButtonDown; | |
int mouseButtons = eventData[P_BUTTONS].GetInt(); | |
int qualifiers = eventData[P_QUALIFIERS].GetInt(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
// exit if not the left mb | |
if (mouseButtons != MOUSEB_LEFT) | |
return; | |
root_->InvokePointerDown(last_mouse_pos_.x_, last_mouse_pos_.y_, 1, modKey, false); | |
} | |
void TBUI::HandleMouseButtonUp(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
using namespace MouseButtonUp; | |
int qualifiers = eventData[P_QUALIFIERS].GetInt(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
root_->InvokePointerUp(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false); | |
} | |
void TBUI::HandleMouseMove(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
using namespace MouseMove; | |
int qualifiers = eventData[P_QUALIFIERS].GetInt(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
last_mouse_pos_ = IntVector2(eventData[P_X].GetInt(), eventData[P_Y].GetInt()); | |
root_->InvokePointerMove(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false); | |
} | |
void TBUI::HandleMouseWheel(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
using namespace MouseWheel; | |
int qualifiers = eventData[P_QUALIFIERS].GetInt(); | |
int delta = eventData[P_WHEEL].GetInt(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
root_->InvokeWheel(last_mouse_pos_.x_, last_mouse_pos_.y_, 0, -delta, modKey); | |
} | |
void TBUI::HandleKeyDown(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
using namespace KeyDown; | |
int qualifiers = eventData[P_QUALIFIERS].GetInt(); | |
int key = eventData[P_KEY].GetInt(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
SPECIAL_KEY spKey = (SPECIAL_KEY)FindTBKey(key); | |
// exit if not a special key | |
if (spKey == TB_KEY_UNDEFINED) | |
return; | |
root_->InvokeKey(key, spKey, modKey, true); | |
} | |
void TBUI::HandleKeyUp(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
using namespace KeyUp; | |
int qualifiers = eventData[P_QUALIFIERS].GetInt(); | |
int key = eventData[P_KEY].GetInt(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
SPECIAL_KEY spKey = (SPECIAL_KEY)FindTBKey(key); | |
root_->InvokeKey(key, spKey, modKey, false); | |
} | |
void TBUI::HandleTextInput(StringHash eventType, VariantMap& eventData) { | |
using namespace tb; | |
using namespace TextInput; | |
int qualifiers = GetSubsystem<Input>()->GetQualifiers(); | |
int key = (int)eventData[P_TEXT].GetString().CString()[0]; | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
root_->InvokeKey(key, TB_KEY_UNDEFINED, modKey, true); | |
} | |
static bool InvokeShortcut(SDL_Scancode code, tb::SPECIAL_KEY special_key, tb::MODIFIER_KEYS modifierkeys, bool down) { | |
using namespace tb; | |
bool shortcut_key = (modifierkeys & TB_CTRL) ? true : false; | |
if (!TBWidget::focused_widget || !down || !shortcut_key) | |
return false; | |
bool reverse_key = (modifierkeys & TB_SHIFT) ? true : false; | |
TBID id; | |
if (code == SDL_SCANCODE_X) | |
id = TBIDC("cut"); | |
else if (code == SDL_SCANCODE_C || special_key == TB_KEY_INSERT) | |
id = TBIDC("copy"); | |
else if (code == SDL_SCANCODE_V || (special_key == TB_KEY_INSERT && reverse_key)) | |
id = TBIDC("paste"); | |
else if (code == SDL_SCANCODE_A) | |
id = TBIDC("selectall"); | |
else if (code == SDL_SCANCODE_Z || code == SDL_SCANCODE_Y) | |
{ | |
bool undo = code == SDL_SCANCODE_Z; | |
if (reverse_key) | |
undo = !undo; | |
id = undo ? TBIDC("undo") : TBIDC("redo"); | |
} | |
else if (code == SDL_SCANCODE_N) | |
id = TBIDC("new"); | |
else if (code == SDL_SCANCODE_O) | |
id = TBIDC("open"); | |
else if (code == SDL_SCANCODE_S) | |
id = TBIDC("save"); | |
else if (code == SDL_SCANCODE_W) | |
id = TBIDC("close"); | |
else if (special_key == TB_KEY_PAGE_UP) | |
id = TBIDC("prev_doc"); | |
else if (special_key == TB_KEY_PAGE_DOWN) | |
id = TBIDC("next_doc"); | |
else | |
return false; | |
TBWidgetEvent ev(EVENT_TYPE_SHORTCUT); | |
ev.modifierkeys = modifierkeys; | |
ev.ref_id = id; | |
return TBWidget::focused_widget->InvokeEvent(ev); | |
} | |
void TBUI::OnRawEvent(StringHash eventType, VariantMap& args) { | |
if (args[SDLRawInput::P_CONSUMED].GetBool()) | |
return; | |
using namespace tb; | |
auto evt = static_cast<SDL_Event*>(args[SDLRawInput::P_SDLEVENT].Get<void*>()); | |
bool handled = false; | |
switch (evt->type) | |
{ | |
case SDL_KEYUP: | |
case SDL_KEYDOWN: | |
{ | |
using namespace KeyUp; | |
int key = evt->key.keysym.sym; | |
int code = evt->key.keysym.scancode; | |
auto down = evt->type == SDL_KEYDOWN; | |
int qualifiers = 0; | |
if (evt->key.keysym.mod & KMOD_CTRL) | |
qualifiers |= QUAL_CTRL; | |
if (evt->key.keysym.mod & KMOD_ALT) | |
qualifiers |= QUAL_ALT; | |
if (evt->key.keysym.mod & KMOD_SHIFT) | |
qualifiers |= QUAL_SHIFT; | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
SPECIAL_KEY spKey = (SPECIAL_KEY)FindTBKey(key); | |
if (InvokeShortcut(evt->key.keysym.scancode, spKey, modKey, down)) | |
break; | |
// exit if not a special key | |
if (spKey == TB_KEY_UNDEFINED && modKey == 0) | |
return; | |
root_->InvokeKey(0, spKey, modKey, down); | |
break; | |
} | |
case SDL_TEXTINPUT: | |
{ | |
using namespace tb; | |
using namespace TextInput; | |
int qualifiers = GetSubsystem<Input>()->GetQualifiers(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
const String& text = evt->text.text; | |
for (unsigned i = 0; i < text.LengthUTF8(); i += 1) { | |
int c = text.AtUTF8(i); | |
handled |= root_->InvokeKey(c, TB_KEY_UNDEFINED, modKey, true); | |
handled |= root_->InvokeKey(c, TB_KEY_UNDEFINED, modKey, false); | |
} | |
break; | |
} | |
case SDL_MOUSEWHEEL: | |
{ | |
using namespace tb; | |
int qualifiers = GetSubsystem<Input>()->GetQualifiers(); | |
int delta = evt->wheel.y; | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
handled |= root_->InvokeWheel(last_mouse_pos_.x_, last_mouse_pos_.y_, 0, -delta, modKey); | |
break; | |
} | |
case SDL_MOUSEBUTTONUP: | |
case SDL_MOUSEBUTTONDOWN: | |
{ | |
using namespace tb; | |
using namespace MouseButtonUp; | |
int qualifiers = GetSubsystem<Input>()->GetQualifiers(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
bool down = evt->type == SDL_MOUSEBUTTONDOWN; | |
if (down) { | |
if (evt->button.button == SDL_BUTTON_LEFT) | |
mouse_buttons_ |= BUTTON_LEFT; | |
if (evt->button.button == SDL_BUTTON_RIGHT) | |
mouse_buttons_ |= BUTTON_RIGHT; | |
if (evt->button.button == SDL_BUTTON_MIDDLE) | |
mouse_buttons_ |= BUTTON_MIDDLE; | |
} else { | |
if (evt->button.button == SDL_BUTTON_LEFT) | |
mouse_buttons_ &= BUTTON_LEFT; | |
if (evt->button.button == SDL_BUTTON_RIGHT) | |
mouse_buttons_ &= BUTTON_RIGHT; | |
if (evt->button.button == SDL_BUTTON_MIDDLE) | |
mouse_buttons_ &= BUTTON_MIDDLE; | |
} | |
/*if (!down && evt->button.button == SDL_BUTTON_RIGHT) { | |
//root_->InvokePointerUp(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false); | |
if (TBWidget::hovered_widget) { | |
TBWidget::hovered_widget->ConvertFromRoot(last_mouse_pos_.x_, last_mouse_pos_.y_); | |
TBWidgetEvent ev(EVENT_TYPE_CONTEXT_MENU, last_mouse_pos_.x_, last_mouse_pos_.y_, false, modKey); | |
handled |= TBWidget::hovered_widget->InvokeEvent(ev); | |
if (handled) | |
break; | |
} | |
}*/ | |
if (down) | |
handled |= root_->InvokePointerDown(last_mouse_pos_.x_, last_mouse_pos_.y_, evt->button.clicks, modKey, false); | |
else | |
handled |= root_->InvokePointerUp(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false); | |
} | |
case SDL_MOUSEMOTION: | |
{ | |
using namespace tb; | |
using namespace MouseMove; | |
int qualifiers = GetSubsystem<Input>()->GetQualifiers(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
last_mouse_pos_ = IntVector2(evt->motion.x, evt->motion.y); | |
root_->InvokePointerMove(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, false); | |
break; | |
} | |
case SDL_FINGERUP: | |
{ | |
int qualifiers = GetSubsystem<Input>()->GetQualifiers(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
handled |= root_->InvokePointerUp(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, true); | |
} | |
case SDL_FINGERDOWN: | |
{ | |
int qualifiers = GetSubsystem<Input>()->GetQualifiers(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
handled |= root_->InvokePointerDown(last_mouse_pos_.x_, last_mouse_pos_.y_, 1, modKey, true); | |
} | |
case SDL_FINGERMOTION: | |
{ | |
using namespace tb; | |
using namespace MouseMove; | |
int qualifiers = GetSubsystem<Input>()->GetQualifiers(); | |
MODIFIER_KEYS modKey = (MODIFIER_KEYS)FindTBKey(qualifiers + QAL_VAL); | |
last_mouse_pos_ = IntVector2(args[P_X].GetInt(), args[P_Y].GetInt()); | |
root_->InvokePointerMove(last_mouse_pos_.x_, last_mouse_pos_.y_, modKey, true); | |
break; | |
} | |
default: | |
break; | |
} | |
switch (evt->type) | |
{ | |
case SDL_KEYUP: | |
case SDL_KEYDOWN: | |
case SDL_TEXTINPUT: | |
args[SDLRawInput::P_CONSUMED] = handled; | |
break; | |
case SDL_MOUSEWHEEL: | |
case SDL_MOUSEBUTTONUP: | |
case SDL_MOUSEBUTTONDOWN: | |
case SDL_MOUSEMOTION: | |
case SDL_FINGERUP: | |
case SDL_FINGERDOWN: | |
case SDL_FINGERMOTION: | |
args[SDLRawInput::P_CONSUMED] = handled; | |
break; | |
default: | |
break; | |
} | |
} | |
// TB special and quality keys func | |
int TBUI::FindTBKey(int key) { | |
HashMap<int, int>::Iterator itr = uKeytoTBkeyMap.Find(key); | |
int itbkey = 0; | |
if (itr != uKeytoTBkeyMap.End()) | |
itbkey = itr->second_; | |
return itbkey; | |
} | |
class UTBFile : public tb::TBFile { | |
public: | |
UTBFile(Context *context) | |
: file_size_(0) | |
, context_(context) { | |
} | |
virtual ~UTBFile() { | |
if (file_) { | |
file_->Close(); | |
file_.Reset(); | |
} | |
} | |
bool OpenFile(const char* filename) { | |
ResourceCache* cache = context_->GetSubsystem<ResourceCache>(); | |
file_ = cache->GetFile(filename); | |
if (file_) { | |
file_size_ = file_->Seek((unsigned)-1); | |
file_->Seek(0); | |
} | |
return !!file_; | |
} | |
virtual long Size() { | |
return (long)file_size_; | |
} | |
virtual size_t Read(void *buf, size_t elemSize, size_t count) { | |
if (!file_) | |
return 0; | |
return file_->Read(buf, elemSize * count); | |
} | |
protected: | |
Context* context_; | |
SharedPtr<File> file_; | |
unsigned file_size_; | |
}; | |
} // namespace Urho3D | |
namespace tb { | |
// static | |
TBFile* TBFile::Open(const char *filename, tb::TBFile::TBFileMode) { | |
Urho3D::UTBFile* file = new Urho3D::UTBFile(Urho3D::g_context); | |
if (!file->OpenFile(filename)) { | |
delete file; | |
file = NULL; | |
} | |
return file; | |
} | |
// static | |
void TBSystem::RescheduleTimer(double fire_time) { | |
} | |
class STBI_Loader : public TBImageLoader { | |
public: | |
int width, height; | |
unsigned char *data; | |
STBI_Loader() : width(0), height(0), data(nullptr) {} | |
~STBI_Loader() { stbi_image_free(data); } | |
virtual int Width() { return width; } | |
virtual int Height() { return height; } | |
virtual uint32 *Data() { return (uint32*)data; } | |
}; | |
TBImageLoader *TBImageLoader::CreateFromFile(const char *filename) { | |
TBTempBuffer buf; | |
if (buf.AppendFile(filename)) { | |
int w, h, comp; | |
if (unsigned char *img_data = stbi_load_from_memory((unsigned char*)buf.GetData(), buf.GetAppendPos(), &w, &h, &comp, 4)) { | |
if (STBI_Loader *img = new STBI_Loader()) { | |
img->width = w; | |
img->height = h; | |
img->data = img_data; | |
return img; | |
} else | |
stbi_image_free(img_data); | |
} | |
} | |
return nullptr; | |
} | |
/** Empty the contents of the clipboard. */ | |
// static | |
void TBClipboard::Empty() { | |
SDL_SetClipboardText(""); | |
} | |
/** Return true if the clipboard currently contains text. */ | |
//static | |
bool TBClipboard::HasText() { | |
return SDL_HasClipboardText(); | |
} | |
/** Set the text of the clipboard in UTF-8 format. */ | |
// static | |
bool TBClipboard::SetText(const char *text) { | |
return SDL_SetClipboardText(text) == 0; | |
} | |
/** Get the text from the clipboard in UTF-8 format. | |
Returns true on success. */ | |
// static | |
bool TBClipboard::GetText(TBStr &text) { | |
char* sdl_text = SDL_GetClipboardText(); | |
text.Set(sdl_text); | |
SDL_free(sdl_text); | |
return true; | |
} | |
} // namespace tb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef __TBUI_RENDERER_H__ | |
#define __TBUI_RENDERER_H__ | |
#pragma once | |
#include "Urho3D/Graphics/Texture2D.h" | |
#include "Urho3D/UI/UIElement.h" | |
#include "Urho3D/Core/Object.h" | |
#include "tb_renderer.h" | |
#include "tb_widgets_reader.h" | |
#include "renderers/tb_renderer_batcher.h" | |
namespace Urho3D { | |
class Context; | |
class VertexBuffer; | |
class Texture2D; | |
class TBUIRootWidget; | |
class TBUI; | |
class ShaderVariation; | |
class UTBBitmap : public tb::TBBitmap, public tb::TBTypedObject { | |
public: | |
TBOBJECT_SUBCLASS(UTBBitmap, tb::TBTypedObject) | |
UTBBitmap(TBUI* renderer); | |
~UTBBitmap(); | |
virtual bool Init(int width, int height, tb::uint32 *data); | |
virtual void SetData(tb::uint32 *_pdata); | |
virtual int Width() { return width_; } | |
virtual int Height() { return height_; } | |
TBUI* renderer_; | |
SharedPtr<Texture2D> texture_; | |
int width_; | |
int height_; | |
}; | |
class UTBMultiTexture : public Texture2D { | |
URHO3D_OBJECT(UTBMultiTexture, Texture2D) | |
public: | |
UTBMultiTexture(Context* context); | |
HashMap<int, SharedPtr<Texture2D>> additional_textures_; | |
ShaderVariation* ps_; | |
ShaderVariation* vs_; | |
VariantMap shader_parameters_; | |
}; | |
class TBUI : public Object, public tb::TBRendererBatcher { | |
URHO3D_OBJECT(TBUI, Object) | |
public: | |
typedef enum { | |
BUTTON_LEFT = 1 << 0, | |
BUTTON_RIGHT = 1 << 1, | |
BUTTON_MIDDLE = 1 << 2, | |
} MouseButtons; | |
TBUI(Context* context); | |
virtual ~TBUI(); | |
static TBUI* Instance(); | |
void Init(); | |
void Shutdown(); | |
void LoadDefaultResources(); | |
tb::TBWidget& Root(); | |
void SetClipRect(const tb::TBRect &rect); | |
// override functions | |
virtual void BeginPaint(int width, int height) override; | |
virtual void EndPaint() override; | |
virtual tb::TBBitmap* CreateBitmap(int width, int height, tb::uint32* data) override; | |
virtual void RenderBatch(Batch* batch); | |
void Render(); | |
void HandleEndFrame(StringHash eventType, VariantMap& eventData); | |
/// Returns currently pressed mouse buttons | |
int GetPressedMouseButtons() const { return mouse_buttons_; } | |
private: | |
friend class TBUIRootWidget; | |
bool needs_repaint_; | |
int repaint_count_hack_; | |
IntRect scissor_; | |
TBUIRootWidget* root_; | |
PODVector<float> vertex_data_; | |
SharedPtr<VertexBuffer> vertexBuffer_; | |
PODVector<UIBatch> batches_; | |
HashMap<int, int> uKeytoTBkeyMap; | |
IntVector2 last_mouse_pos_; | |
int mouse_buttons_; | |
static TBUI* _instance; | |
void OnResizeWin(int width, int height); | |
void CreateKeyMap(); | |
void RegisterHandlers(); | |
void HandleUpdate(StringHash eventType, VariantMap& eventData); | |
// renderer | |
void HandleScreenMode(StringHash eventType, VariantMap& eventData); | |
// inputs | |
void HandleMouseButtonDown(StringHash eventType, VariantMap& eventData); | |
void HandleMouseButtonUp(StringHash eventType, VariantMap& eventData); | |
void HandleMouseMove(StringHash eventType, VariantMap& eventData); | |
void HandleMouseWheel(StringHash eventType, VariantMap& eventData); | |
void HandleKeyDown(StringHash eventType, VariantMap& eventData); | |
void HandleKeyUp(StringHash eventType, VariantMap& eventData); | |
void HandleTextInput(StringHash eventType, VariantMap& eventData); | |
void OnRawEvent(StringHash eventType, VariantMap& args); | |
// TB special and quality keys func | |
int FindTBKey(int key); | |
void OnRootRepaint(); | |
}; | |
} // namespace Urho3D | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment