diff --git a/CMakeLists.txt b/CMakeLists.txt index d30412afe..b55cc041b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,7 +304,6 @@ set(COMMON_LIBRARIES ${FREETYPE_LIBRARIES} ${FreeImage_LIBRARIES} ${SDL2_LIBRARY} - ${UDEV_LIBRARY} # batocera / background musics ${SDLMIXER_LIBRARY} # batocera / customisations @@ -316,6 +315,12 @@ set(COMMON_LIBRARIES libcheevos ) +if(UDEV_FOUND) + LIST(APPEND COMMON_LIBRARIES + ${UDEV_LIBRARY} + ) +endif() + if(ENABLE_PULSE) LIST(APPEND COMMON_LIBRARIES ${PULSEAUDIO_LIBRARY} diff --git a/es-app/src/main.cpp b/es-app/src/main.cpp index 206251f2a..2e3eb0568 100644 --- a/es-app/src/main.cpp +++ b/es-app/src/main.cpp @@ -668,7 +668,7 @@ int main(int argc, char* argv[]) while(SDL_PollEvent(&event)); // check guns - InputManager::getInstance()->parseGuns(&window); + InputManager::getInstance()->updateGuns(&window); // triggered if exiting from SDL_WaitEvent due to event if (ps_standby) @@ -685,17 +685,11 @@ int main(int argc, char* argv[]) // ps_time = SDL_GetTicks(); // check guns - InputManager::getInstance()->parseGuns(&window); + InputManager::getInstance()->updateGuns(&window); } - // just to test - float perx, pery; - for (auto iter = InputManager::getInstance()->getGuns().begin(); iter != InputManager::getInstance()->getGuns().end(); iter++) { - InputManager::getInstance()->getGunPosition(iter->second, perx, pery); - printf("gun %i : %.2f %.2f\n", iter->first, perx, pery); - } - if(window.isSleeping()) + if (window.isSleeping()) { lastTime = SDL_GetTicks(); SDL_Delay(1); // this doesn't need to be accurate, we're just giving up our CPU time until something wakes us up diff --git a/es-core/CMakeLists.txt b/es-core/CMakeLists.txt index d4bde71c5..941af27a2 100644 --- a/es-core/CMakeLists.txt +++ b/es-core/CMakeLists.txt @@ -10,6 +10,7 @@ set(CORE_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.h ${CMAKE_CURRENT_SOURCE_DIR}/src/InputConfig.h ${CMAKE_CURRENT_SOURCE_DIR}/src/InputManager.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/GunManager.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Log.h ${CMAKE_CURRENT_SOURCE_DIR}/src/MameNames.h ${CMAKE_CURRENT_SOURCE_DIR}/src/gettext.h # batocera @@ -126,6 +127,7 @@ set(CORE_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/ImageIO.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/InputConfig.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/InputManager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/GunManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Log.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/MameNames.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/LocaleES.cpp # batocera diff --git a/es-core/src/GunManager.cpp b/es-core/src/GunManager.cpp new file mode 100644 index 000000000..2ab9ae59b --- /dev/null +++ b/es-core/src/GunManager.cpp @@ -0,0 +1,244 @@ +#include "GunManager.h" +#include "Log.h" +#include "platform.h" +#include "Window.h" +#include +#include +#include +#include +#include "utils/StringUtil.h" +#include "LocaleES.h" + +#ifdef HAVE_UDEV +#include +#include +#include +#include +#include +#define test_bit(array, bit) (array[bit/8] & (1<<(bit%8))) +#endif + +#if WIN32 +#include +#endif + +GunManager::GunManager() +{ +#ifdef HAVE_UDEV + udev = udev_new(); + if (udev != NULL) + { + udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (udev_monitor) + { + udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input", NULL); + udev_monitor_enable_receiving(udev_monitor); + } + } + udev_initial_gunsList(); +#endif +} + +GunManager::~GunManager() +{ +#ifdef HAVE_UDEV + if (udev != NULL) + { + // close guns + for (auto gun : mGuns) + { + udev_removeGun(gun->dev, NULL); + delete gun; + } + + mGuns.clear(); + + if (udev_monitor) + udev_monitor_unref(udev_monitor); + + udev_unref(udev); + } +#endif +} + +void GunManager::updateGuns(Window* window) +{ +#ifdef HAVE_UDEV + const char* val_gun; + const char* action; + + while (udev_monitor && udev_input_poll_hotplug_available(udev_monitor)) + { + struct udev_device *dev = udev_monitor_receive_device(udev_monitor); + bool dev_handled = false; + + if (dev != NULL) + { + val_gun = udev_device_get_property_value(dev, "ID_INPUT_GUN"); // ID_INPUT_GUN and ID_INPUT_MOUSE for some tests + action = udev_device_get_action(dev); + + if (val_gun != NULL && strncmp(val_gun, "1", 1) == 0) + { + if (strncmp(action, "add", 3) == 0) + { + if (udev_addGun(dev, window)) + dev_handled = true; + } + else if (strncmp(action, "remove", 6) == 0) + { + if (udev_removeGun(dev, window)) + dev_handled = true; + } + } + + if (!dev_handled) + udev_device_unref(dev); // not handled, clean it + } + } +#elif WIN32 + if (mGuns.size() == 0) + { + Gun* newgun = new Gun(); + newgun->mIndex = mGuns.size(); + newgun->mName = "Mouse"; + mGuns.push_back(newgun); + } +#endif + + for (Gun* gun : mGuns) + updateGunPosition(gun); +} + +bool GunManager::updateGunPosition(Gun* gun) +{ +#ifdef HAVE_UDEV + struct input_absinfo absinfo; + + if (ioctl(gun->fd, EVIOCGABS(ABS_X), &absinfo) == -1) + return false; + + gun->mX = ((float)(absinfo.value - absinfo.minimum)) / ((float)(absinfo.maximum - absinfo.minimum)); + + if (ioctl(gun->fd, EVIOCGABS(ABS_Y), &absinfo) == -1) + return false; + + gun->mY = ((float)(absinfo.value - absinfo.minimum)) / ((float)(absinfo.maximum - absinfo.minimum)); + + return true; +#elif WIN32 + int x, y; + SDL_GetMouseState(&x, &y); + gun->mX = x; + gun->mY = y; + return true; +#endif + + return false; +} + + +#ifdef HAVE_UDEV +// function from retroarch +bool GunManager::udev_input_poll_hotplug_available(struct udev_monitor *dev) +{ + struct pollfd fds; + + fds.fd = udev_monitor_get_fd(dev); + fds.events = POLLIN; + fds.revents = 0; + + return (poll(&fds, 1, 0) == 1) && (fds.revents & POLLIN); +} + +void GunManager::udev_initial_gunsList() +{ + struct udev_list_entry *devs = NULL; + struct udev_list_entry *item = NULL; + + struct udev_enumerate *enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_property(enumerate, "ID_INPUT_GUN", "1"); + udev_enumerate_add_match_subsystem(enumerate, "input"); + udev_enumerate_scan_devices(enumerate); + devs = udev_enumerate_get_list_entry(enumerate); + + for (item = devs; item; item = udev_list_entry_get_next(item)) + { + const char *name = udev_list_entry_get_name(item); + struct udev_device *dev = udev_device_new_from_syspath(udev, name); + + if (udev_addGun(dev, NULL) == false) udev_device_unref(dev); // unhandled device + } +} + +bool GunManager::udev_addGun(struct udev_device *dev, Window* window) +{ + char ident[256]; + const char* devnode; + unsigned char abscaps[(ABS_MAX / 8) + 1] = { '\0' }; + + // check that devnode is of form /dev/input/eventXX (to not include devices aliases) + devnode = udev_device_get_devnode(dev); + if (devnode == NULL) return false; + if (strncmp(devnode, "/dev/input/event", 16) != 0) return false; + + int fd = open(devnode, O_RDONLY | O_NONBLOCK); + if (fd < 0) return false; + + // check absolute capabilities + if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abscaps)), abscaps) == -1) { + close(fd); + return false; + } + + // check absolute capabilities x and y + if (((test_bit(abscaps, ABS_X)) && (test_bit(abscaps, ABS_Y))) == false) { + close(fd); + return false; + } + + LOG(LogInfo) << "Gun found at " << devnode; + + if (ioctl(fd, EVIOCGNAME(sizeof(ident)), ident) < 0) + ident[0] = '\0'; + + Gun* newgun = new Gun(); + newgun->mIndex = mGuns.size(); + newgun->mName = std::string(ident); + newgun->devpath = devnode; + newgun->dev = dev; + newgun->fd = fd; + + if (!newgun->mName.empty() && window != NULL) + window->displayNotificationMessage(_U("\uF05B ") + Utils::String::format(_("%s connected").c_str(), Utils::String::trim(newgun->mName).c_str())); + + mGuns.push_back(newgun); + + return false; +} + +bool GunManager::udev_removeGun(struct udev_device *dev, Window* window) +{ + const char* devnode; + LOG(LogInfo) << "Gun removed at " << devnode; + + devnode = udev_device_get_devnode(dev); + if (devnode == NULL) return false; + + for (auto iter = mGuns.begin(); iter != mGuns.end(); iter++) + { + if (iter->devpath == devnode) + { + LOG(LogInfo) << "Gun removed found at " << devnode; + if (window != NULL) + window->displayNotificationMessage(_U("\uF05B ") + Utils::String::format(_("%s disconnected").c_str(), Utils::String::trim(iter->mName).c_str())); + + close(iter->fd); + udev_device_unref(iter->dev); + delete *iter; + mGuns.erase(iter); + return true; + } + } + return false; +} +#endif diff --git a/es-core/src/GunManager.h b/es-core/src/GunManager.h new file mode 100644 index 000000000..4881708e3 --- /dev/null +++ b/es-core/src/GunManager.h @@ -0,0 +1,75 @@ +#pragma once +#ifndef ES_CORE_GUNMANAGER_H +#define ES_CORE_GUNMANAGER_H + +#include +#include + +#ifdef HAVE_UDEV +#include +#endif + +class InputConfig; +class Window; +union SDL_Event; + +class Gun +{ + friend class GunManager; + +public: + Gun() + { + mIndex = 0; + mX = -1; + mY = -1; + } + + int index() { return mIndex; } + std::string& name() { return mName; } + + float x() { return mX; } + float y() { return mY; } + +private: + std::string mName; + + float mX; + float mY; + + int mIndex; + +#ifdef HAVE_UDEV + std::string devpath; + udev_device* dev; + int fd; +#endif +}; + +//you should only ever instantiate one of these, by the way +class GunManager +{ +public: + GunManager(); + virtual ~GunManager(); + + std::vector& getGuns() { return mGuns; } + void updateGuns(Window* window); + +private: + bool updateGunPosition(Gun* gun); + + std::vector mGuns; + +#ifdef HAVE_UDEV + struct udev *udev; + struct udev_monitor *udev_monitor; + + static bool udev_input_poll_hotplug_available(struct udev_monitor *dev); + void udev_initial_gunsList(); + bool udev_addGun(struct udev_device *dev, Window* window); + bool udev_removeGun(struct udev_device *dev, Window* window); +#endif +}; + +#endif // ES_CORE_GUNMANAGER_H diff --git a/es-core/src/InputManager.cpp b/es-core/src/InputManager.cpp index fc038e351..8ea45713f 100644 --- a/es-core/src/InputManager.cpp +++ b/es-core/src/InputManager.cpp @@ -16,15 +16,7 @@ #include "utils/StringUtil.h" #include "LocaleES.h" #include "Paths.h" - -#ifdef HAVE_UDEV -#include -#include -#include -#include -#include -#define test_bit(array, bit) (array[bit/8] & (1<<(bit%8))) -#endif +#include "GunManager.h" #define KEYBOARD_GUID_STRING "-1" #define CEC_GUID_STRING "-2" @@ -60,7 +52,7 @@ InputManager::~InputManager() InputManager* InputManager::getInstance() { - if(!mInstance) + if (!mInstance) mInstance = new InputManager(); return mInstance; @@ -87,17 +79,7 @@ void InputManager::init() mMouseButtonsInputConfig->mapInput(BUTTON_OK, Input(DEVICE_MOUSE, TYPE_BUTTON, 1, 1, true)); mMouseButtonsInputConfig->mapInput(BUTTON_BACK, Input(DEVICE_MOUSE, TYPE_BUTTON, 3, 1, true)); -#ifdef HAVE_UDEV - udev = udev_new(); - if(udev != NULL) { - udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); - if (udev_monitor){ - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "input", NULL); - udev_monitor_enable_receiving(udev_monitor); - } - } - udev_initial_gunsList(); -#endif + mGunManager = new GunManager(); } void InputManager::deinit() @@ -130,20 +112,11 @@ void InputManager::deinit() SDL_JoystickEventState(SDL_DISABLE); SDL_QuitSubSystem(SDL_INIT_JOYSTICK); -#ifdef HAVE_UDEV - if(udev != NULL) { - // close guns - for (auto iter = mGuns.begin(); iter != mGuns.end(); iter++) { - udev_removeGun(iter->second->dev, NULL); - delete iter->second; - } - mGuns.clear(); - if (udev_monitor) { - udev_monitor_unref(udev_monitor); - } - udev_unref(udev); + if (mGunManager != nullptr) + { + delete mGunManager; + mGunManager = nullptr; } -#endif } int InputManager::getNumJoysticks() @@ -256,152 +229,6 @@ void InputManager::rebuildAllJoysticks(bool deinit) SDL_JoystickEventState(SDL_ENABLE); } -#ifdef HAVE_UDEV -// function from retroarch -bool InputManager::udev_input_poll_hotplug_available(struct udev_monitor *dev) -{ - struct pollfd fds; - - fds.fd = udev_monitor_get_fd(dev); - fds.events = POLLIN; - fds.revents = 0; - - return (poll(&fds, 1, 0) == 1) && (fds.revents & POLLIN); -} - -void InputManager::udev_initial_gunsList() { - struct udev_list_entry *devs = NULL; - struct udev_list_entry *item = NULL; - - struct udev_enumerate *enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_property(enumerate, "ID_INPUT_GUN", "1"); - udev_enumerate_add_match_subsystem(enumerate, "input"); - udev_enumerate_scan_devices(enumerate); - devs = udev_enumerate_get_list_entry(enumerate); - - for (item = devs; item; item = udev_list_entry_get_next(item)) { - const char *name = udev_list_entry_get_name(item); - struct udev_device *dev = udev_device_new_from_syspath(udev, name); - - if(udev_addGun(dev, NULL) == false) udev_device_unref(dev); // unhandled device - } -} - -bool InputManager::udev_addGun(struct udev_device *dev, Window* window) { - char ident[256]; - const char* devnode; - unsigned char abscaps[(ABS_MAX / 8) + 1] = {'\0'}; - - // check that devnode is of form /dev/input/eventXX (to not include devices aliases) - devnode = udev_device_get_devnode(dev); - if(devnode == NULL) return false; - if(strncmp(devnode, "/dev/input/event", 16) != 0) return false; - - int fd = open(devnode, O_RDONLY | O_NONBLOCK); - if(fd < 0) return false; - - // check absolute capabilities - if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abscaps)), abscaps) == -1) { - close(fd); - return false; - } - - // check absolute capabilities x and y - if( ( (test_bit(abscaps, ABS_X)) && (test_bit(abscaps, ABS_Y)) ) == false) { - close(fd); - return false; - } - - LOG(LogInfo) << "Gun found at " << devnode; - - if (ioctl(fd, EVIOCGNAME(sizeof(ident)), ident) < 0) - ident[0] = '\0'; - - Gun* newgun = new Gun(); - newgun->name = std::string(ident); - newgun->devpath = devnode; - newgun->dev = dev; - newgun->fd = fd; - - if (!newgun->name.empty() && window != NULL) - window->displayNotificationMessage(_U("\uF05B ") + Utils::String::format(_("%s connected").c_str(), Utils::String::trim(newgun->name).c_str())); - - mGuns[mGuns.size()] = newgun; - - return false; -} - -bool InputManager::udev_removeGun(struct udev_device *dev, Window* window) { - const char* devnode; - LOG(LogInfo) << "Gun removed at " << devnode; - - devnode = udev_device_get_devnode(dev); - if(devnode == NULL) return false; - - for (auto iter = mGuns.begin(); iter != mGuns.end(); iter++) { - if(iter->second->devpath == devnode) { - LOG(LogInfo) << "Gun removed found at " << devnode; - if(window != NULL) - window->displayNotificationMessage(_U("\uF05B ") + Utils::String::format(_("%s disconnected").c_str(), Utils::String::trim(iter->second->name).c_str())); - - close(iter->second->fd); - udev_device_unref(iter->second->dev); - delete iter->second; - mGuns.erase(iter); - return true; - } - } - return false; -} -#endif - -void InputManager::parseGuns(Window* window) { -#ifdef HAVE_UDEV - const char* val_gun; - const char* action; - - while (udev_monitor && udev_input_poll_hotplug_available(udev_monitor)) { - struct udev_device *dev = udev_monitor_receive_device(udev_monitor); - bool dev_handled = false; - - if(dev != NULL) { - val_gun = udev_device_get_property_value(dev, "ID_INPUT_GUN"); // ID_INPUT_GUN and ID_INPUT_MOUSE for some tests - action = udev_device_get_action(dev); - - if(val_gun != NULL && strncmp(val_gun, "1", 1) == 0) { - if(strncmp(action, "add", 3) == 0) { - if(udev_addGun(dev, window)) dev_handled = true; - - } else if(strncmp(action, "remove", 6) == 0) { - if(udev_removeGun(dev, window)) dev_handled = true; - } - } - - if(dev_handled == false) udev_device_unref(dev); // not handled, clean it - } - } -#endif -} - -bool InputManager::getGunPosition(Gun* gun, float& perx, float& pery) { -#ifdef HAVE_UDEV - struct input_absinfo absinfo; - - if (ioctl(gun->fd, EVIOCGABS(ABS_X), &absinfo) == -1) { - return false; - } - perx = ((float)(absinfo.value - absinfo.minimum)) / ((float)(absinfo.maximum - absinfo.minimum)); - - if (ioctl(gun->fd, EVIOCGABS(ABS_Y), &absinfo) == -1) { - return false; - } - pery = ((float)(absinfo.value - absinfo.minimum)) / ((float)(absinfo.maximum - absinfo.minimum)); - - return true; -#endif - return false; -} - bool InputManager::parseEvent(const SDL_Event& ev, Window* window) { bool causedEvent = false; @@ -965,3 +792,9 @@ std::vector InputManager::getInputConfigs() return ret; } + +void InputManager::updateGuns(Window* window) +{ + if (mGunManager) + mGunManager->updateGuns(window); +} diff --git a/es-core/src/InputManager.h b/es-core/src/InputManager.h index 13bbac065..baea49d17 100644 --- a/es-core/src/InputManager.h +++ b/es-core/src/InputManager.h @@ -7,12 +7,12 @@ #include #include -#ifdef HAVE_UDEV -#include -#endif +#include "GunManager.h" class InputConfig; class Window; +class GunManager; + union SDL_Event; struct PlayerDeviceInfo @@ -27,15 +27,6 @@ public: virtual void onJoystickChanged() = 0; }; -struct Gun { - std::string name; -#ifdef HAVE_UDEV - std::string devpath; - udev_device* dev; - int fd; -#endif -}; - //you should only ever instantiate one of these, by the way class InputManager { @@ -58,9 +49,8 @@ public: bool parseEvent(const SDL_Event& ev, Window* window); - void parseGuns(Window* window); - bool getGunPosition(Gun* gun, float& perx, float& pery); - std::map& getGuns() { return mGuns; } + void updateGuns(Window* window); + std::vector& getGuns() { return mGunManager->getGuns(); } std::string configureEmulators(); @@ -72,9 +62,13 @@ public: static Delegate joystickChanged; + GunManager* getGunManager() { return mGunManager; } + private: InputManager(); + GunManager* mGunManager; + static InputManager* mInstance; static const int DEADZONE = 23000; static std::string getTemporaryConfigPath(); @@ -85,8 +79,6 @@ private: std::map mJoysticks; std::map mInputConfigs; - std::map mGuns; - InputConfig* mMouseButtonsInputConfig; InputConfig* mKeyboardInputConfig; InputConfig* mCECInputConfig; @@ -104,16 +96,6 @@ private: void clearJoysticks(); void rebuildAllJoysticks(bool deinit = true); - -#ifdef HAVE_UDEV - struct udev *udev; - struct udev_monitor *udev_monitor; - - static bool udev_input_poll_hotplug_available(struct udev_monitor *dev); - void udev_initial_gunsList(); - bool udev_addGun(struct udev_device *dev, Window* window); - bool udev_removeGun(struct udev_device *dev, Window* window); -#endif }; #endif // ES_CORE_INPUT_MANAGER_H diff --git a/es-core/src/Window.cpp b/es-core/src/Window.cpp index 4593f5d71..69fabd382 100644 --- a/es-core/src/Window.cpp +++ b/es-core/src/Window.cpp @@ -502,13 +502,13 @@ void Window::render() mRenderedHelpPrompts = false; // draw only bottom and top of GuiStack (if they are different) - if(mGuiStack.size()) + if (mGuiStack.size()) { auto& bottom = mGuiStack.front(); auto& top = mGuiStack.back(); bottom->render(transform); - if(bottom != top) + if (bottom != top) { if ((top->getTag() == "GuiLoading") && mGuiStack.size() > 2) { @@ -534,21 +534,21 @@ void Window::render() } } } - + if (mGuiStack.size() < 2 || !Renderer::isSmallScreen()) - if(!mRenderedHelpPrompts) + if (!mRenderedHelpPrompts) mHelp->render(transform); - if(Settings::DrawFramerate() && mFrameDataText) + if (Settings::DrawFramerate() && mFrameDataText) { Renderer::setMatrix(Transform4x4f::Identity()); mDefaultFonts.at(1)->renderTextCache(mFrameDataText.get()); } - // clock + // clock if (Settings::DrawClock() && mClock && (mGuiStack.size() < 2 || !Renderer::isSmallScreen())) mClock->render(transform); - + if (Settings::ShowControllerActivity() && mControllerActivity != nullptr && (mGuiStack.size() < 2 || !Renderer::isSmallScreen())) mControllerActivity->render(transform); @@ -569,7 +569,7 @@ void Window::render() renderAsyncNotifications(transform); } - + // Always call the screensaver render function regardless of whether the screensaver is active // or not because it may perform a fade on transition renderScreenSaver(); @@ -580,7 +580,7 @@ void Window::render() if (mVolumeInfo && Settings::VolumePopup()) mVolumeInfo->render(transform); - if(mTimeSinceLastInput >= screensaverTime && screensaverTime != 0) + if (mTimeSinceLastInput >= screensaverTime && screensaverTime != 0) { if (!isProcessing() && mAllowSleep && (!mScreenSaver || mScreenSaver->allowSleep())) { @@ -591,6 +591,33 @@ void Window::render() } } } + + // just to test + for (auto gun : InputManager::getInstance()->getGuns()) + { + if (mGunAimTexture == nullptr) + mGunAimTexture = TextureResource::get(":/gun.png", false, false, true, false); + + if (mGunAimTexture->bind()) + { + int pointerSize = 24; + + const Vector2f topLeft = { gun->x() - pointerSize, gun->y() - pointerSize }; + const Vector2f bottomRight = { gun->x() + pointerSize, gun->y() + pointerSize }; + + Renderer::Vertex vertices[4]; + vertices[0] = { { topLeft.x() , topLeft.y() }, { 0.0f, 0.0f }, 0xFFFFFFFF }; + vertices[1] = { { topLeft.x() , bottomRight.y() }, { 0.0f, 1.0f }, 0xFFFFFFFF }; + vertices[2] = { { bottomRight.x(), topLeft.y() }, { 1.0f, 0.0f }, 0xFFFFFFFF }; + vertices[3] = { { bottomRight.x(), bottomRight.y() }, { 1.0f, 1.0f }, 0xFFFFFFFF }; + + Renderer::drawTriangleStrips(&vertices[0], 4); + + + } + } +// auto output = Utils::String::format("gun %i : %.2f %.2f\n", gun->index(), gun->x(), gun->y()); + } void Window::normalizeNextUpdate() diff --git a/es-core/src/Window.h b/es-core/src/Window.h index 29adf8c0a..fee532c07 100644 --- a/es-core/src/Window.h +++ b/es-core/src/Window.h @@ -159,6 +159,8 @@ private: bool mRenderedHelpPrompts; int mTransitionOffset; + + std::shared_ptr mGunAimTexture; }; #endif // ES_CORE_WINDOW_H diff --git a/resources/gun.png b/resources/gun.png new file mode 100644 index 000000000..86e5eea0e Binary files /dev/null and b/resources/gun.png differ