2012-08-05 03:36:55 +02:00
|
|
|
/*
|
|
|
|
* This software is licensed under the terms of the MIT-License
|
2017-02-11 04:52:08 +01:00
|
|
|
* See COPYING for further information.
|
2012-08-05 03:36:55 +02:00
|
|
|
* ---
|
2019-01-23 21:10:43 +01:00
|
|
|
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
|
|
|
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@alienslab.net>.
|
2012-08-05 03:36:55 +02:00
|
|
|
*/
|
|
|
|
|
2017-11-25 20:45:11 +01:00
|
|
|
#include "taisei.h"
|
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
#include "credits.h"
|
|
|
|
#include "global.h"
|
2017-11-15 04:45:41 +01:00
|
|
|
#include "stages/stage6.h"
|
2012-08-05 03:36:55 +02:00
|
|
|
#include "video.h"
|
2018-04-12 16:08:48 +02:00
|
|
|
#include "resource/model.h"
|
|
|
|
#include "renderer/api.h"
|
2012-08-05 03:36:55 +02:00
|
|
|
|
|
|
|
typedef struct CreditsEntry {
|
|
|
|
char **data;
|
|
|
|
int lines;
|
|
|
|
int time;
|
|
|
|
} CreditsEntry;
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
CreditsEntry *entries;
|
|
|
|
int ecount;
|
|
|
|
float panelalpha;
|
2012-08-05 23:27:34 +02:00
|
|
|
int end;
|
2019-01-05 22:40:50 +01:00
|
|
|
bool skipable;
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
CallChain cc;
|
2012-08-05 03:36:55 +02:00
|
|
|
} credits;
|
|
|
|
|
2017-12-28 04:49:37 +01:00
|
|
|
#define CREDITS_ENTRY_FADEIN 200.0
|
|
|
|
#define CREDITS_ENTRY_FADEOUT 100.0
|
|
|
|
#define CREDITS_YUKKURI_SCALE 0.5
|
|
|
|
|
|
|
|
#define CREDITS_FADEOUT 240
|
|
|
|
|
|
|
|
#define ENTRY_TIME 350
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_add(char *data, int time);
|
|
|
|
|
|
|
|
static void credits_fill(void) {
|
2017-10-23 12:48:30 +02:00
|
|
|
// In case the shortened URLs break,
|
|
|
|
// Tuck V's YouTube: https://www.youtube.com/channel/UCaw73cuHLnFCSpjOtt_9pyg
|
|
|
|
// Lalasa's YouTube: https://www.youtube.com/channel/UCc6ePuGLYnKTkdDqxP3OB4Q
|
2018-01-21 18:35:26 +01:00
|
|
|
// InsideI's bandcamp: https://vnutriya.bandcamp.com/
|
2017-10-23 12:48:30 +02:00
|
|
|
|
2017-02-18 04:55:04 +01:00
|
|
|
credits_add("Taisei Project\nbrought to you by…", 200);
|
2017-12-28 04:49:37 +01:00
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"laochailan\n"
|
|
|
|
"Lukas Weber\n"
|
|
|
|
"laochailan@web.de\n\n"
|
|
|
|
"Programming, game design,"
|
|
|
|
"\ngraphics"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"Akari\n"
|
|
|
|
"Andrei Alexeyev\n"
|
|
|
|
"akari@alienslab.net\n\n"
|
|
|
|
"Programming, game design"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"Tuck V\n"
|
|
|
|
"Discord: @Tuck#1679\n"
|
|
|
|
"YouTube: https://is.gd/exafez\n\n"
|
|
|
|
"Original soundtrack"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"Lalasa\n"
|
|
|
|
"Ola Kruzel\n"
|
|
|
|
"okruzel@comcast.net\n"
|
|
|
|
"YouTube: https://is.gd/ohihef\n\n"
|
|
|
|
"Writing, playtesting"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"lachs0r\n"
|
|
|
|
"Martin Herkt\n"
|
|
|
|
"lachs0r@hong-mailing.de\n\n"
|
|
|
|
"Hosting, packaging, editing,\n"
|
|
|
|
"spiritual guidance"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"makise-homura\n"
|
|
|
|
"Igor Molchanov\n"
|
|
|
|
"akemi_homura@kurisa.ch\n\n"
|
|
|
|
"Code contributions\n"
|
|
|
|
"Elbrus compatible™"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"aiju\n"
|
|
|
|
"Julius Schmidt\n"
|
|
|
|
"http://aiju.de/\n\n"
|
|
|
|
"I don't remember\n"
|
|
|
|
"what this guy did"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add("Special Thanks", ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"ZUN\n"
|
|
|
|
"for Tōhō Project\n"
|
|
|
|
"http://www16.big.or.jp/~zun/"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
2018-11-02 23:26:12 +01:00
|
|
|
credits_add((
|
|
|
|
"InsideI\n"
|
|
|
|
"Mikhail Novik\n"
|
|
|
|
"Bandcamp: https://is.gd/owojix\n\n"
|
|
|
|
"Various sound effects"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
2017-12-28 04:49:37 +01:00
|
|
|
credits_add((
|
|
|
|
"Free Software\n"
|
|
|
|
"Simple DirectMedia Layer\n"
|
|
|
|
"https://libsdl.org/\n\n"
|
|
|
|
"zlib\n"
|
|
|
|
"https://zlib.net/\n\n"
|
|
|
|
"libpng\n"
|
|
|
|
"http://www.libpng.org/\n\n"
|
|
|
|
"Ogg Vorbis\n"
|
2018-01-09 00:32:52 +01:00
|
|
|
"https://xiph.org/vorbis/"
|
|
|
|
), 350);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"\n"
|
2017-12-28 04:49:37 +01:00
|
|
|
"libzip\n"
|
|
|
|
"https://libzip.org/\n\n"
|
|
|
|
"Meson build system\n"
|
|
|
|
"http://mesonbuild.com/\n\n"
|
|
|
|
"M cross environment\n"
|
|
|
|
"http://mxe.cc/\n\n"
|
|
|
|
"and many other projects"
|
2018-01-09 00:32:52 +01:00
|
|
|
), 350);
|
2017-12-28 04:49:37 +01:00
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"Mochizuki Ado\n"
|
|
|
|
"for a nice yukkuri image"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"…and You!\n"
|
|
|
|
"for playing"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
credits_add((
|
|
|
|
"Visit Us\n"
|
|
|
|
"https://taisei-project.org/\n\n"
|
|
|
|
"And join our IRC channel\n"
|
|
|
|
"#taisei-project at irc.freenode.net\n\n"
|
|
|
|
"Or our Discord server\n"
|
|
|
|
"https://discord.gg/JEHCMzW"
|
|
|
|
), ENTRY_TIME);
|
|
|
|
|
|
|
|
// yukkureimu
|
2018-01-09 00:32:52 +01:00
|
|
|
credits_add("*\nAnd don't forget to take it easy!", 200);
|
2012-08-05 23:27:34 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_add(char *data, int time) {
|
2012-08-05 03:36:55 +02:00
|
|
|
CreditsEntry *e;
|
|
|
|
char *c, buf[256];
|
|
|
|
int l = 0, i = 0;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
credits.entries = realloc(credits.entries, (++credits.ecount) * sizeof(CreditsEntry));
|
|
|
|
e = &(credits.entries[credits.ecount-1]);
|
|
|
|
e->time = time;
|
|
|
|
e->lines = 1;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
for(c = data; *c; ++c)
|
|
|
|
if(*c == '\n') e->lines++;
|
2017-02-15 14:26:37 +01:00
|
|
|
e->data = malloc(e->lines * sizeof(char*));
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
for(c = data; *c; ++c) {
|
|
|
|
if(*c == '\n') {
|
|
|
|
buf[i] = 0;
|
|
|
|
e->data[l] = malloc(strlen(buf) + 1);
|
|
|
|
strcpy(e->data[l], buf);
|
|
|
|
i = 0;
|
|
|
|
++l;
|
|
|
|
} else {
|
|
|
|
buf[i++] = *c;
|
|
|
|
}
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
buf[i] = 0;
|
|
|
|
e->data[l] = malloc(strlen(buf) + 1);
|
|
|
|
strcpy(e->data[l], buf);
|
2012-08-05 23:27:34 +02:00
|
|
|
credits.end += time + CREDITS_ENTRY_FADEOUT;
|
2012-08-05 03:36:55 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_towerwall_draw(vec3 pos) {
|
|
|
|
r_shader("tower_wall");
|
2018-09-14 09:37:20 +02:00
|
|
|
r_uniform_sampler("tex", "stage6/towerwall");
|
2018-04-12 16:08:48 +02:00
|
|
|
r_uniform_float("lendiv", 2800.0 + 300.0 * sin(global.frames / 77.7));
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_push();
|
|
|
|
r_mat_translate(pos[0], pos[1], pos[2]);
|
|
|
|
r_mat_scale(30,30,30);
|
|
|
|
r_draw_model("towerwall");
|
|
|
|
r_mat_pop();
|
2012-08-05 04:39:19 +02:00
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_shader_standard();
|
2012-08-05 03:36:55 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_init(void) {
|
2012-08-05 03:36:55 +02:00
|
|
|
memset(&credits, 0, sizeof(credits));
|
2019-03-11 15:34:48 +01:00
|
|
|
init_stage3d(&stage_3d_context, 16);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-11-14 02:41:08 +01:00
|
|
|
add_model(&stage_3d_context, credits_towerwall_draw, stage6_towerwall_pos);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-11-14 02:41:08 +01:00
|
|
|
stage_3d_context.cx[0] = 0;
|
|
|
|
stage_3d_context.cx[1] = 600;
|
|
|
|
stage_3d_context.crot[0] = 0;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
global.frames = 0;
|
2019-01-05 22:40:50 +01:00
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
credits_fill();
|
2012-08-05 23:27:34 +02:00
|
|
|
credits.end += 500 + CREDITS_ENTRY_FADEOUT;
|
2019-01-05 22:40:50 +01:00
|
|
|
credits.skipable = progress_times_any_good_ending_achieved() > 0;
|
2017-12-28 04:49:37 +01:00
|
|
|
|
|
|
|
start_bgm("credits");
|
2012-08-05 03:36:55 +02:00
|
|
|
}
|
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
static double entry_height(CreditsEntry *e, double *head, double *body) {
|
|
|
|
double total = *head = *body = 0;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
if(!e->lines) {
|
|
|
|
return total;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
if(e->lines > 0) {
|
|
|
|
if(*(e->data[0]) == '*') {
|
2018-09-14 09:37:20 +02:00
|
|
|
total += *head = r_texture_get_height(get_tex("yukkureimu"), 0) * CREDITS_YUKKURI_SCALE;
|
2018-01-09 00:32:52 +01:00
|
|
|
} else {
|
2018-06-29 23:36:51 +02:00
|
|
|
total += *head = font_get_lineskip(get_font("big"));
|
2018-01-09 00:32:52 +01:00
|
|
|
}
|
2017-12-28 04:49:37 +01:00
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
if(e->lines > 1) {
|
2018-06-29 23:36:51 +02:00
|
|
|
total += *body += (e->lines - 0.5) * font_get_lineskip(get_font("standard"));
|
2018-01-09 00:32:52 +01:00
|
|
|
}
|
2017-12-28 04:49:37 +01:00
|
|
|
}
|
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
return total;
|
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_draw_entry(CreditsEntry *e) {
|
2018-01-09 00:32:52 +01:00
|
|
|
int time = global.frames - 400;
|
|
|
|
float fadein = 1, fadeout = 1;
|
|
|
|
|
|
|
|
for(CreditsEntry *o = credits.entries; o != e; ++o) {
|
|
|
|
time -= o->time + CREDITS_ENTRY_FADEOUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
double h_total, h_head, h_body;
|
|
|
|
h_total = entry_height(e, &h_head, &h_body);
|
|
|
|
|
|
|
|
// random asspull approximation to make stuff not overlap too much
|
|
|
|
int ofs = (1 - pow(1 - h_total / SCREEN_H, 2)) * SCREEN_H * 0.095;
|
2017-12-28 04:49:37 +01:00
|
|
|
time -= ofs;
|
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
if(time < 0) {
|
2012-08-05 03:36:55 +02:00
|
|
|
return;
|
2018-01-09 00:32:52 +01:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-12-28 04:49:37 +01:00
|
|
|
ofs *= 2;
|
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
if(time <= CREDITS_ENTRY_FADEIN) {
|
2012-08-05 03:36:55 +02:00
|
|
|
fadein = time / CREDITS_ENTRY_FADEIN;
|
2018-01-09 00:32:52 +01:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
if(time - e->time - CREDITS_ENTRY_FADEIN + ofs > 0) {
|
2017-12-28 04:49:37 +01:00
|
|
|
fadeout = max(0, 1 - (time - e->time - CREDITS_ENTRY_FADEIN + ofs) / CREDITS_ENTRY_FADEOUT);
|
2018-01-09 00:32:52 +01:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
if(!fadein || !fadeout) {
|
2012-08-05 03:36:55 +02:00
|
|
|
return;
|
2012-08-06 06:17:51 +02:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
bool yukkuri = false;
|
2018-02-06 07:19:25 +01:00
|
|
|
Sprite *yukkuri_spr = NULL;
|
2017-12-28 04:49:37 +01:00
|
|
|
|
2018-01-09 00:32:52 +01:00
|
|
|
if(*e->data[0] == '*') {
|
|
|
|
yukkuri = true;
|
2018-02-06 07:19:25 +01:00
|
|
|
yukkuri_spr = get_sprite("yukkureimu");
|
2017-12-28 04:49:37 +01:00
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_push();
|
2018-01-09 00:32:52 +01:00
|
|
|
|
|
|
|
if(fadein < 1) {
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_translate(0, SCREEN_W * pow(1 - fadein, 2) * 0.5, 0);
|
2018-01-09 00:32:52 +01:00
|
|
|
} else if(fadeout < 1) {
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_translate(0, SCREEN_W * pow(1 - fadeout, 2) * -0.5, 0);
|
2018-01-09 00:32:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// for debugging: draw a quad as tall as the entry is expected to be
|
|
|
|
/*
|
2018-04-12 16:08:48 +02:00
|
|
|
render_push();
|
|
|
|
render_color4(1, 0, 0, fadein * fadeout);
|
|
|
|
render_shader_standard_notex();
|
|
|
|
render_scale(300, h_total, 1);
|
|
|
|
render_draw_quad();
|
|
|
|
render_shader_standard();
|
|
|
|
render_pop();
|
2018-01-09 00:32:52 +01:00
|
|
|
*/
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-07-23 19:07:59 +02:00
|
|
|
r_color(RGBA_MUL_ALPHA(1, 1, 1, fadein * fadeout));
|
2019-01-24 21:21:08 +01:00
|
|
|
r_mat_translate(0, h_body * -0.5, 0);
|
2018-01-09 00:32:52 +01:00
|
|
|
|
|
|
|
for(int i = 0; i < e->lines; ++i) {
|
2012-08-06 06:17:51 +02:00
|
|
|
if(yukkuri && !i) {
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_push();
|
|
|
|
r_mat_scale(CREDITS_YUKKURI_SCALE, CREDITS_YUKKURI_SCALE, 1.0);
|
2018-02-06 07:19:25 +01:00
|
|
|
draw_sprite_p(0, 10 * sin(global.frames / 10.0) * fadeout * fadein, yukkuri_spr);
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_pop();
|
|
|
|
r_mat_translate(0, yukkuri_spr->h * CREDITS_YUKKURI_SCALE * 0.5, 0);
|
2018-01-09 00:32:52 +01:00
|
|
|
} else {
|
2018-06-29 23:36:51 +02:00
|
|
|
Font *font = get_font(i ? "standard" : "big");
|
|
|
|
r_shader("text_default");
|
|
|
|
text_draw(e->data[i], &(TextParams) {
|
|
|
|
.align = ALIGN_CENTER,
|
|
|
|
.font_ptr = font,
|
|
|
|
});
|
|
|
|
r_shader_standard();
|
|
|
|
r_mat_translate(0, font_get_lineskip(font), 0);
|
2018-01-09 00:32:52 +01:00
|
|
|
}
|
2012-08-06 06:17:51 +02:00
|
|
|
}
|
2018-01-09 00:32:52 +01:00
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_pop();
|
|
|
|
r_color4(1, 1, 1, 1);
|
2012-08-05 03:36:55 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_draw(void) {
|
2018-09-14 09:37:20 +02:00
|
|
|
r_clear(CLEAR_ALL, RGBA(0, 0, 0, 1), 1);
|
|
|
|
colorfill(1, 1, 1, 1); // don't use r_clear for this, it screws up letterboxing
|
2018-01-08 22:40:41 +01:00
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_push();
|
|
|
|
r_mat_translate(-SCREEN_W/2, 0, 0);
|
|
|
|
r_enable(RCAP_DEPTH_TEST);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-11-14 02:41:08 +01:00
|
|
|
set_perspective_viewport(&stage_3d_context, 100, 9000, 0, 0, SCREEN_W, SCREEN_H);
|
|
|
|
draw_stage3d(&stage_3d_context, 10000);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_pop();
|
2018-04-26 01:50:48 +02:00
|
|
|
set_ortho(SCREEN_W, SCREEN_H);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_push();
|
|
|
|
r_color4(0, 0, 0, credits.panelalpha * 0.7);
|
|
|
|
r_mat_translate(SCREEN_W/4*3, SCREEN_H/2, 0);
|
|
|
|
r_mat_scale(300, SCREEN_H, 1);
|
2018-11-02 23:27:51 +01:00
|
|
|
r_shader_standard_notex();
|
2018-04-12 16:08:48 +02:00
|
|
|
r_draw_quad();
|
|
|
|
r_color4(1, 1, 1, 1);
|
|
|
|
r_mat_pop();
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_push();
|
|
|
|
r_mat_translate(SCREEN_W/4*3, SCREEN_H/2, 0);
|
2017-12-28 04:49:37 +01:00
|
|
|
|
2018-11-02 23:27:51 +01:00
|
|
|
r_shader_standard();
|
|
|
|
|
2017-12-28 04:49:37 +01:00
|
|
|
for(int i = 0; i < credits.ecount; ++i) {
|
2012-08-05 03:36:55 +02:00
|
|
|
credits_draw_entry(&(credits.entries[i]));
|
2017-12-28 04:49:37 +01:00
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
r_mat_pop();
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-12-26 09:56:21 +01:00
|
|
|
draw_transition();
|
2012-08-05 03:36:55 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_finish(void *arg) {
|
2017-02-25 14:23:22 +01:00
|
|
|
credits.end = 0;
|
|
|
|
set_transition(TransLoader, 0, FADE_TIME*10);
|
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_process(void) {
|
2012-08-05 03:36:55 +02:00
|
|
|
TIMER(&global.frames);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2017-11-14 02:41:08 +01:00
|
|
|
stage_3d_context.cx[2] = 200 - global.frames * 50;
|
|
|
|
stage_3d_context.cx[1] = 500 + 100 * psin(global.frames / 100.0) * psin(global.frames / 200.0 + M_PI);
|
|
|
|
stage_3d_context.cx[0] = 25 * sin(global.frames / 75.7) * cos(global.frames / 99.3);
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
FROM_TO(200, 300, 1)
|
|
|
|
credits.panelalpha += 0.01;
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-05 23:27:34 +02:00
|
|
|
if(global.frames >= credits.end - CREDITS_ENTRY_FADEOUT) {
|
|
|
|
credits.panelalpha -= 1 / 120.0;
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-14 17:56:53 +02:00
|
|
|
if(global.frames == credits.end) {
|
2017-02-25 14:23:22 +01:00
|
|
|
set_transition_callback(TransFadeWhite, CREDITS_FADEOUT, CREDITS_FADEOUT, credits_finish, NULL);
|
2012-08-05 23:27:34 +02:00
|
|
|
}
|
2012-08-05 03:36:55 +02:00
|
|
|
}
|
|
|
|
|
2018-04-12 16:08:48 +02:00
|
|
|
static void credits_free(void) {
|
2012-08-05 03:36:55 +02:00
|
|
|
int i, j;
|
|
|
|
for(i = 0; i < credits.ecount; ++i) {
|
|
|
|
CreditsEntry *e = &(credits.entries[i]);
|
|
|
|
for(j = 0; j < e->lines; ++j)
|
|
|
|
free(e->data[j]);
|
|
|
|
free(e->data);
|
|
|
|
}
|
2017-02-11 04:52:08 +01:00
|
|
|
|
2012-08-05 03:36:55 +02:00
|
|
|
free(credits.entries);
|
|
|
|
}
|
|
|
|
|
2017-03-11 04:41:57 +01:00
|
|
|
void credits_preload(void) {
|
2017-10-02 04:34:51 +02:00
|
|
|
preload_resource(RES_BGM, "credits", RESF_OPTIONAL);
|
2018-04-12 16:08:48 +02:00
|
|
|
preload_resource(RES_SHADER_PROGRAM, "tower_wall", RESF_DEFAULT);
|
2019-04-22 23:09:58 +02:00
|
|
|
preload_resource(RES_SPRITE, "yukkureimu", RESF_DEFAULT);
|
2017-03-11 04:41:57 +01:00
|
|
|
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
|
|
|
"stage6/towerwall",
|
2019-04-22 23:09:58 +02:00
|
|
|
"loading", // for transition
|
2017-03-11 04:41:57 +01:00
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
static LogicFrameAction credits_logic_frame(void *arg) {
|
2017-12-26 09:56:21 +01:00
|
|
|
update_transition();
|
2017-10-04 07:07:04 +02:00
|
|
|
events_poll(NULL, 0);
|
|
|
|
credits_process();
|
|
|
|
global.frames++;
|
2019-01-05 22:40:50 +01:00
|
|
|
|
|
|
|
if(credits.end == 0) {
|
|
|
|
return LFRAME_STOP;
|
|
|
|
} else if(credits.skipable && gamekeypressed(KEY_SKIP)) {
|
|
|
|
return LFRAME_SKIP;
|
|
|
|
} else {
|
|
|
|
return LFRAME_WAIT;
|
|
|
|
}
|
2017-12-26 12:07:40 +01:00
|
|
|
}
|
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
static RenderFrameAction credits_render_frame(void *arg) {
|
2017-12-26 12:07:40 +01:00
|
|
|
credits_draw();
|
|
|
|
return RFRAME_SWAP;
|
2017-10-04 07:07:04 +02:00
|
|
|
}
|
|
|
|
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
static void credits_end_loop(void *ctx) {
|
|
|
|
credits_free();
|
2019-03-11 00:21:43 +01:00
|
|
|
progress_unlock_bgm("credits");
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
run_call_chain(&credits.cc, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void credits_enter(CallChain next) {
|
2017-03-11 04:41:57 +01:00
|
|
|
credits_preload();
|
2012-08-05 03:36:55 +02:00
|
|
|
credits_init();
|
Emscripten compatibility (#161)
* Major refactoring of the main loop(s) and control flow (WIP)
run_at_fps() is gone 🦀
Instead of nested blocking event loops, there is now an eventloop API
that manages an explicit stack of scenes. This makes Taisei a lot more
portable to async environments where spinning a loop forever without
yielding control simply is not an option, and that is the entire point
of this change.
A prime example of such an environment is the Web (via emscripten).
Taisei was able to run there through a terrible hack: inserting
emscripten_sleep calls into the loop, which would yield to the browser.
This has several major drawbacks: first of all, every function that
could possibly call emscripten_sleep must be compiled into a special
kind of bytecode, which then has to be interpreted at runtime, *much*
slower than JITed WebAssembly. And that includes *everything* down the
call stack, too! For more information, see
https://emscripten.org/docs/porting/emterpreter.html
Even though that method worked well enough for experimenting, despite
suboptimal performance, there is another obvious drawback:
emscripten_sleep is implemented via setTimeout(), which can be very
imprecise and is generally not reliable for fluid animation. Browsers
actually have an API specifically for that use case:
window.requestAnimationFrame(), but Taisei's original blocking control
flow style is simply not compatible with it. Emscripten exposes this API
with its emscripten_set_main_loop(), which the eventloop backend now
uses on that platform.
Unfortunately, C is still C, with no fancy closures or coroutines.
With blocking calls into menu/scene loops gone, the control flow is
reimplemented via so-called (pun intended) "call chains". That is
basically an euphemism for callback hell. With manual memory management
and zero type-safety. Not that the menu system wasn't shitty enough
already. I'll just keep telling myself that this is all temporary and
will be replaced with scripts in v1.4.
* improve build system for emscripten + various fixes
* squish menu bugs
* improve emscripten event loop; disable EMULATE_FUNCTION_POINTER_CASTS
Note that stock freetype does not work without
EMULATE_FUNCTION_POINTER_CASTS; use a patched version from the
"emscripten" branch here:
https://github.com/taisei-project/freetype2/tree/emscripten
* Enable -Wcast-function-type
Calling functions through incompatible pointers is nasal demons and
doesn't work in WASM.
* webgl: workaround a crash on some browsers
* emscripten improvements:
* Persist state (config, progress, replays, ...) in local IndexDB
* Simpler HTML shell (temporary)
* Enable more optimizations
* fix build if validate_glsl=false
* emscripten: improve asset packaging, with local cache
Note that even though there are rules to build audio bundles, audio
does *not* work yet. It looks like SDL2_mixer can not work without
threads, which is a problem. Yet another reason to write an OpenAL
backend - emscripten supports that natively.
* emscripten: customize the html shell
* emscripten: force "show log" checkbox unchecked initially
* emscripten: remove quit shortcut from main menu (since there's no quit)
* emscripten: log area fixes
* emscripten/webgl: workaround for fullscreen viewport issue
* emscripten: implement frameskip
* emscripter: improve framerate limiter
* align List to at least 8 bytes (shut up warnings)
* fix non-emscripten builds
* improve fullscreen handling, mainly for emscripten
* Workaround to make audio work in chromium
emscripten-core/emscripten#6511
* emscripten: better vsync handling; enable vsync & disable fxaa by default
2019-03-09 20:32:32 +01:00
|
|
|
credits.cc = next;
|
|
|
|
eventloop_enter(&credits, credits_logic_frame, credits_render_frame, credits_end_loop, FPS);
|
2012-08-05 03:36:55 +02:00
|
|
|
}
|