Shell.h#

Contains the all-important pvr::Shell class that the user will be inheriting from for his application. See bottom of this file or of any Demo file for the newDemo function the user must implement for his application.

Includes#

  • PVRCore/IAssetProvider.h

  • PVRCore/Log.h

  • PVRCore/commandline/CommandLine.h

  • PVRCore/stream/BufferStream.h

  • PVRCore/strings/StringFunctions.h

  • PVRShell/ShellData.h

  • bitset

  • queue

Included By#

Namespaces#

Classes#

Enums#

Functions#

Source Code#

#pragma once
#include "PVRCore/commandline/CommandLine.h"
#include "PVRShell/ShellData.h"
#include "PVRCore/IAssetProvider.h"
#include "PVRCore/stream/BufferStream.h"
#include "PVRCore/Log.h"
#include "PVRCore/strings/StringFunctions.h"
#include <queue>
#include <bitset>

namespace pvr {
struct PointerLocationStore
{
    int16_t x;
    int16_t y;

    PointerLocationStore operator+(const PointerLocationStore& rhs) { return PointerLocationStore{ static_cast<int16_t>(x + rhs.x), static_cast<int16_t>(y + rhs.y) }; }

    PointerLocationStore operator-(const PointerLocationStore& rhs) { return PointerLocationStore{ static_cast<int16_t>(x - rhs.x), static_cast<int16_t>(y - rhs.y) }; }

    void operator+=(const PointerLocationStore& rhs) { *this = *this + rhs; }

    void operator-=(const PointerLocationStore& rhs) { *this = *this - rhs; }
};

class PointerLocation : public PointerLocationStore
{
public:
    PointerLocation() {}

    explicit PointerLocation(const PointerLocationStore& st) : PointerLocationStore(st) {}

    PointerLocation(int16_t x, int16_t y)
    {
        this->x = x;
        this->y = y;
    }
};

enum class SimplifiedInput
{
    NONE = 0,
    Left = 1,
    Right = 2,
    Up = 3,
    Down = 4,
    ActionClose = 5,
    Action1 = 6,
    Action2 = 7,
    Action3 = 8,
};

enum class SystemEvent
{
    SystemEvent_Quit,
    SystemEvent_LoseFocus,
    SystemEvent_GainFocus
};

enum class Keys : uint8_t
{
    // clang-format off
    // Whenever possible, keys get ASCII values of their default (non-shifted) values of a default US keyboard (101 layout).
    Backspace = 0x08,
    Tab = 0x09,
    Return = 0x0D,

    Shift = 0x10, Control = 0x11, Alt = 0x12,

    Pause = 0x13,
    PrintScreen = 0x2C,
    CapsLock = 0x14,
    Escape = 0x1B,
    Space = 0x20,

    PageUp = 0x21, PageDown = 0x22, End = 0x23, Home = 0x24,

    Left = 0x25, Up = 0x26, Right = 0x27, Down = 0x28,

    Insert = 0x2D, Delete = 0x2E,

    // ASCII-Based
    Key0 = 0x30, Key1, Key2, Key3, Key4, Key5, Key6, Key7, Key8, Key9,

    A = 0x41, B, C, D, E, F, G, H, I, J, K, L, M,
    N = 0x4E, O, P, Q, R, S, T, U, V, W, X, Y, Z,

    Num0 = 0x60, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, NumPeriod,

    F1 = 0x70, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,

    SystemKey1 = 0x5B, SystemKey2 = 0x5D,
    WindowsKey = 0x5B, MenuKey = 0x5D, // Aliases

    NumMul = 0x6A, NumAdd = 0x6B, NumSub = 0x6D, NumDiv = 0x6E,
    NumLock = 0x90, ScrollLock = 0x91,

    Semicolon = 0xBA, Equals = 0xBB, Minus = 0xBD,

    Slash = 0xBF,

    Comma = 0xBC, Period = 0xBE,

    Backquote = 0xC0,

    SquareBracketLeft = 0xDB, SquareBracketRight = 0xDD, Quote = 0xDE, Backslash = 0xDC,

