mirror of
				https://github.com/libsdl-org/SDL.git
				synced 2025-11-04 09:44:35 +00:00 
			
		
		
		
	This allows functions like SDL_ConvertEventToRenderCoordinates() to work without having to copy the event. Fixes https://github.com/libsdl-org/SDL/issues/10691
		
			
				
	
	
		
			291 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
  Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
 | 
						|
 | 
						|
  This software is provided 'as-is', without any express or implied
 | 
						|
  warranty.  In no event will the authors be held liable for any damages
 | 
						|
  arising from the use of this software.
 | 
						|
 | 
						|
  Permission is granted to anyone to use this software for any purpose,
 | 
						|
  including commercial applications, and to alter it and redistribute it
 | 
						|
  freely.
 | 
						|
*/
 | 
						|
 | 
						|
#define SDL_MAIN_USE_CALLBACKS 1
 | 
						|
#include <SDL3/SDL_main.h>
 | 
						|
#include <SDL3/SDL_test.h>
 | 
						|
#include <SDL3/SDL_test_common.h>
 | 
						|
 | 
						|
typedef struct Pen
 | 
						|
{
 | 
						|
    SDL_PenID pen;
 | 
						|
    Uint8 r, g, b;
 | 
						|
    float axes[SDL_PEN_NUM_AXES];
 | 
						|
    float x;
 | 
						|
    float y;
 | 
						|
    Uint32 buttons;
 | 
						|
    SDL_bool eraser;
 | 
						|
    SDL_bool touching;
 | 
						|
    struct Pen *next;
 | 
						|
} Pen;
 | 
						|
 | 
						|
static SDL_Renderer *renderer = NULL;
 | 
						|
static SDLTest_CommonState *state = NULL;
 | 
						|
static SDL_Texture *white_pixel = NULL;
 | 
						|
static Pen pens;
 | 
						|
 | 
						|
 | 
						|
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    SDL_srand(0);
 | 
						|
 | 
						|
    /* Initialize test framework */
 | 
						|
    state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
 | 
						|
    if (!state) {
 | 
						|
        return SDL_APP_FAILURE;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Enable standard application logging */
 | 
						|
    SDL_SetLogPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
 | 
						|
 | 
						|
    /* Parse commandline */
 | 
						|
    for (i = 1; i < argc;) {
 | 
						|
        int consumed = SDLTest_CommonArg(state, i);
 | 
						|
        if (consumed <= 0) {
 | 
						|
            static const char *options[] = {
 | 
						|
                NULL,
 | 
						|
            };
 | 
						|
            SDLTest_CommonLogUsage(state, argv[0], options);
 | 
						|
            SDL_Quit();
 | 
						|
            SDLTest_CommonDestroyState(state);
 | 
						|
            return 1;
 | 
						|
        }
 | 
						|
        i += consumed;
 | 
						|
    }
 | 
						|
 | 
						|
    state->num_windows = 1;
 | 
						|
 | 
						|
    /* Load the SDL library */
 | 
						|
    if (!SDLTest_CommonInit(state)) {
 | 
						|
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
 | 
						|
        return SDL_APP_FAILURE;
 | 
						|
    }
 | 
						|
 | 
						|
    SDL_SetLogPriorities(SDL_LOG_PRIORITY_VERBOSE);
 | 
						|
 | 
						|
    renderer = state->renderers[0];
 | 
						|
    if (!renderer) {
 | 
						|
        /* SDL_Log("Couldn't create renderer: %s", SDL_GetError()); */
 | 
						|
        return SDL_APP_FAILURE;
 | 
						|
    }
 | 
						|
 | 
						|
    white_pixel = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, 16, 16);
 | 
						|
    if (!white_pixel) {
 | 
						|
        SDL_Log("Couldn't create white_pixel texture: %s", SDL_GetError());
 | 
						|
        return SDL_APP_FAILURE;
 | 
						|
    } else {
 | 
						|
        const SDL_Rect rect = { 0, 0, 16, 16 };
 | 
						|
        Uint32 pixels[16 * 16];
 | 
						|
        SDL_memset(pixels, 0xFF, sizeof (pixels));
 | 
						|
        SDL_UpdateTexture(white_pixel, &rect, pixels, 16 * sizeof (Uint32));
 | 
						|
    }
 | 
						|
 | 
						|
    SDL_HideCursor();
 | 
						|
 | 
						|
    return SDL_APP_CONTINUE;
 | 
						|
}
 | 
						|
 | 
						|
