examples/example.windowing/example.windowing.native.app/example.windowing.cpp

File members: examples/example.windowing/example.windowing.native.app/example.windowing.cpp

// Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
//
// NVIDIA CORPORATION and its licensors retain all intellectual property
// and proprietary rights in and to this software, related documentation
// and any modifications thereto. Any use, reproduction, disclosure or
// distribution of this software and related documentation without an express
// license agreement from NVIDIA CORPORATION is strictly prohibited.
//
#ifndef DOXYGEN_BUILD // Just need the full listing
#    include <omni/core/ModuleInfo.h>
#    include <omni/core/OmniInit.h>

#    include <windowing/IWindowSystem.h>

#    include <cmath>

// example-begin omni-app-globals
OMNI_APP_GLOBALS("example.windowing.native.app", "Native (C++) example app using example.windowing.");
// example-end omni-app-globals

namespace omni
{
using namespace omni::core;
} // namespace omni

// Demonstrates how to create a custom cursor, in this case a beautiful red circle.
class CustomCursor : public omni::Implements<windowing::ICursor>
{
private:
    struct Pixel
    {
        uint8_t r, g, b, a;
    };

public:
    // abi /////////////////////////////////////////////////////////////////////////////////////////////////////////////

    virtual omni::UInt2 getSize_abi() noexcept
    {
        return m_size;
    }

    virtual omni::Int2 getHotSpot_abi() noexcept
    {
        return m_hotSpot;
    }

    virtual const uint8_t* getPixels_abi() noexcept
    {
        return &(m_pixels.data()->r);
    }

    // implementation details //////////////////////////////////////////////////////////////////////////////////////////

    CustomCursor()
    {
        m_pixels.resize(m_size.w * m_size.h);
        memset(m_pixels.data(), 0, m_pixels.size() * sizeof(Pixel));

        Pixel* p = m_pixels.data();
        for (int r = 0; r < int(m_size.h); ++r)
        {
            for (int c = 0; c < int(m_size.w); ++c)
            {
                int x = c - m_hotSpot.x;
                int y = r - m_hotSpot.y;
                float d = std::sqrt(float((x * x) + (y * y)));
                float k = std::abs(d - m_diameter) - m_halfThickness;

                if (k < 1.0)
                {
                    if (k < 0.0)
                    {
                        k = 0.0;
                    }

                    p->r = 255;
                    p->g = 0;
                    p->b = 0;
                    p->a = uint8_t((1.0 - k) * 255);
                }

                ++p;
            }
        }
    }

private:
    static constexpr float m_diameter = 25.0f;
    static constexpr float m_halfThickness = 1.5f;
    static constexpr omni::UInt2 m_size{ 64, 64 };
    static constexpr omni::Int2 m_hotSpot{ 32, 32 };
    std::vector<Pixel> m_pixels;
};

const char* mods2str(uint32_t mods)
{
    static char str[8];
    str[0] = (mods & input::fKeyboardModifierFlagShift) ? 's' : '-';
    str[1] = (mods & input::fKeyboardModifierFlagControl) ? 'c' : '-';
    str[2] = (mods & input::fKeyboardModifierFlagAlt) ? 'a' : '-';
    str[3] = (mods & input::fKeyboardModifierFlagSuper) ? 'w' : '-';
    str[4] = (mods & input::fKeyboardModifierFlagCapsLock) ? 'l' : '-';
    str[5] = (mods & input::fKeyboardModifierFlagNumLock) ? 'n' : '-';
    str[6] = '\0';
    return str;
}

