z_mirror/sdl-osu

git clone https://git.raiguard.me/z_mirror/sdl-osu

Caleb HeuerSwitch to four-space indents and inline braces836a89c

trunk
6.7 KiB167 linesraw
1#include "beatmapselector.h"
2#include "beatmap.h"
3#include "beatmapstore.h"
4#include "game.h"
5#include "graphics.h"
6#include "util.h"
7#include <SDL3/SDL.h>
8#include <SDL3_ttf/SDL_ttf.h>
9#include <stdio.h>
10#include <stdlib.h>
11
12int Osu_SortBeatmapsByTitle(const void* userdata1, const void* userdata2) {
13    const struct Osu_Beatmap* beatmap1 = *(struct Osu_Beatmap**)userdata1;
14    const struct Osu_Beatmap* beatmap2 = *(struct Osu_Beatmap**)userdata2;
15
16    SDL_assert(beatmap1->title);
17    SDL_assert(beatmap2->title);
18
19    return strcmp(beatmap1->title, beatmap2->title);
20}
21
22struct Osu_BeatmapSelector* Osu_CreateBeatmapSelector(struct Osu_Game* game, struct Osu_BeatmapStore* beatmapStore) {
23    struct Osu_BeatmapSelector* selector = calloc(1, sizeof(struct Osu_BeatmapSelector));
24    selector->beatmaps = calloc(beatmapStore->beatmapsLen, sizeof(struct Osu_BeatmapStore));
25    selector->beatmapsLen = beatmapStore->beatmapsLen;
26    memcpy(selector->beatmaps, beatmapStore->beatmaps, sizeof(struct Osu_Beatmap*) * selector->beatmapsLen);
27    qsort(selector->beatmaps, selector->beatmapsLen, sizeof(struct Osu_Beatmap*), Osu_SortBeatmapsByTitle);
28
29    selector->beatmapTexts = calloc(selector->beatmapsLen, sizeof(struct SDL_Text*));
30    for (size_t i = 0; i < selector->beatmapsLen; i++) {
31        struct Osu_Beatmap* beatmap = selector->beatmaps[i];
32        char label[512];
33        snprintf(label, 512, "%s (%s)", beatmap->title, beatmap->version);
34        selector->beatmapTexts[i] = TTF_CreateText(game->graphics->textEngine, game->graphics->font, label, 0);
35    }
36
37    SDL_SAFECALL(SDL_StartTextInput, game->graphics->window);
38
39    return selector;
40}
41
42void Osu_DestroyBeatmapSelector(struct Osu_Game* game, struct Osu_BeatmapSelector* selector) {
43    if (selector->beatmapTexts) {
44        for (size_t i = 0; i < selector->beatmapsLen; i++) {
45            TTF_DestroyText(selector->beatmapTexts[i]);
46        }
47        free(selector->beatmapTexts);
48        selector->beatmapTexts = NULL;
49    }
50
51    SDL_SAFECALL(SDL_StopTextInput, game->graphics->window);
52
53    free(selector->beatmaps); // Does not own the contained pointers.
54    free(selector);
55}
56
57void Osu_HandleBeatmapSelectorEvent(struct Osu_Game* game, struct Osu_BeatmapSelector* selector, union SDL_Event* event) {
58    if (event->type == SDL_EVENT_MOUSE_WHEEL) {
59        selector->beatmapYOffset += event->wheel.y * 100;
60        if (selector->beatmapYOffset > 0) {
61            selector->beatmapYOffset = 0;
62        }
63    }
64
65    if (event->type == SDL_EVENT_KEY_UP && event->key.key == SDLK_F2) {
66        Osu_SetSelectedBeatmap(game, game->beatmaps->beatmaps[Osu_Random(0, game->beatmaps->beatmapsLen - 1)]);
67    }
68
69    if (event->type == SDL_EVENT_TEXT_INPUT) {
70        SDL_strlcat(selector->searchText, event->text.text, sizeof(selector->searchText));
71    } else if (event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_BACKSPACE) {
72        size_t len = SDL_strlen(selector->searchText);
73        if (len > 0) {
74            const char* cursor = selector->searchText + len;
75            SDL_StepBackUTF8(selector->searchText, &cursor);
76            selector->searchText[cursor - selector->searchText] = 0;
77        }
78    } else if (event->type == SDL_EVENT_KEY_UP && event->key.key == SDLK_RETURN) {
79        Osu_EnterBeatmap(game, selector->selectedBeatmap);
80    }
81    // TODO: This is all very messy and hardcoded, bad!
82    if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
83        int screenW, screenH;
84        SDL_GetWindowSizeInPixels(game->graphics->window, &screenW, &screenH);
85        float backgroundW, backgroundH;
86        SDL_GetTextureSize(game->graphics->beatmapWedgeTexture, &backgroundW, &backgroundH);
87        SDL_FRect backgroundRect = {
88            .x = screenW - ((backgroundW / 5) * 4),
89            .y = 0,
90            .w = backgroundW,
91            .h = backgroundH,
92        };
93        SDL_FPoint mousePoint = {
94            .x = event->button.x * SDL_GetWindowDisplayScale(game->graphics->window),
95            .y = event->button.y * SDL_GetWindowDisplayScale(game->graphics->window),
96        };
97        size_t drawnIndex = 0;
98        for (size_t i = 0; i < selector->beatmapsLen; i++) {
99            if (strlen(selector->searchText) > 0 && !SDL_strstr(selector->beatmaps[i]->title, selector->searchText)) {
100                continue;
101            }
102            drawnIndex++;
103            int y = selector->beatmapYOffset + drawnIndex * (backgroundH * 0.8);
104            if (y + backgroundH < 0) {
105                continue;
106            }
107            if (y > screenH) {
108                break;
109            }
110            backgroundRect.y = y;
111            if (SDL_PointInRectFloat(&mousePoint, &backgroundRect)) {
112                Osu_SetSelectedBeatmap(game, selector->beatmaps[i]);
113                break;
114            }
115        }
116    }
117}
118
119void Osu_RenderBeatmapSelector(struct Osu_BeatmapSelector* selector, struct Osu_Graphics* graphics) {
120    float wedgeW, wedgeH;
121    SDL_GetTextureSize(graphics->beatmapWedgeTexture, &wedgeW, &wedgeH);
122    struct SDL_FRect backgroundRect = {
123        .x = graphics->screenRect.w - ((wedgeW / 5) * 4),
124        .y = 0,
125        .w = wedgeW,
126        .h = wedgeH,
127    };
128
129    struct SDL_FPoint mousePoint;
130    SDL_GetMouseState(&mousePoint.x, &mousePoint.y);
131    mousePoint.x *= SDL_GetWindowDisplayScale(graphics->window);
132    mousePoint.y *= SDL_GetWindowDisplayScale(graphics->window);
133
134    size_t drawnIndex = 0;
135    for (size_t i = 0; i < selector->beatmapsLen; i++) {
136        if (strlen(selector->searchText) > 0 && !SDL_strstr(selector->beatmaps[i]->title, selector->searchText)) {
137            continue;
138        }
139        drawnIndex++;
140        int y = selector->beatmapYOffset + drawnIndex * (wedgeH * 0.8);
141        if (y + wedgeH < 0) {
142            continue;
143        }
144        if (y > graphics->screenRect.h) {
145            break;
146        }
147        backgroundRect.y = y;
148        if (selector->selectedBeatmap == selector->beatmaps[i]) {
149            SDL_SetTextureColorMod(graphics->beatmapWedgeTexture, 200, 200, 200);
150        } else if (SDL_PointInRectFloat(&mousePoint, &backgroundRect)) {
151            SDL_SetTextureColorMod(graphics->beatmapWedgeTexture, 255, 150, 245);
152        } else {
153            SDL_SetTextureColorMod(graphics->beatmapWedgeTexture, 255, 110, 245);
154        }
155        SDL_RenderTexture(graphics->renderer, graphics->beatmapWedgeTexture, NULL, &backgroundRect);
156        TTF_DrawRendererText(selector->beatmapTexts[i], backgroundRect.x + 255, y + 30);
157    }
158
159    struct SDL_FRect topTexRect = Osu_GetTextureRect(graphics->songSelectTopTexture);
160    struct SDL_FRect destRect = {
161        .x = 0,
162        .y = 0,
163        .w = topTexRect.w * 2,
164        .h = topTexRect.h * 2,
165    };
166    SDL_RenderTexture(graphics->renderer, graphics->songSelectTopTexture, &topTexRect, &destRect);
167}