    MaxNumKeyCodes,
    Unknown = 0xFF
    // clang-format on
};

inline std::string to_string(Keys key)
{
    switch (key)
    {
    case Keys::Backspace: return "Backspace";
    case Keys::Tab: return "Tab";
    case Keys::Return: return "Return";
    case Keys::Shift: return "Shift";
    case Keys::Control: return "Control";
    case Keys::Alt: return "Alt";
    case Keys::Pause: return "Pause";
    case Keys::PrintScreen: return "PrintScreen";
    case Keys::CapsLock: return "CapsLock";
    case Keys::Escape: return "Escape";
    case Keys::Space: return "Space";
    case Keys::PageUp: return "PageUp";
    case Keys::PageDown: return "PageDown";
    case Keys::End: return "End";
    case Keys::Home: return "Home";
    case Keys::Left: return "Left";
    case Keys::Up: return "Up";
    case Keys::Right: return "Right";
    case Keys::Down: return "Down";
    case Keys::Insert: return "Insert";
    case Keys::Delete: return "Delete";
    case Keys::Key0: return "Key0";
    case Keys::Key1: return "Key1";
    case Keys::Key2: return "Key2";
    case Keys::Key3: return "Key3";
    case Keys::Key4: return "Key4";
    case Keys::Key5: return "Key5";
    case Keys::Key6: return "Key6";
    case Keys::Key7: return "Key7";
    case Keys::Key8: return "Key8";
    case Keys::Key9: return "Key9";
    case Keys::A: return "A";
    case Keys::B: return "B";
    case Keys::C: return "C";
    case Keys::D: return "D";
    case Keys::E: return "E";
    case Keys::F: return "F";
    case Keys::G: return "G";
    case Keys::H: return "H";
    case Keys::I: return "I";
    case Keys::J: return "J";
    case Keys::K: return "K";
    case Keys::L: return "L";
    case Keys::M: return "M";
    case Keys::N: return "N";
    case Keys::O: return "O";
    case Keys::P: return "P";
    case Keys::Q: return "Q";
    case Keys::R: return "R";
    case Keys::S: return "S";
    case Keys::T: return "T";
    case Keys::U: return "U";
    case Keys::V: return "V";
    case Keys::W: return "W";
    case Keys::X: return "X";
    case Keys::Y: return "Y";
    case Keys::Z: return "Z";
    case Keys::Num0: return "Num0";
    case Keys::Num1: return "Num1";
    case Keys::Num2: return "Num2";
    case Keys::Num3: return "Num3";
    case Keys::Num4: return "Num4";
    case Keys::Num5: return "Num5";
    case Keys::Num6: return "Num6";
    case Keys::Num7: return "Num7";
    case Keys::Num8: return "Num9";
    case Keys::F1: return "F1";
    case Keys::F2: return "F2";
    case Keys::F3: return "F3";
    case Keys::F4: return "F4";
    case Keys::F5: return "F5";
    case Keys::F6: return "F6";
    case Keys::F7: return "F7";
    case Keys::F8: return "F8";
    case Keys::F9: return "F9";
    case Keys::F10: return "F10";
    case Keys::F11: return "F11";
    case Keys::F12: return "F12";
    case Keys::SystemKey1: return "SystemKey1";
    case Keys::SystemKey2: return "SystemKey2";
    case Keys::NumMul: return "NumMul";
    case Keys::NumAdd: return "NumAdd";
    case Keys::NumSub: return "NumSub";
    case Keys::NumDiv: return "NumDiv";
    case Keys::NumLock: return "NumLock";
    case Keys::ScrollLock: return "ScrollLock";
    case Keys::Semicolon: return "Semicolon";
    case Keys::Equals: return "Equals";
    case Keys::Minus: return "Minus";
    case Keys::Slash: return "Slash";
    case Keys::Comma: return "Comma";
    case Keys::Period: return "Period";
    case Keys::Backquote: return "Backquote";
    case Keys::SquareBracketLeft: return "SquareBracketLeft";
    case Keys::SquareBracketRight: return "SquareBracketRight";
    case Keys::Quote: return "Quote";
    case Keys::Backslash: return "Backslash";
    case Keys::Unknown: return "Unknown";

    default: return "Unknown";
    }
}

struct ConfigureEvent
{
    int x;
    int y;
    int width;
    int height;
    int border_width;
};

class Stream;
namespace platform {

struct ShellEvent
{
    enum ShellEventType
    {
        SystemEvent,
        PointingDeviceDown,
        PointingDeviceUp,
        PointingDeviceMove,
        KeyDown,
        KeyUp
    } type;