int main(int argc, char** argv)
{
    OMNI_CORE_INIT(argc, argv);

    auto windowSystem = omni::createType<windowing::IWindowSystem>();
    if (!windowSystem)
    {
        OMNI_LOG_FATAL("unable to access window system");
        return 1;
    }

    printf("IWindowSystem provided by: '%s'\n", omni::getModuleFilename(windowSystem.get()).c_str());

    auto window = windowSystem->createWindow({ 640, 480 }, "example.windowing", windowing::fWindowHintScaleToMonitor);
    if (!window)
    {
        OMNI_LOG_FATAL("unable to create window");
        return 1;
    }

    printf("         ESC: Quit\n");
    printf("         F11: Toggle fullscreen\n");
    printf("      CTRL-m: Toggle minimized\n");
    printf("    SHIFT-Up: Grow window\n");
    printf("  SHIFT-Down: Shrink window\n");
    printf("      CTRL-c: Copy text to internal clipboard\n");
    printf("      CTRL-v: Print text from internal clipboard\n");
    printf("          Up: Change cursor\n");
    printf("           1: Enable custom cursor\n");

    omni::UInt2 size{ 0, 0 };
    window->addOnResizeConsumer([&size](windowing::IWindow* window, omni::UInt2 sz) {
        size = sz;
        fprintf(stderr, "window resize: %u %u\n", size.w, size.h);
    });

    windowing::CursorType cursors[] = { windowing::CursorType::eArrow,
                                        windowing::CursorType::eIBeam,
                                        windowing::CursorType::eCrosshair,
                                        windowing::CursorType::eHand,
                                        windowing::CursorType::eHorizontalResize,
                                        windowing::CursorType::eVerticalResize };
    size_t cursorIndex = 0;

    auto customCursor = omni::steal<windowing::ICursor>(new CustomCursor);

    window->addOnKeyboardEventConsumer([&window, &customCursor, &cursors, &cursorIndex](
                                           input::IKeyboard* /*keyboard*/, const input::KeyboardEvent* event) {
        if (input::isKeyRelease(*event, input::KeyboardKey::eEscape))
        {
            window->setShouldClose(true);
        }
        else if (input::isKeyRelease(*event, input::KeyboardKey::eF11))
        {
            window->setFullscreen(!window->isFullscreen());
        }
        else if (input::isOnlyControlDown(*event) && input::isKeyRelease(*event, input::KeyboardKey::eM))
        {
            window->setMinimized(!window->isMinimized());
        }
        else if (input::isOnlyShiftDown(*event) && input::isKeyPress(*event, input::KeyboardKey::eUp))
        {
            auto sz = window->getSize();
            if (sz.x > 100)
            {
                sz.x += 10;
            }
            if (sz.y > 100)
            {
                sz.y += 10;
            }
            window->setSize(sz);
        }
        else if (input::isOnlyShiftDown(*event) && input::isKeyPress(*event, input::KeyboardKey::eDown))
        {
            auto sz = window->getSize();
            if (sz.x > 100)
            {
                sz.x -= 10;
            }
            if (sz.y > 100)
            {
                sz.y -= 10;
            }
            window->setSize(sz);
        }
        else if (input::isOnlyControlDown(*event) && input::isKeyRelease(*event, input::KeyboardKey::eC))
        {
            window->setClipboardText("hi from example.windowing");
        }
        else if (input::isOnlyControlDown(*event) && input::isKeyRelease(*event, input::KeyboardKey::eV))
        {
            const char* text = window->getClipboardText();
            fprintf(stderr, "pasted: %s\n", (text ? text : "<empty>"));
        }
        else if (input::isKeyRelease(*event, input::KeyboardKey::eUp))
        {
            cursorIndex = (cursorIndex + 1) % CARB_COUNTOF(cursors);
            window->setCursor(cursors[cursorIndex]);
        }
        else if (input::isKeyRelease(*event, input::KeyboardKey::eKey1))
        {
            fprintf(stderr, "setting custom cursor\n");
            window->setCursor(customCursor.get());
        }
    });

    window->addOnMaximizeConsumer([](windowing::IWindow* /*window*/, bool maximized) {
        fprintf(stderr, "onMaximize: %s\n", (maximized ? "maximized" : "restored"));
    });

    window->addOnMinimizeConsumer([](windowing::IWindow* /*window*/, bool minimized) {
        fprintf(stderr, "onMinimize: %s\n", (minimized ? "minimized" : "restored"));
    });

    window->addOnFocusConsumer([](windowing::IWindow* /*window*/, bool focused) {
        fprintf(stderr, "onFocus: %s\n", (focused ? "true" : "false"));
    });

    window->addOnCloseConsumer([](windowing::IWindow* /*window*/) { fprintf(stderr, "onClose\n"); });

    window->addOnDropConsumer([](windowing::IWindow* /*window*/, const char* const* paths, uint32_t pathCount) {
        fprintf(stderr, "onDrop\n");
        for (uint32_t i = 0; i < pathCount; ++i)
        {
            fprintf(stderr, "  %s\n", paths[i]);
        }
    });

    window->addOnContentScaleConsumer([](windowing::IWindow* /*window*/, omni::Float2 scale) {
        fprintf(stderr, "onContentScale: %f %f\n", scale.x, scale.y);
    });

    window->addOnMouseOverConsumer(
        [](windowing::IWindow* window, bool over) { fprintf(stderr, "onMouseOver: %s\n", (over ? "true" : "false")); });

    window->addOnMouseEventConsumer([](input::IMouse* /*mouse*/, const input::MouseEvent* event) {
        switch (event->type)
        {
            case input::MouseEventType::eButtonPress:
            case input::MouseEventType::eButtonRelease:
            {
                bool isPress = (input::MouseEventType::eButtonPress == event->type);
                fprintf(stderr, "button %d %s mods:%s\n", int(event->button), (isPress ? "press" : "release"),
                        mods2str(event->modifiers));
                break;
            }

            case input::MouseEventType::eMotion:
            {
                fprintf(stderr, "motion: x:%f y:%f  delta: x:%f y:%f mods:%s\n", event->position.x, event->position.y,
                        event->positionDelta.x, event->positionDelta.y, mods2str(event->modifiers));
                break;
            }

            case input::MouseEventType::eScroll:
            {
                fprintf(stderr, "scroll: x:%f y:%f %s\n", event->scrollDelta.x, event->scrollDelta.y,
                        mods2str(event->modifiers));
                break;
            }

            default:
                fprintf(stderr, "unknown mouse event\n");
        }
    });

    windowSystem->addOnGamepadConnectConsumer([](input::IGamepad* gamepad, bool isConnected) {
        fprintf(stderr, "gamepad %s\n", (isConnected ? "connected" : "disconnected"));
        gamepad->addOnStateChangeConsumer([](input::IGamepad* gamepad, const input::GamepadState* oldState,
                                             const input::GamepadState* newState) {
            if ((oldState->leftStick.x != newState->leftStick.x) || (oldState->leftStick.y != newState->leftStick.y))
            {
                fprintf(stderr, "left:%f %f ", newState->leftStick.x, newState->leftStick.y);
            }
            if ((oldState->rightStick.x != newState->rightStick.x) || (oldState->rightStick.y != newState->rightStick.y))
            {
                fprintf(stderr, "right:%f %f ", newState->rightStick.x, newState->rightStick.y);
            }
            if ((oldState->directionPad.x != newState->directionPad.x) ||
                (oldState->directionPad.y != newState->directionPad.y))
            {
                fprintf(stderr, "dpad:%d %d ", newState->directionPad.x, newState->directionPad.y);
            }
            if (oldState->leftStickButton != newState->leftStickButton)
            {
                fprintf(stderr, "%c ", ((newState->leftStickButton > 0.0f) ? 'L' : 'l'));
            }
            if (oldState->rightStickButton != newState->rightStickButton)
            {
                fprintf(stderr, "%c ", ((newState->rightStickButton > 0.0f) ? 'L' : 'l'));
            }
            if (oldState->a != newState->a)
            {
                fprintf(stderr, "%c ", ((newState->a > 0.0f) ? 'A' : 'a'));
            }
            if (oldState->b != newState->b)
            {
                fprintf(stderr, "%c ", ((newState->b > 0.0f) ? 'B' : 'b'));
            }
            if (oldState->x != newState->x)
            {
                fprintf(stderr, "%c ", ((newState->x > 0.0f) ? 'X' : 'x'));
            }
            if (oldState->y != newState->y)
            {
                fprintf(stderr, "%c ", ((newState->y > 0.0f) ? 'Y' : 'y'));
            }
            if (oldState->select != newState->select)
            {
                fprintf(stderr, "%s ", (newState->select ? "SEL" : "sel"));
            }
            if (oldState->start != newState->start)
            {
                fprintf(stderr, "%s ", (newState->start ? "START" : "start"));
            }
            if (oldState->leftShoulder != newState->leftShoulder)
            {
                fprintf(stderr, "%s ", ((newState->leftShoulder > 0.0f) ? "lS" : "ls"));
            }
            if (oldState->rightShoulder != newState->rightShoulder)
            {
                fprintf(stderr, "%s ", ((newState->rightShoulder > 0.0f) ? "rS" : "rs"));
            }
            if (oldState->leftTrigger != newState->leftTrigger)
            {
                fprintf(stderr, "lt:%f ", newState->leftTrigger);
            }
            if (oldState->rightTrigger != newState->rightTrigger)
            {
                fprintf(stderr, "rt:%f ", newState->rightTrigger);
            }
            fprintf(stderr, "\n");
        });
    });

    window->setShown(true);

    while (!window->getShouldClose())
    {
        windowSystem->pollEvents();
    }

    fprintf(stderr, "final resize: %u %u\n", size.x, size.y);
    fprintf(stderr, "final size: %u %u\n", window->getSize().x, window->getSize().y);

    return 0;
}
#endif