cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_BWin.h (19137B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21
     22#ifndef _SDL_BWin_h
     23#define _SDL_BWin_h
     24
     25#ifdef __cplusplus
     26extern "C" {
     27#endif
     28
     29#include "../../SDL_internal.h"
     30#include "SDL.h"
     31#include "SDL_syswm.h"
     32#include "SDL_bframebuffer.h"
     33
     34#ifdef __cplusplus
     35}
     36#endif
     37
     38#include <stdio.h>
     39#include <AppKit.h>
     40#include <InterfaceKit.h>
     41#include <be/game/DirectWindow.h>
     42#if SDL_VIDEO_OPENGL
     43#include <be/opengl/GLView.h>
     44#endif
     45#include "SDL_events.h"
     46#include "../../main/haiku/SDL_BApp.h"
     47
     48
     49enum WinCommands {
     50    BWIN_MOVE_WINDOW,
     51    BWIN_RESIZE_WINDOW,
     52    BWIN_SHOW_WINDOW,
     53    BWIN_HIDE_WINDOW,
     54    BWIN_MAXIMIZE_WINDOW,
     55    BWIN_MINIMIZE_WINDOW,
     56    BWIN_RESTORE_WINDOW,
     57    BWIN_SET_TITLE,
     58    BWIN_SET_BORDERED,
     59    BWIN_FULLSCREEN
     60};
     61
     62
     63class SDL_BWin:public BDirectWindow
     64{
     65  public:
     66    /* Constructor/Destructor */
     67    SDL_BWin(BRect bounds, window_look look, uint32 flags)
     68        : BDirectWindow(bounds, "Untitled", look, B_NORMAL_WINDOW_FEEL, flags)
     69    {
     70        _last_buttons = 0;
     71
     72#if SDL_VIDEO_OPENGL
     73        _SDL_GLView = NULL;
     74#endif
     75        _shown = false;
     76        _inhibit_resize = false;
     77        _mouse_focused = false;
     78        _prev_frame = NULL;
     79
     80        /* Handle framebuffer stuff */
     81        _connected = _connection_disabled = false;
     82        _buffer_created = _buffer_dirty = false;
     83        _trash_window_buffer = false;
     84        _buffer_locker = new BLocker();
     85        _bitmap = NULL;
     86        _clips = NULL;
     87
     88#ifdef DRAWTHREAD
     89        _draw_thread_id = spawn_thread(BE_DrawThread, "drawing_thread",
     90                            B_NORMAL_PRIORITY, (void*) this);
     91        resume_thread(_draw_thread_id);
     92#endif
     93    }
     94
     95    virtual ~ SDL_BWin()
     96    {
     97        Lock();
     98        _connection_disabled = true;
     99        int32 result;
    100
    101#if SDL_VIDEO_OPENGL
    102        if (_SDL_GLView) {
    103            _SDL_GLView->UnlockGL();
    104            RemoveChild(_SDL_GLView);   /* Why was this outside the if
    105                                            statement before? */
    106        }
    107
    108#endif
    109        Unlock();
    110#if SDL_VIDEO_OPENGL
    111        if (_SDL_GLView) {
    112            delete _SDL_GLView;
    113        }
    114#endif
    115
    116        /* Clean up framebuffer stuff */
    117        _buffer_locker->Lock();
    118#ifdef DRAWTHREAD
    119        wait_for_thread(_draw_thread_id, &result);
    120#endif
    121        free(_clips);
    122        delete _buffer_locker;
    123    }
    124
    125
    126    /* * * * * OpenGL functionality * * * * */
    127#if SDL_VIDEO_OPENGL
    128    virtual BGLView *CreateGLView(Uint32 gl_flags) {
    129        Lock();
    130        if (_SDL_GLView == NULL) {
    131            _SDL_GLView = new BGLView(Bounds(), "SDL GLView",
    132                                     B_FOLLOW_ALL_SIDES,
    133                                     (B_WILL_DRAW | B_FRAME_EVENTS),
    134                                     gl_flags);
    135        }
    136        AddChild(_SDL_GLView);
    137        _SDL_GLView->EnableDirectMode(true);
    138        _SDL_GLView->LockGL();  /* "New" GLViews are created */
    139        Unlock();
    140        return (_SDL_GLView);
    141    }
    142
    143    virtual void RemoveGLView() {
    144        Lock();
    145        if(_SDL_GLView) {
    146            _SDL_GLView->UnlockGL();
    147            RemoveChild(_SDL_GLView);
    148        }
    149        Unlock();
    150    }
    151
    152    virtual void SwapBuffers(void) {
    153        _SDL_GLView->UnlockGL();
    154        _SDL_GLView->LockGL();
    155        _SDL_GLView->SwapBuffers();
    156    }
    157#endif
    158
    159    /* * * * * Framebuffering* * * * */
    160    virtual void DirectConnected(direct_buffer_info *info) {
    161        if(!_connected && _connection_disabled) {
    162            return;
    163        }
    164
    165        /* Determine if the pixel buffer is usable after this update */
    166        _trash_window_buffer =      _trash_window_buffer
    167                                || ((info->buffer_state & B_BUFFER_RESIZED)
    168                                || (info->buffer_state & B_BUFFER_RESET)
    169                                || (info->driver_state == B_MODE_CHANGED));
    170        LockBuffer();
    171
    172        switch(info->buffer_state & B_DIRECT_MODE_MASK) {
    173        case B_DIRECT_START:
    174            _connected = true;
    175
    176        case B_DIRECT_MODIFY:
    177            if(_clips) {
    178                free(_clips);
    179                _clips = NULL;
    180            }
    181
    182            _num_clips = info->clip_list_count;
    183            _clips = (clipping_rect *)malloc(_num_clips*sizeof(clipping_rect));
    184            if(_clips) {
    185                memcpy(_clips, info->clip_list,
    186                    _num_clips*sizeof(clipping_rect));
    187
    188                _bits = (uint8*) info->bits;
    189                _row_bytes = info->bytes_per_row;
    190                _bounds = info->window_bounds;
    191                _bytes_per_px = info->bits_per_pixel / 8;
    192                _buffer_dirty = true;
    193            }
    194            break;
    195
    196        case B_DIRECT_STOP:
    197            _connected = false;
    198            break;
    199        }
    200#if SDL_VIDEO_OPENGL
    201        if(_SDL_GLView) {
    202            _SDL_GLView->DirectConnected(info);
    203        }
    204#endif
    205
    206
    207        /* Call the base object directconnected */
    208        BDirectWindow::DirectConnected(info);
    209
    210        UnlockBuffer();
    211
    212    }
    213
    214
    215
    216
    217    /* * * * * Event sending * * * * */
    218    /* Hook functions */
    219    virtual void FrameMoved(BPoint origin) {
    220        /* Post a message to the BApp so that it can handle the window event */
    221        BMessage msg(BAPP_WINDOW_MOVED);
    222        msg.AddInt32("window-x", (int)origin.x);
    223        msg.AddInt32("window-y", (int)origin.y);
    224        _PostWindowEvent(msg);
    225
    226        /* Perform normal hook operations */
    227        BDirectWindow::FrameMoved(origin);
    228    }
    229
    230    virtual void FrameResized(float width, float height) {
    231        /* Post a message to the BApp so that it can handle the window event */
    232        BMessage msg(BAPP_WINDOW_RESIZED);
    233
    234        msg.AddInt32("window-w", (int)width + 1);
    235        msg.AddInt32("window-h", (int)height + 1);
    236        _PostWindowEvent(msg);
    237
    238        /* Perform normal hook operations */
    239        BDirectWindow::FrameResized(width, height);
    240    }
    241
    242    virtual bool QuitRequested() {
    243        BMessage msg(BAPP_WINDOW_CLOSE_REQUESTED);
    244        _PostWindowEvent(msg);
    245
    246        /* We won't allow a quit unless asked by DestroyWindow() */
    247        return false;
    248    }
    249
    250    virtual void WindowActivated(bool active) {
    251        BMessage msg(BAPP_KEYBOARD_FOCUS);  /* Mouse focus sold separately */
    252        _PostWindowEvent(msg);
    253    }
    254
    255    virtual void Zoom(BPoint origin,
    256                float width,
    257                float height) {
    258        BMessage msg(BAPP_MAXIMIZE);    /* Closest thing to maximization Haiku has */
    259        _PostWindowEvent(msg);
    260
    261        /* Before the window zooms, record its size */
    262        if( !_prev_frame )
    263            _prev_frame = new BRect(Frame());
    264
    265        /* Perform normal hook operations */
    266        BDirectWindow::Zoom(origin, width, height);
    267    }
    268
    269    /* Member functions */
    270    virtual void Show() {
    271        while(IsHidden()) {
    272            BDirectWindow::Show();
    273        }
    274        _shown = true;
    275
    276        BMessage msg(BAPP_SHOW);
    277        _PostWindowEvent(msg);
    278    }
    279
    280    virtual void Hide() {
    281        BDirectWindow::Hide();
    282        _shown = false;
    283
    284        BMessage msg(BAPP_HIDE);
    285        _PostWindowEvent(msg);
    286    }
    287
    288    virtual void Minimize(bool minimize) {
    289        BDirectWindow::Minimize(minimize);
    290        int32 minState = (minimize ? BAPP_MINIMIZE : BAPP_RESTORE);
    291
    292        BMessage msg(minState);
    293        _PostWindowEvent(msg);
    294    }
    295
    296
    297    /* BView message interruption */
    298    virtual void DispatchMessage(BMessage * msg, BHandler * target)
    299    {
    300        BPoint where;   /* Used by mouse moved */
    301        int32 buttons;  /* Used for mouse button events */
    302        int32 key;      /* Used for key events */
    303
    304        switch (msg->what) {
    305        case B_MOUSE_MOVED:
    306            int32 transit;
    307            if (msg->FindPoint("where", &where) == B_OK
    308                && msg->FindInt32("be:transit", &transit) == B_OK) {
    309                _MouseMotionEvent(where, transit);
    310            }
    311
    312            /* FIXME: Apparently a button press/release event might be dropped
    313               if made before before a different button is released.  Does
    314               B_MOUSE_MOVED have the data needed to check if a mouse button
    315               state has changed? */
    316            if (msg->FindInt32("buttons", &buttons) == B_OK) {
    317                _MouseButtonEvent(buttons);
    318            }
    319            break;
    320
    321        case B_MOUSE_DOWN:
    322        case B_MOUSE_UP:
    323            /* _MouseButtonEvent() detects any and all buttons that may have
    324               changed state, as well as that button's new state */
    325            if (msg->FindInt32("buttons", &buttons) == B_OK) {
    326                _MouseButtonEvent(buttons);
    327            }
    328            break;
    329
    330        case B_MOUSE_WHEEL_CHANGED:
    331            float x, y;
    332            if (msg->FindFloat("be:wheel_delta_x", &x) == B_OK
    333                && msg->FindFloat("be:wheel_delta_y", &y) == B_OK) {
    334                    _MouseWheelEvent((int)x, (int)y);
    335            }
    336            break;
    337
    338        case B_KEY_DOWN:
    339        case B_UNMAPPED_KEY_DOWN:      /* modifier keys are unmapped */
    340            if (msg->FindInt32("key", &key) == B_OK) {
    341                _KeyEvent((SDL_Scancode)key, SDL_PRESSED);
    342            }
    343            break;
    344
    345        case B_KEY_UP:
    346        case B_UNMAPPED_KEY_UP:        /* modifier keys are unmapped */
    347            if (msg->FindInt32("key", &key) == B_OK) {
    348                _KeyEvent(key, SDL_RELEASED);
    349            }
    350            break;
    351
    352        default:
    353            /* move it after switch{} so it's always handled
    354               that way we keep Haiku features like:
    355               - CTRL+Q to close window (and other shortcuts)
    356               - PrintScreen to make screenshot into /boot/home
    357               - etc.. */
    358            /* BDirectWindow::DispatchMessage(msg, target); */
    359            break;
    360        }
    361
    362        BDirectWindow::DispatchMessage(msg, target);
    363    }
    364
    365    /* Handle command messages */
    366    virtual void MessageReceived(BMessage* message) {
    367        switch (message->what) {
    368            /* Handle commands from SDL */
    369            case BWIN_SET_TITLE:
    370                _SetTitle(message);
    371                break;
    372            case BWIN_MOVE_WINDOW:
    373                _MoveTo(message);
    374                break;
    375            case BWIN_RESIZE_WINDOW:
    376                _ResizeTo(message);
    377                break;
    378            case BWIN_SET_BORDERED:
    379                _SetBordered(message);
    380                break;
    381            case BWIN_SHOW_WINDOW:
    382                Show();
    383                break;
    384            case BWIN_HIDE_WINDOW:
    385                Hide();
    386                break;
    387            case BWIN_MAXIMIZE_WINDOW:
    388                BWindow::Zoom();
    389                break;
    390            case BWIN_MINIMIZE_WINDOW:
    391                Minimize(true);
    392                break;
    393            case BWIN_RESTORE_WINDOW:
    394                _Restore();
    395                break;
    396            case BWIN_FULLSCREEN:
    397                _SetFullScreen(message);
    398                break;
    399            default:
    400                /* Perform normal message handling */
    401                BDirectWindow::MessageReceived(message);
    402                break;
    403        }
    404
    405    }
    406
    407
    408
    409    /* Accessor methods */
    410    bool IsShown() { return _shown; }
    411    int32 GetID() { return _id; }
    412    uint32 GetRowBytes() { return _row_bytes; }
    413    int32 GetFbX() { return _bounds.left; }
    414    int32 GetFbY() { return _bounds.top; }
    415    bool ConnectionEnabled() { return !_connection_disabled; }
    416    bool Connected() { return _connected; }
    417    clipping_rect *GetClips() { return _clips; }
    418    int32 GetNumClips() { return _num_clips; }
    419    uint8* GetBufferPx() { return _bits; }
    420    int32 GetBytesPerPx() { return _bytes_per_px; }
    421    bool CanTrashWindowBuffer() { return _trash_window_buffer; }
    422    bool BufferExists() { return _buffer_created; }
    423    bool BufferIsDirty() { return _buffer_dirty; }
    424    BBitmap *GetBitmap() { return _bitmap; }
    425#if SDL_VIDEO_OPENGL
    426    BGLView *GetGLView() { return _SDL_GLView; }
    427#endif
    428
    429    /* Setter methods */
    430    void SetID(int32 id) { _id = id; }
    431    void SetBufferExists(bool bufferExists) { _buffer_created = bufferExists; }
    432    void LockBuffer() { _buffer_locker->Lock(); }
    433    void UnlockBuffer() { _buffer_locker->Unlock(); }
    434    void SetBufferDirty(bool bufferDirty) { _buffer_dirty = bufferDirty; }
    435    void SetTrashBuffer(bool trash) { _trash_window_buffer = trash;     }
    436    void SetBitmap(BBitmap *bitmap) { _bitmap = bitmap; }
    437
    438
    439private:
    440    /* Event redirection */
    441    void _MouseMotionEvent(BPoint &where, int32 transit) {
    442        if(transit == B_EXITED_VIEW) {
    443            /* Change mouse focus */
    444            if(_mouse_focused) {
    445                _MouseFocusEvent(false);
    446            }
    447        } else {
    448            /* Change mouse focus */
    449            if (!_mouse_focused) {
    450                _MouseFocusEvent(true);
    451            }
    452            BMessage msg(BAPP_MOUSE_MOVED);
    453            msg.AddInt32("x", (int)where.x);
    454            msg.AddInt32("y", (int)where.y);
    455
    456            _PostWindowEvent(msg);
    457        }
    458    }
    459
    460    void _MouseFocusEvent(bool focusGained) {
    461        _mouse_focused = focusGained;
    462        BMessage msg(BAPP_MOUSE_FOCUS);
    463        msg.AddBool("focusGained", focusGained);
    464        _PostWindowEvent(msg);
    465
    466/* FIXME: Why were these here?
    467 if false: be_app->SetCursor(B_HAND_CURSOR);
    468 if true:  SDL_SetCursor(NULL); */
    469    }
    470
    471    void _MouseButtonEvent(int32 buttons) {
    472        int32 buttonStateChange = buttons ^ _last_buttons;
    473
    474        /* Make sure at least one button has changed state */
    475        if( !(buttonStateChange) ) {
    476            return;
    477        }
    478
    479        /* Add any mouse button events */
    480        if(buttonStateChange & B_PRIMARY_MOUSE_BUTTON) {
    481            _SendMouseButton(SDL_BUTTON_LEFT, buttons &
    482                B_PRIMARY_MOUSE_BUTTON);
    483        }
    484        if(buttonStateChange & B_SECONDARY_MOUSE_BUTTON) {
    485            _SendMouseButton(SDL_BUTTON_RIGHT, buttons &
    486                B_PRIMARY_MOUSE_BUTTON);
    487        }
    488        if(buttonStateChange & B_TERTIARY_MOUSE_BUTTON) {
    489            _SendMouseButton(SDL_BUTTON_MIDDLE, buttons &
    490                B_PRIMARY_MOUSE_BUTTON);
    491        }
    492
    493        _last_buttons = buttons;
    494    }
    495
    496    void _SendMouseButton(int32 button, int32 state) {
    497        BMessage msg(BAPP_MOUSE_BUTTON);
    498        msg.AddInt32("button-id", button);
    499        msg.AddInt32("button-state", state);
    500        _PostWindowEvent(msg);
    501    }
    502
    503    void _MouseWheelEvent(int32 x, int32 y) {
    504        /* Create a message to pass along to the BeApp thread */
    505        BMessage msg(BAPP_MOUSE_WHEEL);
    506        msg.AddInt32("xticks", x);
    507        msg.AddInt32("yticks", y);
    508        _PostWindowEvent(msg);
    509    }
    510
    511    void _KeyEvent(int32 keyCode, int32 keyState) {
    512        /* Create a message to pass along to the BeApp thread */
    513        BMessage msg(BAPP_KEY);
    514        msg.AddInt32("key-state", keyState);
    515        msg.AddInt32("key-scancode", keyCode);
    516        be_app->PostMessage(&msg);
    517        /* Apparently SDL only uses the scancode */
    518    }
    519
    520    void _RepaintEvent() {
    521        /* Force a repaint: Call the SDL exposed event */
    522        BMessage msg(BAPP_REPAINT);
    523        _PostWindowEvent(msg);
    524    }
    525    void _PostWindowEvent(BMessage &msg) {
    526        msg.AddInt32("window-id", _id);
    527        be_app->PostMessage(&msg);
    528    }
    529
    530    /* Command methods (functions called upon by SDL) */
    531    void _SetTitle(BMessage *msg) {
    532        const char *title;
    533        if(
    534            msg->FindString("window-title", &title) != B_OK
    535        ) {
    536            return;
    537        }
    538        SetTitle(title);
    539    }
    540
    541    void _MoveTo(BMessage *msg) {
    542        int32 x, y;
    543        if(
    544            msg->FindInt32("window-x", &x) != B_OK ||
    545            msg->FindInt32("window-y", &y) != B_OK
    546        ) {
    547            return;
    548        }
    549        MoveTo(x, y);
    550    }
    551
    552    void _ResizeTo(BMessage *msg) {
    553        int32 w, h;
    554        if(
    555            msg->FindInt32("window-w", &w) != B_OK ||
    556            msg->FindInt32("window-h", &h) != B_OK
    557        ) {
    558            return;
    559        }
    560        ResizeTo(w, h);
    561    }
    562
    563    void _SetBordered(BMessage *msg) {
    564        bool bEnabled;
    565        if(msg->FindBool("window-border", &bEnabled) != B_OK) {
    566            return;
    567        }
    568        SetLook(bEnabled ? B_BORDERED_WINDOW_LOOK : B_NO_BORDER_WINDOW_LOOK);
    569    }
    570
    571    void _Restore() {
    572        if(IsMinimized()) {
    573            Minimize(false);
    574        } else if(IsHidden()) {
    575            Show();
    576        } else if(_prev_frame != NULL) {    /* Zoomed */
    577            MoveTo(_prev_frame->left, _prev_frame->top);
    578            ResizeTo(_prev_frame->Width(), _prev_frame->Height());
    579        }
    580    }
    581
    582    void _SetFullScreen(BMessage *msg) {
    583        bool fullscreen;
    584        if(
    585            msg->FindBool("fullscreen", &fullscreen) != B_OK
    586        ) {
    587            return;
    588        }
    589        SetFullScreen(fullscreen);
    590    }
    591
    592    /* Members */
    593#if SDL_VIDEO_OPENGL
    594    BGLView * _SDL_GLView;
    595#endif
    596
    597    int32 _last_buttons;
    598    int32 _id;  /* Window id used by SDL_BApp */
    599    bool  _mouse_focused;       /* Does this window have mouse focus? */
    600    bool  _shown;
    601    bool  _inhibit_resize;
    602
    603    BRect *_prev_frame; /* Previous position and size of the window */
    604
    605    /* Framebuffer members */
    606    bool            _connected,
    607                    _connection_disabled,
    608                    _buffer_created,
    609                    _buffer_dirty,
    610                    _trash_window_buffer;
    611    uint8          *_bits;
    612    uint32          _row_bytes;
    613    clipping_rect   _bounds;
    614    BLocker        *_buffer_locker;
    615    clipping_rect  *_clips;
    616    int32           _num_clips;
    617    int32           _bytes_per_px;
    618    thread_id       _draw_thread_id;
    619
    620    BBitmap        *_bitmap;
    621};
    622
    623
    624/* FIXME:
    625 * An explanation of framebuffer flags.
    626 *
    627 * _connected -           Original variable used to let the drawing thread know
    628 *                         when changes are being made to the other framebuffer
    629 *                         members.
    630 * _connection_disabled - Used to signal to the drawing thread that the window
    631 *                         is closing, and the thread should exit.
    632 * _buffer_created -      True if the current buffer is valid
    633 * _buffer_dirty -        True if the window should be redrawn.
    634 * _trash_window_buffer - True if the window buffer needs to be trashed partway
    635 *                         through a draw cycle.  Occurs when the previous
    636 *                         buffer provided by DirectConnected() is invalidated.
    637 */
    638#endif