    union
    {
        PointerLocationStore location;
        uint8_t buttonIdx;
        pvr::SystemEvent systemEvent;
        Keys key;
    };
};

struct ShellData;
class ShellOS;
class Shell : public IAssetProvider
{
    friend class ShellOS;
    friend class StateMachine;

public:
    struct PointerNormalisedLocation
    {
        PointerNormalisedLocation() {}

        float x;
        float y;
    };

    struct PointingDeviceState
    {
    protected:
        PointerLocation _pointerLocation;
        PointerLocation _dragStartLocation;
        int8_t _buttons;
    public:
        PointingDeviceState() : _pointerLocation(0, 0), _dragStartLocation(0, 0), _buttons(0) {}
        PointerLocation position() const { return _pointerLocation; }

        PointerLocation dragStartPosition() const { return _dragStartLocation; }

        bool isPressed(int8_t buttonIndex) const { return (_buttons & (1 << buttonIndex)) != 0; }
        bool isDragging() const { return (_buttons & 0x80) != 0; }
    };

private:
    struct PrivatePointerState : public PointingDeviceState
    {
        void startDragging()
        {
            _buttons |= 0x80;
            _dragStartLocation = _pointerLocation;
        }
        void endDragging() { _buttons &= 0x7F; }

        void setButton(int8_t buttonIndex, bool pressed) { _buttons = (_buttons & ~(1 << buttonIndex)) | (pressed << buttonIndex); }
        void setPointerLocation(PointerLocation pointerLocation) { this->_pointerLocation = pointerLocation; }
    };

protected:
    virtual Result initApplication() = 0;

    virtual Result initView() = 0;

    virtual Result renderFrame() = 0;

    virtual Result releaseView() = 0;

    virtual Result quitApplication() = 0;

    virtual void eventClick(int buttonIdx, PointerLocation location)
    {
        (void)buttonIdx;
        (void)location;
    }

    virtual void eventDragFinished(PointerLocation location) { (void)location; }

    virtual void eventDragStart(int buttonIdx, PointerLocation location)
    {
        (void)location;
        (void)buttonIdx;
    }

    virtual void eventButtonDown(int buttonIdx) { (void)buttonIdx; }

    virtual void eventButtonUp(int buttonIdx) { (void)buttonIdx; }

    virtual void eventKeyDown(Keys key) { (void)key; }

    virtual void eventKeyStroke(Keys key) { (void)key; }

    virtual void eventKeyUp(Keys key) { (void)key; }

    virtual void eventMappedInput(SimplifiedInput key)
    {
        switch (key)
        {
        case SimplifiedInput::ActionClose: exitShell(); break;
        default: break;
        }
    }

    Shell();

public:
    void onKeyDown(Keys key)
    {
        ShellEvent evt;
        evt.type = ShellEvent::KeyDown;
        evt.key = key;
        eventQueue.push(evt);
    }

    void onKeyUp(Keys key)
    {
        ShellEvent evt;
        evt.type = ShellEvent::KeyUp;
        evt.key = key;
        eventQueue.push(evt);
    }

    void onPointingDeviceDown(uint8_t buttonIdx)
    {
        ShellEvent evt;
        evt.type = ShellEvent::PointingDeviceDown;
        evt.buttonIdx = buttonIdx;
        eventQueue.push(evt);
    }

