cscg22-gearboy

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

SDL_shape.c (11041B)


      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#include "SDL.h"
     24#include "SDL_assert.h"
     25#include "SDL_video.h"
     26#include "SDL_sysvideo.h"
     27#include "SDL_pixels.h"
     28#include "SDL_surface.h"
     29#include "SDL_shape.h"
     30#include "SDL_shape_internals.h"
     31
     32SDL_Window*
     33SDL_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags)
     34{
     35    SDL_Window *result = NULL;
     36    result = SDL_CreateWindow(title,-1000,-1000,w,h,(flags | SDL_WINDOW_BORDERLESS) & (~SDL_WINDOW_FULLSCREEN) & (~SDL_WINDOW_RESIZABLE) /* & (~SDL_WINDOW_SHOWN) */);
     37    if(result != NULL) {
     38        result->shaper = SDL_GetVideoDevice()->shape_driver.CreateShaper(result);
     39        if(result->shaper != NULL) {
     40            result->shaper->userx = x;
     41            result->shaper->usery = y;
     42            result->shaper->mode.mode = ShapeModeDefault;
     43            result->shaper->mode.parameters.binarizationCutoff = 1;
     44            result->shaper->hasshape = SDL_FALSE;
     45            return result;
     46        }
     47        else {
     48            SDL_DestroyWindow(result);
     49            return NULL;
     50        }
     51    }
     52    else
     53        return NULL;
     54}
     55
     56SDL_bool
     57SDL_IsShapedWindow(const SDL_Window *window)
     58{
     59    if(window == NULL)
     60        return SDL_FALSE;
     61    else
     62        return (SDL_bool)(window->shaper != NULL);
     63}
     64
     65/* REQUIRES that bitmap point to a w-by-h bitmap with ppb pixels-per-byte. */
     66void
     67SDL_CalculateShapeBitmap(SDL_WindowShapeMode mode,SDL_Surface *shape,Uint8* bitmap,Uint8 ppb)
     68{
     69    int x = 0;
     70    int y = 0;
     71    Uint8 r = 0,g = 0,b = 0,alpha = 0;
     72    Uint8* pixel = NULL;
     73    Uint32 bitmap_pixel,pixel_value = 0,mask_value = 0;
     74    SDL_Color key;
     75    if(SDL_MUSTLOCK(shape))
     76        SDL_LockSurface(shape);
     77    for(y = 0;y<shape->h;y++) {
     78        for(x=0;x<shape->w;x++) {
     79            alpha = 0;
     80            pixel_value = 0;
     81            pixel = (Uint8 *)(shape->pixels) + (y*shape->pitch) + (x*shape->format->BytesPerPixel);
     82            switch(shape->format->BytesPerPixel) {
     83                case(1):
     84                    pixel_value = *(Uint8*)pixel;
     85                    break;
     86                case(2):
     87                    pixel_value = *(Uint16*)pixel;
     88                    break;
     89                case(3):
     90                    pixel_value = *(Uint32*)pixel & (~shape->format->Amask);
     91                    break;
     92                case(4):
     93                    pixel_value = *(Uint32*)pixel;
     94                    break;
     95            }
     96            SDL_GetRGBA(pixel_value,shape->format,&r,&g,&b,&alpha);
     97            bitmap_pixel = y*shape->w + x;
     98            switch(mode.mode) {
     99                case(ShapeModeDefault):
    100                    mask_value = (alpha >= 1 ? 1 : 0);
    101                    break;
    102                case(ShapeModeBinarizeAlpha):
    103                    mask_value = (alpha >= mode.parameters.binarizationCutoff ? 1 : 0);
    104                    break;
    105                case(ShapeModeReverseBinarizeAlpha):
    106                    mask_value = (alpha <= mode.parameters.binarizationCutoff ? 1 : 0);
    107                    break;
    108                case(ShapeModeColorKey):
    109                    key = mode.parameters.colorKey;
    110                    mask_value = ((key.r != r || key.g != g || key.b != b) ? 1 : 0);
    111                    break;
    112            }
    113            bitmap[bitmap_pixel / ppb] |= mask_value << (7 - ((ppb - 1) - (bitmap_pixel % ppb)));
    114        }
    115    }
    116    if(SDL_MUSTLOCK(shape))
    117        SDL_UnlockSurface(shape);
    118}
    119
    120static SDL_ShapeTree*
    121RecursivelyCalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* mask,SDL_Rect dimensions) {
    122    int x = 0,y = 0;
    123    Uint8* pixel = NULL;
    124    Uint32 pixel_value = 0;
    125    Uint8 r = 0,g = 0,b = 0,a = 0;
    126    SDL_bool pixel_opaque = SDL_FALSE;
    127    int last_opaque = -1;
    128    SDL_Color key;
    129    SDL_ShapeTree* result = (SDL_ShapeTree*)SDL_malloc(sizeof(SDL_ShapeTree));
    130    SDL_Rect next = {0,0,0,0};
    131
    132    for(y=dimensions.y;y<dimensions.y + dimensions.h;y++) {
    133        for(x=dimensions.x;x<dimensions.x + dimensions.w;x++) {
    134            pixel_value = 0;
    135            pixel = (Uint8 *)(mask->pixels) + (y*mask->pitch) + (x*mask->format->BytesPerPixel);
    136            switch(mask->format->BytesPerPixel) {
    137                case(1):
    138                    pixel_value = *(Uint8*)pixel;
    139                    break;
    140                case(2):
    141                    pixel_value = *(Uint16*)pixel;
    142                    break;
    143                case(3):
    144                    pixel_value = *(Uint32*)pixel & (~mask->format->Amask);
    145                    break;
    146                case(4):
    147                    pixel_value = *(Uint32*)pixel;
    148                    break;
    149            }
    150            SDL_GetRGBA(pixel_value,mask->format,&r,&g,&b,&a);
    151            switch(mode.mode) {
    152                case(ShapeModeDefault):
    153                    pixel_opaque = (a >= 1 ? SDL_TRUE : SDL_FALSE);
    154                    break;
    155                case(ShapeModeBinarizeAlpha):
    156                    pixel_opaque = (a >= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
    157                    break;
    158                case(ShapeModeReverseBinarizeAlpha):
    159                    pixel_opaque = (a <= mode.parameters.binarizationCutoff ? SDL_TRUE : SDL_FALSE);
    160                    break;
    161                case(ShapeModeColorKey):
    162                    key = mode.parameters.colorKey;
    163                    pixel_opaque = ((key.r != r || key.g != g || key.b != b) ? SDL_TRUE : SDL_FALSE);
    164                    break;
    165            }
    166            if(last_opaque == -1)
    167                last_opaque = pixel_opaque;
    168            if(last_opaque != pixel_opaque) {
    169                const int halfwidth = dimensions.w / 2;
    170                const int halfheight = dimensions.h / 2;
    171
    172                result->kind = QuadShape;
    173
    174                next.x = dimensions.x;
    175                next.y = dimensions.y;
    176                next.w = halfwidth;
    177                next.h = halfheight;
    178                result->data.children.upleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
    179
    180                next.x = dimensions.x + halfwidth;
    181                next.w = dimensions.w - halfwidth;
    182                result->data.children.upright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
    183
    184                next.x = dimensions.x;
    185                next.w = halfwidth;
    186                next.y = dimensions.y + halfheight;
    187                next.h = dimensions.h - halfheight;
    188                result->data.children.downleft = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
    189
    190                next.x = dimensions.x + halfwidth;
    191                next.w = dimensions.w - halfwidth;
    192                result->data.children.downright = (struct SDL_ShapeTree *)RecursivelyCalculateShapeTree(mode,mask,next);
    193
    194                return result;
    195            }
    196        }
    197    }
    198
    199
    200    /* If we never recursed, all the pixels in this quadrant have the same "value". */
    201    result->kind = (last_opaque == SDL_TRUE ? OpaqueShape : TransparentShape);
    202    result->data.shape = dimensions;
    203    return result;
    204}
    205
    206SDL_ShapeTree*
    207SDL_CalculateShapeTree(SDL_WindowShapeMode mode,SDL_Surface* shape)
    208{
    209    SDL_Rect dimensions = {0,0,shape->w,shape->h};
    210    SDL_ShapeTree* result = NULL;
    211    if(SDL_MUSTLOCK(shape))
    212        SDL_LockSurface(shape);
    213    result = RecursivelyCalculateShapeTree(mode,shape,dimensions);
    214    if(SDL_MUSTLOCK(shape))
    215        SDL_UnlockSurface(shape);
    216    return result;
    217}
    218
    219void
    220SDL_TraverseShapeTree(SDL_ShapeTree *tree,SDL_TraversalFunction function,void* closure)
    221{
    222    SDL_assert(tree != NULL);
    223    if(tree->kind == QuadShape) {
    224        SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upleft,function,closure);
    225        SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.upright,function,closure);
    226        SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downleft,function,closure);
    227        SDL_TraverseShapeTree((SDL_ShapeTree *)tree->data.children.downright,function,closure);
    228    }
    229    else
    230        function(tree,closure);
    231}
    232
    233void
    234SDL_FreeShapeTree(SDL_ShapeTree** shape_tree)
    235{
    236    if((*shape_tree)->kind == QuadShape) {
    237        SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.upleft);
    238        SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.upright);
    239        SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.downleft);
    240        SDL_FreeShapeTree((SDL_ShapeTree **)&(*shape_tree)->data.children.downright);
    241    }
    242    SDL_free(*shape_tree);
    243    *shape_tree = NULL;
    244}
    245
    246int
    247SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode)
    248{
    249    int result;
    250    if(window == NULL || !SDL_IsShapedWindow(window))
    251        /* The window given was not a shapeable window. */
    252        return SDL_NONSHAPEABLE_WINDOW;
    253    if(shape == NULL)
    254        /* Invalid shape argument. */
    255        return SDL_INVALID_SHAPE_ARGUMENT;
    256
    257    if(shape_mode != NULL)
    258        window->shaper->mode = *shape_mode;
    259    result = SDL_GetVideoDevice()->shape_driver.SetWindowShape(window->shaper,shape,shape_mode);
    260    window->shaper->hasshape = SDL_TRUE;
    261    if(window->shaper->userx != 0 && window->shaper->usery != 0) {
    262        SDL_SetWindowPosition(window,window->shaper->userx,window->shaper->usery);
    263        window->shaper->userx = 0;
    264        window->shaper->usery = 0;
    265    }
    266    return result;
    267}
    268
    269static SDL_bool
    270SDL_WindowHasAShape(SDL_Window *window)
    271{
    272    if (window == NULL || !SDL_IsShapedWindow(window))
    273        return SDL_FALSE;
    274    return window->shaper->hasshape;
    275}
    276
    277int
    278SDL_GetShapedWindowMode(SDL_Window *window,SDL_WindowShapeMode *shape_mode)
    279{
    280    if(window != NULL && SDL_IsShapedWindow(window)) {
    281        if(shape_mode == NULL) {
    282            if(SDL_WindowHasAShape(window))
    283                /* The window given has a shape. */
    284                return 0;
    285            else
    286                /* The window given is shapeable but lacks a shape. */
    287                return SDL_WINDOW_LACKS_SHAPE;
    288        }
    289        else {
    290            *shape_mode = window->shaper->mode;
    291            return 0;
    292        }
    293    }
    294    else
    295        /* The window given is not a valid shapeable window. */
    296        return SDL_NONSHAPEABLE_WINDOW;
    297}