static Pen *FindPen(SDL_PenID which)
 | 
						|
{
 | 
						|
    Pen *i;
 | 
						|
    for (i = pens.next; i != NULL; i = i->next) {
 | 
						|
        if (i->pen == which) {
 | 
						|
            return i;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
 | 
						|
{
 | 
						|
    Pen *pen = NULL;
 | 
						|
 | 
						|
    switch (event->type) {
 | 
						|
        case SDL_EVENT_PEN_PROXIMITY_IN: {
 | 
						|
            pen = (Pen *) SDL_calloc(1, sizeof (*pen));
 | 
						|
            if (!pen) {
 | 
						|
                SDL_Log("Out of memory!");
 | 
						|
                return SDL_APP_FAILURE;
 | 
						|
            }
 | 
						|
 | 
						|
            SDL_Log("Pen %" SDL_PRIu32 " enters proximity!", event->pproximity.which);
 | 
						|
            pen->pen = event->pproximity.which;
 | 
						|
            pen->r = (Uint8) SDL_rand(256);
 | 
						|
            pen->g = (Uint8) SDL_rand(256);
 | 
						|
            pen->b = (Uint8) SDL_rand(256);
 | 
						|
            pen->x = 320.0f;
 | 
						|
            pen->y = 240.0f;
 | 
						|
            pen->next = pens.next;
 | 
						|
            pens.next = pen;
 | 
						|
 | 
						|
            return SDL_APP_CONTINUE;
 | 
						|
        }
 | 
						|
 | 
						|
        case SDL_EVENT_PEN_PROXIMITY_OUT: {
 | 
						|
            Pen *prev = &pens;
 | 
						|
            Pen *i;
 | 
						|
 | 
						|
            SDL_Log("Pen %" SDL_PRIu32 " leaves proximity!", event->pproximity.which);
 | 
						|
            for (i = pens.next; i != NULL; i = i->next) {
 | 
						|
                if (i->pen == event->pproximity.which) {
 | 
						|
                    prev->next = i->next;
 | 
						|
                    SDL_free(i);
 | 
						|
                    break;
 | 
						|
                }
 | 
						|
                prev = i;
 | 
						|
            }
 | 
						|
 | 
						|
            return SDL_APP_CONTINUE;
 | 
						|
        }
 | 
						|
 | 
						|
        case SDL_EVENT_PEN_DOWN:
 | 
						|
            /*SDL_Log("Pen %" SDL_PRIu32 " down!", event->ptouch.which);*/
 | 
						|
            pen = FindPen(event->ptouch.which);
 | 
						|
            if (pen) {
 | 
						|
                pen->touching = SDL_TRUE;
 | 
						|
                pen->eraser = (event->ptouch.eraser != 0);
 | 
						|
            }
 | 
						|
            return SDL_APP_CONTINUE;
 | 
						|
 | 
						|
        case SDL_EVENT_PEN_UP:
 | 
						|
            /*SDL_Log("Pen %" SDL_PRIu32 " up!", event->ptouch.which);*/
 | 
						|
            pen = FindPen(event->ptouch.which);
 | 
						|
            if (pen) {
 | 
						|
                pen->touching = SDL_FALSE;
 | 
						|
                pen->axes[SDL_PEN_AXIS_PRESSURE] = 0.0f;
 | 
						|
            }
 | 
						|
            return SDL_APP_CONTINUE;
 | 
						|
 | 
						|
        case SDL_EVENT_PEN_BUTTON_DOWN:
 | 
						|
            /*SDL_Log("Pen %" SDL_PRIu32 " button %d down!", event->pbutton.which, (int) event->pbutton.button);*/
 | 
						|
            pen = FindPen(event->ptouch.which);
 | 
						|
            if (pen) {
 | 
						|
                pen->buttons |= (1 << (event->pbutton.button-1));
 | 
						|
            }
 | 
						|
            return SDL_APP_CONTINUE;
 | 
						|
 | 
						|
        case SDL_EVENT_PEN_BUTTON_UP:
 | 
						|
            /*SDL_Log("Pen %" SDL_PRIu32 " button %d up!", event->pbutton.which, (int) event->pbutton.button);*/
 | 
						|
            pen = FindPen(event->ptouch.which);
 | 
						|
            if (pen) {
 | 
						|
                pen->buttons &= ~(1 << (event->pbutton.button-1));
 | 
						|
            }
 | 
						|
            return SDL_APP_CONTINUE;
 | 
						|
 | 
						|
        case SDL_EVENT_PEN_MOTION:
 | 
						|
            /*SDL_Log("Pen %" SDL_PRIu32 " moved to (%f,%f)!", event->pmotion.which, event->pmotion.x, event->pmotion.y);*/
 | 
						|
            pen = FindPen(event->ptouch.which);
 | 
						|
            if (pen) {
 | 
						|
                pen->x = event->pmotion.x;
 | 
						|
                pen->y = event->pmotion.y;
 | 
						|
            }
 | 
						|
            return SDL_APP_CONTINUE;
 | 
						|
 | 
						|
        case SDL_EVENT_PEN_AXIS:
 | 
						|
            /*SDL_Log("Pen %" SDL_PRIu32 " axis %d is now %f!", event->paxis.which, (int) event->paxis.axis, event->paxis.value);*/
 | 
						|
            pen = FindPen(event->ptouch.which);
 | 
						|
            if (pen && (event->paxis.axis < SDL_arraysize(pen->axes))) {
 | 
						|
                pen->axes[event->paxis.axis] = event->paxis.value;
 | 
						|
            }
 | 
						|
            return SDL_APP_CONTINUE;
 | 
						|
 | 
						|
        case SDL_EVENT_KEY_DOWN: {
 | 
						|
            const SDL_Keycode sym = event->key.key;
 | 
						|
            if (sym == SDLK_ESCAPE || sym == SDLK_AC_BACK) {
 | 
						|
                SDL_Log("Key : Escape!");
 | 
						|
                return SDL_APP_SUCCESS;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        case SDL_EVENT_QUIT:
 | 
						|
            return SDL_APP_SUCCESS;
 | 
						|
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    return SDLTest_CommonEventMainCallbacks(state, event);
 | 
						|
}
 | 
						|
 | 
						|
static void DrawOnePen(Pen *pen, int num)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    /* draw button presses for this pen. A square for each in the pen's color, offset down the screen so they don't overlap. */
 | 
						|
    SDL_SetRenderDrawColor(renderer, pen->r, pen->g, pen->b, 255);
 | 
						|
    for (i = 0; i < 8; i++) {   /* we assume you don't have more than 8 buttons atm... */
 | 
						|
        if (pen->buttons & (1 << i)) {
 | 
						|
            const SDL_FRect rect = { 30.0f * ((float) i), ((float) num) * 30.0f, 30.0f, 30.0f };
 | 
						|
            SDL_RenderFillRect(renderer, &rect);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* draw a square to represent pressure. Always green for eraser and blue for pen */
 | 
						|
    /* we do this with a texture, so we can trivially rotate it, which SDL_RenderFillRect doesn't offer. */
 | 
						|
    if (pen->axes[SDL_PEN_AXIS_PRESSURE] > 0.0f) {
 | 
						|
        const float size = (150.0f * pen->axes[SDL_PEN_AXIS_PRESSURE]) + 20.0f;
 | 
						|
        const float halfsize = size / 2.0f;
 | 
						|
        const SDL_FRect rect = { pen->x - halfsize, pen->y - halfsize, size, size };
 | 
						|
        const SDL_FPoint center = { halfsize, halfsize };
 | 
						|
        if (pen->eraser) {
 | 
						|
            SDL_SetTextureColorMod(white_pixel, 0, 255, 0);
 | 
						|
        } else {
 | 
						|
            SDL_SetTextureColorMod(white_pixel, 0, 0, 255);
 | 
						|
        }
 | 
						|
        SDL_RenderTextureRotated(renderer, white_pixel, NULL, &rect, pen->axes[SDL_PEN_AXIS_ROTATION], ¢er, SDL_FLIP_NONE);
 | 
						|
    }
 | 
						|
 | 
						|
    /* draw a little square for position in the center of the pressure, with the pen-specific color. */
 | 
						|
    {
 | 
						|
        const float distance = pen->touching ? 0.0f : SDL_clamp(pen->axes[SDL_PEN_AXIS_DISTANCE], 0.0f, 1.0f);
 | 
						|
        const float size = 10 + (30.0f * (1.0f - distance));
 | 
						|
        const float halfsize = size / 2.0f;
 | 
						|
        const SDL_FRect rect = { pen->x - halfsize, pen->y - halfsize, size, size };
 | 
						|
        const SDL_FPoint center = { halfsize, halfsize };
 | 
						|
        SDL_SetTextureColorMod(white_pixel, pen->r, pen->g, pen->b);
 | 
						|
        SDL_RenderTextureRotated(renderer, white_pixel, NULL, &rect, pen->axes[SDL_PEN_AXIS_ROTATION], ¢er, SDL_FLIP_NONE);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
SDL_AppResult SDL_AppIterate(void *appstate)
 | 
						|
{
 | 
						|
    int num = 0;
 | 
						|
    Pen *pen;
 | 
						|
 | 
						|
    SDL_SetRenderDrawColor(renderer, 0x99, 0x99, 0x99, 255);
 | 
						|
    SDL_RenderClear(renderer);
 | 
						|
 | 
						|
    for (pen = pens.next; pen != NULL; pen = pen->next, num++) {
 | 
						|
        DrawOnePen(pen, num);
 | 
						|
    }
 | 
						|
 | 
						|
    SDL_RenderPresent(renderer);
 | 
						|
 | 
						|
    return SDL_APP_CONTINUE;
 | 
						|
}
 | 
						|
 | 
						|
void SDL_AppQuit(void *appstate)
 | 
						|
{
 | 
						|
    Pen *i, *next;
 | 
						|
    for (i = pens.next; i != NULL; i = next) {
 | 
						|
        next = i->next;
 | 
						|
        SDL_free(i);
 | 
						|
    }
 | 
						|
    pens.next = NULL;
 | 
						|
    SDL_DestroyTexture(white_pixel);
 | 
						|
    SDLTest_CommonQuit(state);
 | 
						|
}
 | 
						|
 |