    void onPointingDeviceUp(uint8_t buttonIdx)
    {
        ShellEvent evt;
        evt.type = ShellEvent::PointingDeviceUp;
        evt.buttonIdx = buttonIdx;
        eventQueue.push(evt);
    }

    void onSystemEvent(SystemEvent systemEvent)
    {
        ShellEvent evt;
        evt.type = ShellEvent::SystemEvent;
        evt.systemEvent = systemEvent;
        eventQueue.push(evt);
    }

    void onConfigureEvent(const ConfigureEvent& configureEvent) { _configureEvent = configureEvent; }

private:
    void updatePointerPosition(PointerLocation location);
    void implKeyDown(Keys key);
    void implKeyUp(Keys key);
    void implPointingDeviceDown(uint8_t buttonIdx);
    void implPointingDeviceUp(uint8_t buttonIdx);
    void implSystemEvent(SystemEvent systemEvent);

    std::queue<ShellEvent> eventQueue;

    void processShellEvents();

public:
    virtual ~Shell();

    DisplayAttributes& getDisplayAttributes();

    const DisplayAttributes& getDisplayAttributes() const;

    OSConnection getConnection() const;

    OSDisplay getDisplay() const;

    OSWindow getWindow() const;

private:
    // called by the State Machine

    bool init(ShellData* data);
    Result shellInitApplication();
    Result shellQuitApplication();
    Result shellInitView();
    Result shellReleaseView();
    Result shellRenderFrame();

public:
    bool isKeyPressed(Keys key) const { return isKeyPressedVal(key); }

    bool isButtonPressed(int8_t buttonIndex) const { return buttonIndex > 7 ? false : _pointerState.isPressed(buttonIndex); }

    PointerLocation getPointerAbsolutePosition() const { return _pointerState.position(); }

    PointerLocation getPointerRelativePosition() const
    {
        PointerLocation pointerloc = getPointerAbsolutePosition();
        pointerloc.x -= static_cast<uint16_t>(_configureEvent.x);
        pointerloc.y -= static_cast<uint16_t>(_configureEvent.y);
        return pointerloc;
    }

    PointerNormalisedLocation getPointerNormalisedPosition() const
    {
        PointerNormalisedLocation pos;
        pos.x = _pointerState.position().x / static_cast<float>(getWidth());
        pos.y = _pointerState.position().y / static_cast<float>(getHeight());
        return pos;
    }

    const PointingDeviceState& getPointingDeviceState() const { return _pointerState; }
    /* End Input Handling :  Queried */

    uint64_t getTime() const;

    uint64_t getFrameTime() const;

    uint64_t getTimeAtInitApplication() const;

    const platform::CommandLineParser::ParsedCommandLine& getCommandLine() const;

    void setFullscreen(const bool fullscreen);

    bool isFullScreen() const;

    uint32_t getWidth() const;

    uint32_t getHeight() const;

    uint32_t getCaptureFrameScale() const;

    Api getMaxApi() const;

    Api getMinApi() const;

    Result setDimensions(uint32_t w, uint32_t h);

    uint32_t getPositionX() const;

    uint32_t getPositionY() const;

    Result setPosition(uint32_t x, uint32_t y);

    int32_t getQuitAfterFrame() const;

    void setQuitAfterFrame(uint32_t value);

    float getQuitAfterTime() const;

    void setQuitAfterTime(float value);

    VsyncMode getVsyncMode() const;

    void setVsyncMode(VsyncMode mode);

    void setPreferredSwapChainLength(uint32_t swapChainLength);

    void forceReleaseInitView();

    void forceReleaseInitWindow();

    uint32_t getAASamples() const;

    void setAASamples(uint32_t value);

    uint32_t getColorBitsPerPixel() const;

    uint32_t getDepthBitsPerPixel() const;

    uint32_t getStencilBitsPerPixel() const;

    ColorSpace getBackBufferColorspace() const;

    void setBackBufferColorspace(ColorSpace colorSpace);

    void setColorBitsPerPixel(uint32_t r, uint32_t g, uint32_t b, uint32_t a);

    void setDepthBitsPerPixel(uint32_t value);

