cscg22-gearboy

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

SDL_rpimouse.c (9737B)


      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#include "../../SDL_internal.h"
     22
     23#if SDL_VIDEO_DRIVER_RPI
     24
     25#include "SDL_assert.h"
     26#include "SDL_surface.h"
     27
     28#include "SDL_rpivideo.h"
     29#include "SDL_rpimouse.h"
     30
     31#include "../SDL_sysvideo.h"
     32#include "../../events/SDL_mouse_c.h"
     33#include "../../events/default_cursor.h"
     34
     35/* Copied from vc_vchi_dispmanx.h which is bugged and tries to include a non existing file */
     36/* Attributes changes flag mask */
     37#define ELEMENT_CHANGE_LAYER          (1<<0)
     38#define ELEMENT_CHANGE_OPACITY        (1<<1)
     39#define ELEMENT_CHANGE_DEST_RECT      (1<<2)
     40#define ELEMENT_CHANGE_SRC_RECT       (1<<3)
     41#define ELEMENT_CHANGE_MASK_RESOURCE  (1<<4)
     42#define ELEMENT_CHANGE_TRANSFORM      (1<<5)
     43/* End copied from vc_vchi_dispmanx.h */
     44
     45static SDL_Cursor *RPI_CreateDefaultCursor(void);
     46static SDL_Cursor *RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y);
     47static int RPI_ShowCursor(SDL_Cursor * cursor);
     48static void RPI_MoveCursor(SDL_Cursor * cursor);
     49static void RPI_FreeCursor(SDL_Cursor * cursor);
     50static void RPI_WarpMouse(SDL_Window * window, int x, int y);
     51static void RPI_WarpMouseGlobal(int x, int y);
     52
     53static SDL_Cursor *
     54RPI_CreateDefaultCursor(void)
     55{
     56    return SDL_CreateCursor(default_cdata, default_cmask, DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
     57}
     58
     59/* Create a cursor from a surface */
     60static SDL_Cursor *
     61RPI_CreateCursor(SDL_Surface * surface, int hot_x, int hot_y)
     62{
     63    RPI_CursorData *curdata;
     64    SDL_Cursor *cursor;
     65    int ret;
     66    VC_RECT_T dst_rect;
     67    Uint32 dummy;
     68        
     69    SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
     70    SDL_assert(surface->pitch == surface->w * 4);
     71    
     72    cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
     73    curdata = (RPI_CursorData *) SDL_calloc(1, sizeof(*curdata));
     74
     75    curdata->hot_x = hot_x;
     76    curdata->hot_y = hot_y;
     77    curdata->w = surface->w;
     78    curdata->h = surface->h;
     79    
     80    /* This usage is inspired by Wayland/Weston RPI code, how they figured this out is anyone's guess */
     81    curdata->resource = vc_dispmanx_resource_create( VC_IMAGE_ARGB8888, surface->w | (surface->pitch << 16), surface->h | (surface->h << 16), &dummy );
     82    SDL_assert(curdata->resource);
     83    vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
     84    /* A note from Weston: 
     85     * vc_dispmanx_resource_write_data() ignores ifmt,
     86     * rect.x, rect.width, and uses stride only for computing
     87     * the size of the transfer as rect.height * stride.
     88     * Therefore we can only write rows starting at x=0.
     89     */
     90    ret = vc_dispmanx_resource_write_data( curdata->resource, VC_IMAGE_ARGB8888, surface->pitch, surface->pixels, &dst_rect );
     91    SDL_assert ( ret == DISPMANX_SUCCESS );
     92    
     93    cursor->driverdata = curdata;
     94    
     95    return cursor;
     96
     97}
     98
     99/* Show the specified cursor, or hide if cursor is NULL */
    100static int
    101RPI_ShowCursor(SDL_Cursor * cursor)
    102{
    103    int ret;
    104    DISPMANX_UPDATE_HANDLE_T update;
    105    RPI_CursorData *curdata;
    106    VC_RECT_T src_rect, dst_rect;
    107    SDL_Mouse *mouse;
    108    SDL_VideoDisplay *display;
    109    SDL_DisplayData *data;
    110    VC_DISPMANX_ALPHA_T alpha = {  DISPMANX_FLAGS_ALPHA_FROM_SOURCE /* flags */ , 255 /*opacity 0->255*/,  0 /* mask */ };
    111    
    112    mouse = SDL_GetMouse();
    113    if (mouse == NULL) {
    114        return -1;
    115    }
    116    
    117    if (cursor == NULL) {
    118        /* FIXME: We hide the current mouse's cursor, what we actually need is *_HideCursor */
    119
    120        if ( mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
    121            curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
    122            if (curdata->element > DISPMANX_NO_HANDLE) {
    123                update = vc_dispmanx_update_start( 10 );
    124                SDL_assert( update );
    125                ret = vc_dispmanx_element_remove( update, curdata->element );
    126                SDL_assert( ret == DISPMANX_SUCCESS );
    127                ret = vc_dispmanx_update_submit_sync( update );
    128                SDL_assert( ret == DISPMANX_SUCCESS );
    129                curdata->element = DISPMANX_NO_HANDLE;
    130            }
    131        }
    132        return 0;
    133    }
    134    
    135    curdata = (RPI_CursorData *) cursor->driverdata;
    136    if (curdata == NULL) {
    137        return -1;
    138    }
    139    
    140    if (mouse->focus == NULL) {
    141        return -1;
    142    }
    143    
    144    display = SDL_GetDisplayForWindow(mouse->focus);
    145    if (display == NULL) {
    146        return -1;
    147    }
    148    
    149    data = (SDL_DisplayData*) display->driverdata;
    150    if (data == NULL) {
    151        return -1;
    152    }
    153    
    154    if (curdata->element == DISPMANX_NO_HANDLE) {
    155        vc_dispmanx_rect_set( &src_rect, 0, 0, curdata->w << 16, curdata->h << 16 );
    156        vc_dispmanx_rect_set( &dst_rect, 0, 0, curdata->w, curdata->h);
    157        
    158        update = vc_dispmanx_update_start( 10 );
    159        SDL_assert( update );
    160
    161        curdata->element = vc_dispmanx_element_add( update,
    162                                                    data->dispman_display,
    163                                                    SDL_RPI_MOUSELAYER, // layer
    164                                                    &dst_rect,
    165                                                    curdata->resource,
    166                                                    &src_rect,
    167                                                    DISPMANX_PROTECTION_NONE,
    168                                                    &alpha,
    169                                                    DISPMANX_NO_HANDLE, // clamp
    170                                                    VC_IMAGE_ROT0 );
    171        SDL_assert( curdata->element > DISPMANX_NO_HANDLE);
    172        ret = vc_dispmanx_update_submit_sync( update );
    173        SDL_assert( ret == DISPMANX_SUCCESS );
    174    }
    175    
    176    return 0;
    177}
    178
    179/* Free a window manager cursor */
    180static void
    181RPI_FreeCursor(SDL_Cursor * cursor)
    182{
    183    int ret;
    184    DISPMANX_UPDATE_HANDLE_T update;
    185    RPI_CursorData *curdata;
    186    
    187    if (cursor != NULL) {
    188        curdata = (RPI_CursorData *) cursor->driverdata;
    189        
    190        if (curdata != NULL) {
    191            if (curdata->element != DISPMANX_NO_HANDLE) {
    192                update = vc_dispmanx_update_start( 10 );
    193                SDL_assert( update );
    194                ret = vc_dispmanx_element_remove( update, curdata->element );
    195                SDL_assert( ret == DISPMANX_SUCCESS );
    196                ret = vc_dispmanx_update_submit_sync( update );
    197                SDL_assert( ret == DISPMANX_SUCCESS );
    198            }
    199            
    200            if (curdata->resource != DISPMANX_NO_HANDLE) {
    201                ret = vc_dispmanx_resource_delete( curdata->resource );
    202                SDL_assert( ret == DISPMANX_SUCCESS );
    203            }
    204        
    205            SDL_free(cursor->driverdata);
    206        }
    207        SDL_free(cursor);
    208    }
    209}
    210
    211/* Warp the mouse to (x,y) */
    212static void
    213RPI_WarpMouse(SDL_Window * window, int x, int y)
    214{
    215    RPI_WarpMouseGlobal(x, y);
    216}
    217
    218/* Warp the mouse to (x,y) */
    219static void
    220RPI_WarpMouseGlobal(int x, int y)
    221{
    222    RPI_CursorData *curdata;
    223    DISPMANX_UPDATE_HANDLE_T update;
    224    int ret;
    225    VC_RECT_T dst_rect;
    226    SDL_Mouse *mouse = SDL_GetMouse();
    227    
    228    if (mouse != NULL && mouse->cur_cursor != NULL && mouse->cur_cursor->driverdata != NULL) {
    229        curdata = (RPI_CursorData *) mouse->cur_cursor->driverdata;
    230        if (curdata->element != DISPMANX_NO_HANDLE) {
    231            update = vc_dispmanx_update_start( 10 );
    232            SDL_assert( update );
    233            vc_dispmanx_rect_set( &dst_rect, x, y, curdata->w, curdata->h);
    234            ret = vc_dispmanx_element_change_attributes(
    235                update,
    236                curdata->element,
    237                ELEMENT_CHANGE_DEST_RECT,
    238                0,
    239                0,
    240                &dst_rect,
    241                NULL,
    242                DISPMANX_NO_HANDLE,
    243                DISPMANX_NO_ROTATE);
    244            SDL_assert( ret == DISPMANX_SUCCESS );
    245            /* Submit asynchronously, otherwise the peformance suffers a lot */
    246            ret = vc_dispmanx_update_submit( update, 0, NULL );
    247            SDL_assert( ret == DISPMANX_SUCCESS );
    248        }
    249    }    
    250}
    251
    252void
    253RPI_InitMouse(_THIS)
    254{
    255    /* FIXME: Using UDEV it should be possible to scan all mice 
    256     * but there's no point in doing so as there's no multimice support...yet!
    257     */
    258    SDL_Mouse *mouse = SDL_GetMouse();
    259
    260    mouse->CreateCursor = RPI_CreateCursor;
    261    mouse->ShowCursor = RPI_ShowCursor;
    262    mouse->MoveCursor = RPI_MoveCursor;
    263    mouse->FreeCursor = RPI_FreeCursor;
    264    mouse->WarpMouse = RPI_WarpMouse;
    265    mouse->WarpMouseGlobal = RPI_WarpMouseGlobal;
    266
    267    SDL_SetDefaultCursor(RPI_CreateDefaultCursor());
    268}
    269
    270void
    271RPI_QuitMouse(_THIS)
    272{
    273    
    274}
    275
    276/* This is called when a mouse motion event occurs */
    277static void
    278RPI_MoveCursor(SDL_Cursor * cursor)
    279{
    280    SDL_Mouse *mouse = SDL_GetMouse();
    281    RPI_WarpMouse(mouse->focus, mouse->x, mouse->y);
    282}
    283
    284#endif /* SDL_VIDEO_DRIVER_RPI */
    285
    286/* vi: set ts=4 sw=4 expandtab: */