Add a QuestShock startup splash; rename the app and data folder
build / build (push) Successful in 2m35s
build / build (push) Successful in 2m35s
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
#include "qs_splash.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <android/log.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xr_session.h"
|
||||
|
||||
#define QS_SPLASH_HOLD_MS 2500
|
||||
#define QS_SPLASH_FADE_MS 500
|
||||
#define QS_SPLASH_TOTAL_MS (QS_SPLASH_HOLD_MS + 2 * QS_SPLASH_FADE_MS)
|
||||
// The XR session only starts once frames are polled, so the display time is
|
||||
// counted from the first submitted frame; this bounds the wait for it.
|
||||
#define QS_SPLASH_SESSION_TIMEOUT_MS 5000
|
||||
|
||||
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, "QuestShock", __VA_ARGS__)
|
||||
|
||||
extern void pump_events(void);
|
||||
// OpenGL.cc (engine patch 11): draws a software frame into the XR game swapchain.
|
||||
extern void android_composite_software_frame(SDL_Surface *ui);
|
||||
|
||||
static SDL_Surface *s_image = NULL;
|
||||
|
||||
void qs_splash_set_image(const uint32_t *argb, int width, int height) {
|
||||
if (s_image != NULL) {
|
||||
SDL_FreeSurface(s_image);
|
||||
s_image = NULL;
|
||||
}
|
||||
if (argb == NULL || width <= 0 || height <= 0)
|
||||
return;
|
||||
s_image = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_ARGB8888);
|
||||
if (s_image == NULL)
|
||||
return;
|
||||
for (int y = 0; y < height; y++)
|
||||
memcpy((uint8_t *)s_image->pixels + (size_t)y * s_image->pitch, argb + (size_t)y * width,
|
||||
(size_t)width * sizeof(uint32_t));
|
||||
SDL_SetSurfaceBlendMode(s_image, SDL_BLENDMODE_BLEND);
|
||||
}
|
||||
|
||||
// 0-255 brightness at `elapsed` ms after the first frame.
|
||||
static int qs_splash_level(uint32_t elapsed) {
|
||||
uint32_t edge = elapsed < QS_SPLASH_TOTAL_MS - elapsed ? elapsed : QS_SPLASH_TOTAL_MS - elapsed;
|
||||
if (edge >= QS_SPLASH_FADE_MS)
|
||||
return 255;
|
||||
return (int)(255 * edge / QS_SPLASH_FADE_MS);
|
||||
}
|
||||
|
||||
void qs_splash_show(void) {
|
||||
if (s_image == NULL) {
|
||||
LOGI("Startup splash: no image");
|
||||
return;
|
||||
}
|
||||
int width, height;
|
||||
xr_get_game_swapchain_size(&width, &height);
|
||||
if (width <= 0 || height <= 0) {
|
||||
LOGI("Startup splash: no XR game swapchain");
|
||||
return;
|
||||
}
|
||||
|
||||
// The image is stretched over the whole swapchain image, so it is
|
||||
// letterboxed into a canvas of that size to keep its aspect ratio.
|
||||
SDL_Surface *canvas =
|
||||
SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_RGBA32);
|
||||
if (canvas == NULL)
|
||||
return;
|
||||
const float scale = SDL_min((float)width / s_image->w, (float)height / s_image->h);
|
||||
SDL_Rect dst;
|
||||
dst.w = (int)(s_image->w * scale);
|
||||
dst.h = (int)(s_image->h * scale);
|
||||
dst.x = (width - dst.w) / 2;
|
||||
dst.y = (height - dst.h) / 2;
|
||||
|
||||
const uint32_t waitStart = SDL_GetTicks();
|
||||
uint32_t shownStart = 0;
|
||||
uint32_t elapsed = 0;
|
||||
int drawnLevel = -1;
|
||||
bool done = false;
|
||||
|
||||
while (!done) {
|
||||
pump_events();
|
||||
xr_poll_events();
|
||||
if (xr_frame_begin()) {
|
||||
if (shownStart == 0)
|
||||
shownStart = SDL_GetTicks();
|
||||
elapsed = SDL_GetTicks() - shownStart;
|
||||
if (elapsed >= QS_SPLASH_TOTAL_MS) {
|
||||
elapsed = QS_SPLASH_TOTAL_MS;
|
||||
done = true;
|
||||
}
|
||||
const int level = qs_splash_level(elapsed);
|
||||
if (level != drawnLevel) {
|
||||
drawnLevel = level;
|
||||
SDL_FillRect(canvas, NULL, SDL_MapRGB(canvas->format, 0, 0, 0));
|
||||
SDL_SetSurfaceColorMod(s_image, level, level, level);
|
||||
SDL_BlitScaled(s_image, NULL, canvas, &dst);
|
||||
}
|
||||
android_composite_software_frame(canvas);
|
||||
} else {
|
||||
SDL_Delay(10);
|
||||
if (shownStart == 0 && SDL_GetTicks() - waitStart > QS_SPLASH_SESSION_TIMEOUT_MS)
|
||||
done = true;
|
||||
}
|
||||
xr_frame_end();
|
||||
}
|
||||
|
||||
LOGI("Startup splash: %s after %u ms", shownStart != 0 ? "shown" : "XR session did not start",
|
||||
(unsigned)(SDL_GetTicks() - waitStart));
|
||||
SDL_FreeSurface(canvas);
|
||||
}
|
||||
Reference in New Issue
Block a user