    void setStencilBitsPerPixel(uint32_t value);

    void setForceFrameTime(const bool value);

    bool isForcingFrameTime() const;

    bool isScreenRotated() const;

    bool isScreenPortrait() const;

    bool isScreenLandscape() const;

    void showOutputInfo() const;

    void setCaptureFrames(uint32_t start, uint32_t stop);

    void setCaptureFrameScale(uint32_t value);

    uint32_t getCaptureFrameStart() const;

    uint32_t getCaptureFrameStop() const;

    uint32_t getFrameNumber() const;

    uint32_t getContextPriority() const;

    void setContextPriority(uint32_t value);

    uint32_t getDesiredConfig() const;

    void setDesiredConfig(uint32_t value);

    uint32_t getFakeFrameTime() const;

    void setFakeFrameTime(uint32_t value);

    bool isShowingFPS() const;

    void setShowFPS(bool showFPS);

    float getFPS() const;

    static const char* getSDKVersion() { return PVRSDK_BUILD; }

    template<typename... Args>
    void setExitMessage(const char* const format, Args... args)
    {
        _data->exitMessage = strings::createFormatted(format, args...);
        Log(LogLevel::Information, strings::createFormatted("Exit message set to: %s", _data->exitMessage.c_str()).c_str());
    }

    template<typename... Args>
    void setApplicationName(const char* const format, Args... args);

    template<typename... Args>
    void setTitle(const char* const format, Args... args)
    {
        _data->attributes.windowTitle = strings::createFormatted(format, args...);
    }

    const std::string& getExitMessage() const;

    const std::string& getApplicationName() const;

    const std::string& getDefaultReadPath() const;

    const std::vector<std::string>& getReadPaths() const;

    const std::string& getWritePath() const;

    void exitShell();

    std::unique_ptr<Stream> getAssetStream(const std::string& filename, bool errorIfFileNotFound = true) const;

    std::unique_ptr<Stream> getWriteAssetStream(const std::string& filename, bool allowRead = false, bool truncateIfExists = false) const;

    ShellOS& getOS() const;

    bool shouldTakeScreenshot() const { return getFrameNumber() >= getCaptureFrameStart() && getFrameNumber() <= getCaptureFrameStop(); }

    std::string getScreenshotFileName() const;

    void addReadPath(const std::string& readPath);

private:
    bool _dragging;
    std::bitset<256> _keystate;
    PrivatePointerState _pointerState;
    ShellData* _data;
    ConfigureEvent _configureEvent;
    SimplifiedInput MapKeyToMainInput(Keys key) const
    {
        switch (key)
        {
        case Keys::Space:
        case Keys::Return: return SimplifiedInput::Action1; break;
        case Keys::Escape:
        case Keys::Q: return SimplifiedInput::ActionClose; break;
        case Keys::Key1: return SimplifiedInput::Action2; break;
        case Keys::Key2: return SimplifiedInput::Action3; break;

        case Keys::Left: return SimplifiedInput::Left; break;
        case Keys::Right: return SimplifiedInput::Right; break;
        case Keys::Up: return SimplifiedInput::Up; break;
        case Keys::Down: return SimplifiedInput::Down; break;
        default: return SimplifiedInput::NONE;
        }
    }
    bool setKeyPressedVal(Keys key, char val)
    {
        bool temp = _keystate[static_cast<uint32_t>(key)];
        _keystate[static_cast<uint32_t>(key)] = (val != 0);
        return temp;
    }
    bool isKeyPressedVal(Keys key) const { return _keystate[static_cast<uint32_t>(key)]; }
    SimplifiedInput MapPointingDeviceButtonToSimpleInput(int buttonIdx) const
    {
        switch (buttonIdx)
        {
        case 0: return SimplifiedInput::Action1;
        case 1: return SimplifiedInput::Action2;
        case 2: return SimplifiedInput::Action3;
        default: return SimplifiedInput::NONE;
        }
    }
};

} // namespace platform
using pvr::platform::Shell;
std::unique_ptr<pvr::Shell> newDemo();
} // namespace pvr