F.E.I.S/include/imgui/imgui-SFML.cpp
2019-01-03 23:20:35 +01:00

782 lines
26 KiB
C++

#include "imgui-SFML.h"
#include <imgui.h>
#include <SFML/OpenGL.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Texture.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/Touch.hpp>
#include <SFML/Window/Window.hpp>
#include <cmath> // abs
#include <cstddef> // offsetof, NULL
#include <cassert>
#ifdef ANDROID
#ifdef USE_JNI
#include <jni.h>
#include <android/native_activity.h>
#include <SFML/System/NativeActivity.hpp>
static bool s_wantTextInput = false;
int openKeyboardIME()
{
ANativeActivity *activity = sf::getNativeActivity();
JavaVM* vm = activity->vm;
JNIEnv* env = activity->env;
JavaVMAttachArgs attachargs;
attachargs.version = JNI_VERSION_1_6;
attachargs.name = "NativeThread";
attachargs.group = NULL;
jint res = vm->AttachCurrentThread(&env, &attachargs);
if (res == JNI_ERR)
return EXIT_FAILURE;
jclass natact = env->FindClass("android/app/NativeActivity");
jclass context = env->FindClass("android/content/Context");
jfieldID fid = env->GetStaticFieldID(context, "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
jobject svcstr = env->GetStaticObjectField(context, fid);
jmethodID getss = env->GetMethodID(natact, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
jobject imm_obj = env->CallObjectMethod(activity->clazz, getss, svcstr);
jclass imm_cls = env->GetObjectClass(imm_obj);
jmethodID toggleSoftInput = env->GetMethodID(imm_cls, "toggleSoftInput", "(II)V");
env->CallVoidMethod(imm_obj, toggleSoftInput, 2, 0);
env->DeleteLocalRef(imm_obj);
env->DeleteLocalRef(imm_cls);
env->DeleteLocalRef(svcstr);
env->DeleteLocalRef(context);
env->DeleteLocalRef(natact);
vm->DetachCurrentThread();
return EXIT_SUCCESS;
}
int closeKeyboardIME()
{
ANativeActivity *activity = sf::getNativeActivity();
JavaVM* vm = activity->vm;
JNIEnv* env = activity->env;
JavaVMAttachArgs attachargs;
attachargs.version = JNI_VERSION_1_6;
attachargs.name = "NativeThread";
attachargs.group = NULL;
jint res = vm->AttachCurrentThread(&env, &attachargs);
if (res == JNI_ERR)
return EXIT_FAILURE;
jclass natact = env->FindClass("android/app/NativeActivity");
jclass context = env->FindClass("android/content/Context");
jfieldID fid = env->GetStaticFieldID(context, "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
jobject svcstr = env->GetStaticObjectField(context, fid);
jmethodID getss = env->GetMethodID(natact, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;");
jobject imm_obj = env->CallObjectMethod(activity->clazz, getss, svcstr);
jclass imm_cls = env->GetObjectClass(imm_obj);
jmethodID toggleSoftInput = env->GetMethodID(imm_cls, "toggleSoftInput", "(II)V");
env->CallVoidMethod(imm_obj, toggleSoftInput, 1, 0);
env->DeleteLocalRef(imm_obj);
env->DeleteLocalRef(imm_cls);
env->DeleteLocalRef(svcstr);
env->DeleteLocalRef(context);
env->DeleteLocalRef(natact);
vm->DetachCurrentThread();
return EXIT_SUCCESS;
}
#endif
#endif
// Supress warnings caused by converting from uint to void* in pCmd->TextureID
#ifdef __clang__
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
#elif defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
#endif
namespace
{
// data
static bool s_windowHasFocus = false;
static bool s_mousePressed[3] = { false, false, false };
static bool s_touchDown[3] = { false, false, false };
static bool s_mouseMoved = false;
static sf::Vector2i s_touchPos;
static sf::Texture* s_fontTexture = NULL; // owning pointer to internal font atlas which is used if user doesn't set custom sf::Texture.
static const unsigned int NULL_JOYSTICK_ID = sf::Joystick::Count;
static unsigned int s_joystickId = NULL_JOYSTICK_ID;
static const unsigned int NULL_JOYSTICK_BUTTON = sf::Joystick::ButtonCount;
static unsigned int s_joystickMapping[ImGuiNavInput_COUNT];
struct StickInfo {
sf::Joystick::Axis xAxis;
sf::Joystick::Axis yAxis;
bool xInverted;
bool yInverted;
float threshold;
};
StickInfo s_dPadInfo;
StickInfo s_lStickInfo;
// various helper functions
ImVec2 getTopLeftAbsolute(const sf::FloatRect& rect);
ImVec2 getDownRightAbsolute(const sf::FloatRect& rect);
void RenderDrawLists(ImDrawData* draw_data); // rendering callback function prototype
// Implementation of ImageButton overload
bool imageButtonImpl(const sf::Texture& texture, const sf::FloatRect& textureRect, const sf::Vector2f& size, const int framePadding,
const sf::Color& bgColor, const sf::Color& tintColor);
// Default mapping is XInput gamepad mapping
void initDefaultJoystickMapping();
// Returns first id of connected joystick
unsigned int getConnectedJoystickId();
void updateJoystickActionState(ImGuiIO& io, ImGuiNavInput_ action);
void updateJoystickDPadState(ImGuiIO& io);
void updateJoystickLStickState(ImGuiIO& io);
}
namespace ImGui
{
namespace SFML
{
void Init(sf::RenderWindow& window, bool loadDefaultFont)
{
Init(window, window, loadDefaultFont);
}
void Init(sf::Window& window, sf::RenderTarget& target, bool loadDefaultFont)
{
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;
// init keyboard mapping
io.KeyMap[ImGuiKey_Tab] = sf::Keyboard::Tab;
io.KeyMap[ImGuiKey_LeftArrow] = sf::Keyboard::Left;
io.KeyMap[ImGuiKey_RightArrow] = sf::Keyboard::Right;
io.KeyMap[ImGuiKey_UpArrow] = sf::Keyboard::Up;
io.KeyMap[ImGuiKey_DownArrow] = sf::Keyboard::Down;
io.KeyMap[ImGuiKey_PageUp] = sf::Keyboard::PageUp;
io.KeyMap[ImGuiKey_PageDown] = sf::Keyboard::PageDown;
io.KeyMap[ImGuiKey_Home] = sf::Keyboard::Home;
io.KeyMap[ImGuiKey_End] = sf::Keyboard::End;
io.KeyMap[ImGuiKey_Insert] = sf::Keyboard::Insert;
#ifdef ANDROID
io.KeyMap[ImGuiKey_Backspace] = sf::Keyboard::Delete;
#else
io.KeyMap[ImGuiKey_Delete] = sf::Keyboard::Delete;
io.KeyMap[ImGuiKey_Backspace] = sf::Keyboard::BackSpace;
#endif
io.KeyMap[ImGuiKey_Space] = sf::Keyboard::Space;
io.KeyMap[ImGuiKey_Enter] = sf::Keyboard::Return;
io.KeyMap[ImGuiKey_Escape] = sf::Keyboard::Escape;
io.KeyMap[ImGuiKey_A] = sf::Keyboard::A;
io.KeyMap[ImGuiKey_C] = sf::Keyboard::C;
io.KeyMap[ImGuiKey_V] = sf::Keyboard::V;
io.KeyMap[ImGuiKey_X] = sf::Keyboard::X;
io.KeyMap[ImGuiKey_Y] = sf::Keyboard::Y;
io.KeyMap[ImGuiKey_Z] = sf::Keyboard::Z;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
s_joystickId = getConnectedJoystickId();
for (unsigned int i = 0; i < ImGuiNavInput_COUNT; i++) {
s_joystickMapping[i] = NULL_JOYSTICK_BUTTON;
}
initDefaultJoystickMapping();
// init rendering
io.DisplaySize = static_cast<sf::Vector2f>(target.getSize());
if (s_fontTexture) { // delete previously created texture
delete s_fontTexture;
}
s_fontTexture = new sf::Texture;
if (loadDefaultFont) {
// this will load default font automatically
// No need to call AddDefaultFont
UpdateFontTexture();
}
s_windowHasFocus = window.hasFocus();
}
void ProcessEvent(const sf::Event& event)
{
if (s_windowHasFocus) {
ImGuiIO& io = ImGui::GetIO();
switch (event.type) {
case sf::Event::MouseMoved:
s_mouseMoved = true;
break;
case sf::Event::MouseButtonPressed: // fall-through
case sf::Event::MouseButtonReleased:
{
int button = event.mouseButton.button;
if (event.type == sf::Event::MouseButtonPressed &&
button >= 0 && button < 3) {
s_mousePressed[event.mouseButton.button] = true;
}
}
break;
case sf::Event::TouchBegan: // fall-through
case sf::Event::TouchEnded:
{
s_mouseMoved = false;
int button = event.touch.finger;
if (event.type == sf::Event::TouchBegan &&
button >= 0 && button < 3) {
s_touchDown[event.touch.finger] = true;
}
}
break;
case sf::Event::MouseWheelMoved:
io.MouseWheel += static_cast<float>(event.mouseWheel.delta);
break;
case sf::Event::KeyPressed: // fall-through
case sf::Event::KeyReleased:
io.KeysDown[event.key.code] = (event.type == sf::Event::KeyPressed);
io.KeyCtrl = event.key.control;
io.KeyShift = event.key.shift;
io.KeyAlt = event.key.alt;
break;
case sf::Event::TextEntered:
if (event.text.unicode > 0 && event.text.unicode < 0x10000) {
io.AddInputCharacter(static_cast<ImWchar>(event.text.unicode));
}
break;
case sf::Event::JoystickConnected:
if (s_joystickId == NULL_JOYSTICK_ID) {
s_joystickId = event.joystickConnect.joystickId;
}
break;
case sf::Event::JoystickDisconnected:
if (s_joystickId == event.joystickConnect.joystickId) { // used gamepad was disconnected
s_joystickId = getConnectedJoystickId();
}
break;
default:
break;
}
}
switch (event.type) {
case sf::Event::LostFocus:
s_windowHasFocus = false;
break;
case sf::Event::GainedFocus:
s_windowHasFocus = true;
break;
default:
break;
}
}
void Update(sf::RenderWindow& window, sf::Time dt)
{
Update(window, window, dt);
}
void Update(sf::Window& window, sf::RenderTarget& target, sf::Time dt)
{
if (!s_mouseMoved) {
if (sf::Touch::isDown(0))
s_touchPos = sf::Touch::getPosition(0, window);
Update(s_touchPos, static_cast<sf::Vector2f>(target.getSize()), dt);
} else {
Update(sf::Mouse::getPosition(window), static_cast<sf::Vector2f>(target.getSize()), dt);
}
if (ImGui::GetIO().MouseDrawCursor) {
// Hide OS mouse cursor if imgui is drawing it
window.setMouseCursorVisible(false);
}
}
void Update(const sf::Vector2i& mousePos, const sf::Vector2f& displaySize, sf::Time dt)
{
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize = displaySize;
io.DeltaTime = dt.asSeconds();
if (s_windowHasFocus) {
if (io.WantSetMousePos) {
sf::Vector2i mousePos(static_cast<int>(io.MousePos.x), static_cast<int>(io.MousePos.y));
sf::Mouse::setPosition(mousePos);
} else {
io.MousePos = mousePos;
}
for (unsigned int i = 0; i < 3; i++) {
io.MouseDown[i] = s_touchDown[i] || sf::Touch::isDown(i) || s_mousePressed[i] || sf::Mouse::isButtonPressed((sf::Mouse::Button)i);
s_mousePressed[i] = false;
s_touchDown[i] = false;
}
}
#ifdef ANDROID
#ifdef USE_JNI
if (io.WantTextInput && !s_wantTextInput) {
openKeyboardIME();
s_wantTextInput = true;
}
if (!io.WantTextInput && s_wantTextInput) {
closeKeyboardIME();
s_wantTextInput = false;
}
#endif
#endif
assert(io.Fonts->Fonts.Size > 0); // You forgot to create and set up font atlas (see createFontTexture)
// gamepad navigation
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) &&
s_joystickId != NULL_JOYSTICK_ID) {
updateJoystickActionState(io, ImGuiNavInput_Activate);
updateJoystickActionState(io, ImGuiNavInput_Cancel);
updateJoystickActionState(io, ImGuiNavInput_Input);
updateJoystickActionState(io, ImGuiNavInput_Menu);
updateJoystickActionState(io, ImGuiNavInput_FocusPrev);
updateJoystickActionState(io, ImGuiNavInput_FocusNext);
updateJoystickActionState(io, ImGuiNavInput_TweakSlow);
updateJoystickActionState(io, ImGuiNavInput_TweakFast);
updateJoystickDPadState(io);
updateJoystickLStickState(io);
}
ImGui::NewFrame();
}
void Render(sf::RenderTarget& target)
{
target.resetGLStates();
ImGui::Render();
RenderDrawLists(ImGui::GetDrawData());
}
void Shutdown()
{
ImGui::GetIO().Fonts->TexID = NULL;
if (s_fontTexture) { // if internal texture was created, we delete it
delete s_fontTexture;
s_fontTexture = NULL;
}
ImGui::DestroyContext();
}
void UpdateFontTexture()
{
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
sf::Texture& texture = *s_fontTexture;
texture.create(width, height);
texture.update(pixels);
io.Fonts->TexID = (void*)texture.getNativeHandle();
}
sf::Texture& GetFontTexture()
{
return *s_fontTexture;
}
void SetActiveJoystickId(unsigned int joystickId)
{
assert(joystickId < sf::Joystick::Count);
s_joystickId = joystickId;
}
void SetJoytickDPadThreshold(float threshold)
{
assert(threshold >= 0.f && threshold <= 100.f);
s_dPadInfo.threshold = threshold;
}
void SetJoytickLStickThreshold(float threshold)
{
assert(threshold >= 0.f && threshold <= 100.f);
s_lStickInfo.threshold = threshold;
}
void SetJoystickMapping(int action, unsigned int joystickButton)
{
assert(action < ImGuiNavInput_COUNT);
assert(joystickButton < sf::Joystick::ButtonCount);
s_joystickMapping[action] = joystickButton;
}
void SetDPadXAxis(sf::Joystick::Axis dPadXAxis, bool inverted)
{
s_dPadInfo.xAxis = dPadXAxis;
s_dPadInfo.xInverted = inverted;
}
void SetDPadYAxis(sf::Joystick::Axis dPadYAxis, bool inverted)
{
s_dPadInfo.yAxis = dPadYAxis;
s_dPadInfo.yInverted = inverted;
}
void SetLStickXAxis(sf::Joystick::Axis lStickXAxis, bool inverted)
{
s_lStickInfo.xAxis = lStickXAxis;
s_lStickInfo.xInverted = inverted;
}
void SetLStickYAxis(sf::Joystick::Axis lStickYAxis, bool inverted)
{
s_lStickInfo.yAxis = lStickYAxis;
s_lStickInfo.yInverted = inverted;
}
} // end of namespace SFML
/////////////// Image Overloads
void Image(const sf::Texture& texture,
const sf::Color& tintColor, const sf::Color& borderColor)
{
Image(texture, static_cast<sf::Vector2f>(texture.getSize()), tintColor, borderColor);
}
void Image(const sf::Texture& texture, const sf::Vector2f& size,
const sf::Color& tintColor, const sf::Color& borderColor)
{
ImGui::Image((void*)texture.getNativeHandle(), size, ImVec2(0, 0), ImVec2(1, 1), tintColor, borderColor);
}
void Image(const sf::Texture& texture, const sf::FloatRect& textureRect,
const sf::Color& tintColor, const sf::Color& borderColor)
{
Image(texture, sf::Vector2f(std::abs(textureRect.width), std::abs(textureRect.height)), textureRect, tintColor, borderColor);
}
void Image(const sf::Texture& texture, const sf::Vector2f& size, const sf::FloatRect& textureRect,
const sf::Color& tintColor, const sf::Color& borderColor)
{
sf::Vector2f textureSize = static_cast<sf::Vector2f>(texture.getSize());
ImVec2 uv0(textureRect.left / textureSize.x, textureRect.top / textureSize.y);
ImVec2 uv1((textureRect.left + textureRect.width) / textureSize.x,
(textureRect.top + textureRect.height) / textureSize.y);
ImGui::Image((void*)texture.getNativeHandle(), size, uv0, uv1, tintColor, borderColor);
}
void Image(const sf::Sprite& sprite,
const sf::Color& tintColor, const sf::Color& borderColor)
{
sf::FloatRect bounds = sprite.getGlobalBounds();
Image(sprite, sf::Vector2f(bounds.width, bounds.height), tintColor, borderColor);
}
void Image(const sf::Sprite& sprite, const sf::Vector2f& size,
const sf::Color& tintColor, const sf::Color& borderColor)
{
const sf::Texture* texturePtr = sprite.getTexture();
// sprite without texture cannot be drawn
if (!texturePtr) { return; }
Image(*texturePtr, size, static_cast<sf::FloatRect>(sprite.getTextureRect()), tintColor, borderColor);
}
/////////////// Image Button Overloads
bool ImageButton(const sf::Texture& texture,
const int framePadding, const sf::Color& bgColor, const sf::Color& tintColor)
{
return ImageButton(texture, static_cast<sf::Vector2f>(texture.getSize()), framePadding, bgColor, tintColor);
}
bool ImageButton(const sf::Texture& texture, const sf::Vector2f& size,
const int framePadding, const sf::Color& bgColor, const sf::Color& tintColor)
{
sf::Vector2f textureSize = static_cast<sf::Vector2f>(texture.getSize());
return ::imageButtonImpl(texture, sf::FloatRect(0.f, 0.f, textureSize.x, textureSize.y), size, framePadding, bgColor, tintColor);
}
bool ImageButton(const sf::Sprite& sprite,
const int framePadding, const sf::Color& bgColor, const sf::Color& tintColor)
{
sf::FloatRect spriteSize = sprite.getGlobalBounds();
return ImageButton(sprite, sf::Vector2f(spriteSize.width, spriteSize.height), framePadding, bgColor, tintColor);
}
bool ImageButton(const sf::Sprite& sprite, const sf::Vector2f& size,
const int framePadding, const sf::Color& bgColor, const sf::Color& tintColor)
{
const sf::Texture* texturePtr = sprite.getTexture();
if (!texturePtr) { return false; }
return ::imageButtonImpl(*texturePtr, static_cast<sf::FloatRect>(sprite.getTextureRect()), size, framePadding, bgColor, tintColor);
}
/////////////// Draw_list Overloads
void DrawLine(const sf::Vector2f& a, const sf::Vector2f& b, const sf::Color& color,
float thickness)
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
sf::Vector2f pos = ImGui::GetCursorScreenPos();
draw_list->AddLine(a + pos, b + pos, ColorConvertFloat4ToU32(color), thickness);
}
void DrawRect(const sf::FloatRect& rect, const sf::Color& color,
float rounding, int rounding_corners, float thickness)
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddRect(
getTopLeftAbsolute(rect),
getDownRightAbsolute(rect),
ColorConvertFloat4ToU32(color), rounding, rounding_corners, thickness);
}
void DrawRectFilled(const sf::FloatRect& rect, const sf::Color& color,
float rounding, int rounding_corners)
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
draw_list->AddRectFilled(
getTopLeftAbsolute(rect),
getDownRightAbsolute(rect),
ColorConvertFloat4ToU32(color), rounding, rounding_corners);
}
} // end of namespace ImGui
namespace
{
ImVec2 getTopLeftAbsolute(const sf::FloatRect & rect)
{
ImVec2 pos = ImGui::GetCursorScreenPos();
return ImVec2(rect.left + pos.x, rect.top + pos.y);
}
ImVec2 getDownRightAbsolute(const sf::FloatRect & rect)
{
ImVec2 pos = ImGui::GetCursorScreenPos();
return ImVec2(rect.left + rect.width + pos.x, rect.top + rect.height + pos.y);
}
// Rendering callback
void RenderDrawLists(ImDrawData* draw_data)
{
ImGui::GetDrawData();
if (draw_data->CmdListsCount == 0) {
return;
}
ImGuiIO& io = ImGui::GetIO();
assert(io.Fonts->TexID != NULL); // You forgot to create and set font texture
// scale stuff (needed for proper handling of window resize)
int fb_width = static_cast<int>(io.DisplaySize.x * io.DisplayFramebufferScale.x);
int fb_height = static_cast<int>(io.DisplaySize.y * io.DisplayFramebufferScale.y);
if (fb_width == 0 || fb_height == 0) { return; }
draw_data->ScaleClipRects(io.DisplayFramebufferScale);
#ifdef GL_VERSION_ES_CL_1_1
GLint last_program, last_texture, last_array_buffer, last_element_array_buffer;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer);
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &last_element_array_buffer);
#else
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
#endif
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glEnable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glViewport(0, 0, (GLsizei)fb_width, (GLsizei)fb_height);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
#ifdef GL_VERSION_ES_CL_1_1
glOrthof(0.0f, io.DisplaySize.x, io.DisplaySize.y, 0.0f, -1.0f, +1.0f);
#else
glOrtho(0.0f, io.DisplaySize.x, io.DisplaySize.y, 0.0f, -1.0f, +1.0f);
#endif
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
for (int n = 0; n < draw_data->CmdListsCount; ++n) {
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const unsigned char* vtx_buffer = (const unsigned char*)&cmd_list->VtxBuffer.front();
const ImDrawIdx* idx_buffer = &cmd_list->IdxBuffer.front();
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + offsetof(ImDrawVert, pos)));
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), (void*)(vtx_buffer + offsetof(ImDrawVert, uv)));
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), (void*)(vtx_buffer + offsetof(ImDrawVert, col)));
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); ++cmd_i) {
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback) {
pcmd->UserCallback(cmd_list, pcmd);
} else {
GLuint tex_id = (GLuint)*((unsigned int*)&pcmd->TextureId);
glBindTexture(GL_TEXTURE_2D, tex_id);
glScissor((int)pcmd->ClipRect.x, (int)(fb_height - pcmd->ClipRect.w),
(int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, GL_UNSIGNED_SHORT, idx_buffer);
}
idx_buffer += pcmd->ElemCount;
}
}
#ifdef GL_VERSION_ES_CL_1_1
glBindTexture(GL_TEXTURE_2D, last_texture);
glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, last_element_array_buffer);
glDisable(GL_SCISSOR_TEST);
#else
glPopAttrib();
#endif
}
bool imageButtonImpl(const sf::Texture& texture, const sf::FloatRect& textureRect, const sf::Vector2f& size, const int framePadding,
const sf::Color& bgColor, const sf::Color& tintColor)
{
sf::Vector2f textureSize = static_cast<sf::Vector2f>(texture.getSize());
ImVec2 uv0(textureRect.left / textureSize.x, textureRect.top / textureSize.y);
ImVec2 uv1((textureRect.left + textureRect.width) / textureSize.x,
(textureRect.top + textureRect.height) / textureSize.y);
return ImGui::ImageButton((void*)texture.getNativeHandle(), size, uv0, uv1, framePadding, bgColor, tintColor);
}
unsigned int getConnectedJoystickId()
{
for (unsigned int i = 0; i < (unsigned int)sf::Joystick::Count; ++i) {
if (sf::Joystick::isConnected(i)) return i;
}
return NULL_JOYSTICK_ID;
}
void initDefaultJoystickMapping()
{
ImGui::SFML::SetJoystickMapping(ImGuiNavInput_Activate, 0);
ImGui::SFML::SetJoystickMapping(ImGuiNavInput_Cancel, 1);
ImGui::SFML::SetJoystickMapping(ImGuiNavInput_Input, 3);
ImGui::SFML::SetJoystickMapping(ImGuiNavInput_Menu, 2);
ImGui::SFML::SetJoystickMapping(ImGuiNavInput_FocusPrev, 4);
ImGui::SFML::SetJoystickMapping(ImGuiNavInput_FocusNext, 5);
ImGui::SFML::SetJoystickMapping(ImGuiNavInput_TweakSlow, 4);
ImGui::SFML::SetJoystickMapping(ImGuiNavInput_TweakFast, 5);
ImGui::SFML::SetDPadXAxis(sf::Joystick::PovX);
// D-pad Y axis is inverted on Windows
#ifdef _WIN32
ImGui::SFML::SetDPadYAxis(sf::Joystick::PovY, true);
#else
ImGui::SFML::SetDPadYAxis(sf::Joystick::PovY);
#endif
ImGui::SFML::SetLStickXAxis(sf::Joystick::X);
ImGui::SFML::SetLStickYAxis(sf::Joystick::Y);
ImGui::SFML::SetJoytickDPadThreshold(5.f);
ImGui::SFML::SetJoytickLStickThreshold(5.f);
}
void updateJoystickActionState(ImGuiIO& io, ImGuiNavInput_ action)
{
bool isPressed = sf::Joystick::isButtonPressed(s_joystickId, s_joystickMapping[action]);
io.NavInputs[action] = isPressed ? 1.0f : 0.0f;
}
void updateJoystickDPadState(ImGuiIO& io)
{
float dpadXPos = sf::Joystick::getAxisPosition(s_joystickId, s_dPadInfo.xAxis);
if (s_dPadInfo.xInverted) dpadXPos = -dpadXPos;
float dpadYPos = sf::Joystick::getAxisPosition(s_joystickId, s_dPadInfo.yAxis);
if (s_dPadInfo.yInverted) dpadYPos = -dpadYPos;
io.NavInputs[ImGuiNavInput_DpadLeft] = dpadXPos < -s_dPadInfo.threshold ? 1.0f : 0.0f;
io.NavInputs[ImGuiNavInput_DpadRight] = dpadXPos > s_dPadInfo.threshold ? 1.0f : 0.0f;
io.NavInputs[ImGuiNavInput_DpadUp] = dpadYPos < -s_dPadInfo.threshold ? 1.0f : 0.0f;
io.NavInputs[ImGuiNavInput_DpadDown] = dpadYPos > s_dPadInfo.threshold ? 1.0f : 0.0f;
}
void updateJoystickLStickState(ImGuiIO& io)
{
float lStickXPos = sf::Joystick::getAxisPosition(s_joystickId, s_lStickInfo.xAxis);
if (s_lStickInfo.xInverted) lStickXPos = -lStickXPos;
float lStickYPos = sf::Joystick::getAxisPosition(s_joystickId, s_lStickInfo.yAxis);
if (s_lStickInfo.yInverted) lStickYPos = -lStickYPos;
if (lStickXPos < -s_lStickInfo.threshold) {
io.NavInputs[ImGuiNavInput_LStickLeft] = std::abs(lStickXPos / 100.f);
}
if (lStickXPos > s_lStickInfo.threshold) {
io.NavInputs[ImGuiNavInput_LStickRight] = lStickXPos / 100.f;
}
if (lStickYPos < -s_lStickInfo.threshold) {
io.NavInputs[ImGuiNavInput_LStickUp] = std::abs(lStickYPos / 100.f);
}
if (lStickYPos > s_lStickInfo.threshold) {
io.NavInputs[ImGuiNavInput_LStickDown] = lStickYPos / 100.f;
}
}
} // end of anonymous namespace