2014-10-10 17:53:13 +00:00
|
|
|
/* RetroArch - A frontend for libretro.
|
2018-10-17 04:55:49 +00:00
|
|
|
* Copyright (C) 2014-2018 - Jean-André Santoni
|
|
|
|
* Copyright (C) 2011-2018 - Daniel De Matteis
|
2014-10-10 17:53:13 +00:00
|
|
|
*
|
|
|
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
|
|
|
* of the GNU General Public License as published by the Free Software Found-
|
|
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2014-09-19 11:36:18 +00:00
|
|
|
#include <math.h>
|
2015-02-11 17:52:59 +00:00
|
|
|
#include <string.h>
|
2016-05-10 18:31:27 +00:00
|
|
|
|
2015-02-11 17:52:59 +00:00
|
|
|
#include <compat/strl.h>
|
2016-02-24 23:57:46 +00:00
|
|
|
#include <encodings/utf.h>
|
2017-09-28 16:47:33 +00:00
|
|
|
#include <retro_math.h>
|
2015-03-15 02:26:09 +00:00
|
|
|
#include <retro_miscellaneous.h>
|
2016-05-10 18:31:27 +00:00
|
|
|
#include <features/features_cpu.h>
|
2015-06-05 16:22:15 +00:00
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
#define DG_DYNARR_IMPLEMENTATION
|
2018-12-27 19:18:53 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <retro_assert.h>
|
|
|
|
#define DG_DYNARR_ASSERT(cond, msg) (void)0
|
2018-12-10 02:12:57 +00:00
|
|
|
#include <array/dynarray.h>
|
|
|
|
#undef DG_DYNARR_IMPLEMENTATION
|
|
|
|
|
2015-09-26 23:10:15 +00:00
|
|
|
#include "menu_animation.h"
|
2015-06-14 23:50:57 +00:00
|
|
|
#include "../configuration.h"
|
2016-05-10 06:53:14 +00:00
|
|
|
#include "../performance_counters.h"
|
2014-09-19 11:36:18 +00:00
|
|
|
|
2019-02-08 06:26:43 +00:00
|
|
|
#define IDEAL_DELTA_TIME (1.0 / 60.0 * 1000000.0)
|
|
|
|
|
2015-09-06 00:41:36 +00:00
|
|
|
struct tween
|
|
|
|
{
|
2015-09-26 22:42:27 +00:00
|
|
|
float duration;
|
|
|
|
float running_since;
|
|
|
|
float initial_value;
|
|
|
|
float target_value;
|
|
|
|
float *subject;
|
2017-08-09 00:05:00 +00:00
|
|
|
uintptr_t tag;
|
2015-09-26 22:42:27 +00:00
|
|
|
easing_cb easing;
|
|
|
|
tween_cb cb;
|
2018-09-18 13:13:33 +00:00
|
|
|
void *userdata;
|
2018-12-19 00:12:19 +00:00
|
|
|
bool deleted;
|
2015-09-06 00:41:36 +00:00
|
|
|
};
|
|
|
|
|
2018-12-16 04:39:57 +00:00
|
|
|
DA_TYPEDEF(struct tween, tween_array_t)
|
2018-12-10 02:12:57 +00:00
|
|
|
|
2015-09-06 02:18:26 +00:00
|
|
|
struct menu_animation
|
2015-09-06 00:41:36 +00:00
|
|
|
{
|
2018-12-10 02:12:57 +00:00
|
|
|
tween_array_t list;
|
|
|
|
tween_array_t pending;
|
2018-12-19 00:12:19 +00:00
|
|
|
bool pending_deletes;
|
2018-12-10 02:12:57 +00:00
|
|
|
bool in_update;
|
2015-09-06 02:18:26 +00:00
|
|
|
};
|
2015-09-06 00:41:36 +00:00
|
|
|
|
2015-09-25 20:26:10 +00:00
|
|
|
typedef struct menu_animation menu_animation_t;
|
|
|
|
|
2017-01-09 15:39:09 +00:00
|
|
|
static menu_animation_t anim;
|
|
|
|
static retro_time_t cur_time = 0;
|
|
|
|
static retro_time_t old_time = 0;
|
|
|
|
static float delta_time = 0.0f;
|
|
|
|
static bool animation_is_active = false;
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
/* from https://github.com/kikito/tween.lua/blob/master/tween.lua */
|
2014-09-19 11:36:18 +00:00
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_linear(float t, float b, float c, float d)
|
2015-02-10 23:40:18 +00:00
|
|
|
{
|
2015-02-11 00:15:16 +00:00
|
|
|
return c * t / d + b;
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_out_quad(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
2015-02-11 00:15:16 +00:00
|
|
|
t = t / d * 2;
|
|
|
|
if (t < 1)
|
|
|
|
return c / 2 * pow(t, 2) + b;
|
|
|
|
return -c / 2 * ((t - 1) * (t - 3) - 1) + b;
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_quad(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return c * pow(t / d, 2) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_quad(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
t = t / d;
|
|
|
|
return -c * t * (t - 2) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_in_quad(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_out_quad(t * 2, b, c / 2, d);
|
|
|
|
return easing_in_quad((t * 2) - d, b + c / 2, c / 2, d);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_cubic(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return c * pow(t / d, 3) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_cubic(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return c * (pow(t / d - 1, 3) + 1) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-13 14:54:45 +00:00
|
|
|
static float easing_in_out_cubic(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
t = t / d * 2;
|
|
|
|
if (t < 1)
|
|
|
|
return c / 2 * t * t * t + b;
|
|
|
|
t = t - 2;
|
|
|
|
return c / 2 * (t * t * t + 2) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_in_cubic(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_out_cubic(t * 2, b, c / 2, d);
|
|
|
|
return easing_in_cubic((t * 2) - d, b + c / 2, c / 2, d);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_quart(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return c * pow(t / d, 4) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_quart(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return -c * (pow(t / d - 1, 4) - 1) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_out_quart(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
t = t / d * 2;
|
|
|
|
if (t < 1)
|
|
|
|
return c / 2 * pow(t, 4) + b;
|
|
|
|
return -c / 2 * (pow(t - 2, 4) - 2) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_in_quart(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_out_quart(t * 2, b, c / 2, d);
|
|
|
|
return easing_in_quart((t * 2) - d, b + c / 2, c / 2, d);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_quint(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return c * pow(t / d, 5) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_quint(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return c * (pow(t / d - 1, 5) + 1) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_out_quint(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
t = t / d * 2;
|
|
|
|
if (t < 1)
|
|
|
|
return c / 2 * pow(t, 5) + b;
|
|
|
|
return c / 2 * (pow(t - 2, 5) + 2) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_in_quint(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_out_quint(t * 2, b, c / 2, d);
|
|
|
|
return easing_in_quint((t * 2) - d, b + c / 2, c / 2, d);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_sine(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return -c * cos(t / d * (M_PI / 2)) + c + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_sine(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return c * sin(t / d * (M_PI / 2)) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_out_sine(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
return -c / 2 * (cos(M_PI * t / d) - 1) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_in_sine(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_out_sine(t * 2, b, c / 2, d);
|
|
|
|
return easing_in_sine((t * 2) -d, b + c / 2, c / 2, d);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_expo(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t == 0)
|
|
|
|
return b;
|
2014-10-22 00:05:01 +00:00
|
|
|
return c * powf(2, 10 * (t / d - 1)) + b - c * 0.001;
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_expo(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t == d)
|
|
|
|
return b + c;
|
2014-10-22 00:05:01 +00:00
|
|
|
return c * 1.001 * (-powf(2, -10 * t / d) + 1) + b;
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_out_expo(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t == 0)
|
|
|
|
return b;
|
|
|
|
if (t == d)
|
|
|
|
return b + c;
|
|
|
|
t = t / d * 2;
|
|
|
|
if (t < 1)
|
2014-10-22 00:05:01 +00:00
|
|
|
return c / 2 * powf(2, 10 * (t - 1)) + b - c * 0.0005;
|
|
|
|
return c / 2 * 1.0005 * (-powf(2, -10 * (t - 1)) + 2) + b;
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_in_expo(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_out_expo(t * 2, b, c / 2, d);
|
|
|
|
return easing_in_expo((t * 2) - d, b + c / 2, c / 2, d);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_circ(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
2014-10-22 00:05:01 +00:00
|
|
|
return(-c * (sqrt(1 - powf(t / d, 2)) - 1) + b);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_circ(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
2014-10-22 00:05:01 +00:00
|
|
|
return(c * sqrt(1 - powf(t / d - 1, 2)) + b);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_out_circ(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
t = t / d * 2;
|
|
|
|
if (t < 1)
|
|
|
|
return -c / 2 * (sqrt(1 - t * t) - 1) + b;
|
|
|
|
t = t - 2;
|
|
|
|
return c / 2 * (sqrt(1 - t * t) + 1) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_in_circ(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_out_circ(t * 2, b, c / 2, d);
|
|
|
|
return easing_in_circ((t * 2) - d, b + c / 2, c / 2, d);
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_bounce(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
t = t / d;
|
|
|
|
if (t < 1 / 2.75)
|
|
|
|
return c * (7.5625 * t * t) + b;
|
|
|
|
if (t < 2 / 2.75)
|
|
|
|
{
|
|
|
|
t = t - (1.5 / 2.75);
|
|
|
|
return c * (7.5625 * t * t + 0.75) + b;
|
|
|
|
}
|
|
|
|
else if (t < 2.5 / 2.75)
|
|
|
|
{
|
|
|
|
t = t - (2.25 / 2.75);
|
|
|
|
return c * (7.5625 * t * t + 0.9375) + b;
|
|
|
|
}
|
|
|
|
t = t - (2.625 / 2.75);
|
|
|
|
return c * (7.5625 * t * t + 0.984375) + b;
|
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_bounce(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
2015-02-11 00:15:16 +00:00
|
|
|
return c - easing_out_bounce(d - t, 0, c, d) + b;
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_in_out_bounce(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_in_bounce(t * 2, 0, c, d) * 0.5 + b;
|
|
|
|
return easing_out_bounce(t * 2 - d, 0, c, d) * 0.5 + c * .5 + b;
|
2014-09-19 11:36:18 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
static float easing_out_in_bounce(float t, float b, float c, float d)
|
2014-09-19 11:36:18 +00:00
|
|
|
{
|
|
|
|
if (t < d / 2)
|
2015-02-11 00:15:16 +00:00
|
|
|
return easing_out_bounce(t * 2, b, c / 2, d);
|
|
|
|
return easing_in_bounce((t * 2) - d, b + c / 2, c / 2, d);
|
|
|
|
}
|
|
|
|
|
2015-09-25 20:28:08 +00:00
|
|
|
static void menu_animation_ticker_generic(uint64_t idx,
|
|
|
|
size_t max_width, size_t *offset, size_t *width)
|
|
|
|
{
|
2017-02-26 09:33:03 +00:00
|
|
|
int ticker_period = (int)(2 * (*width - max_width) + 4);
|
2017-01-17 13:15:43 +00:00
|
|
|
int phase = idx % ticker_period;
|
2015-09-25 20:28:08 +00:00
|
|
|
|
2017-01-17 13:15:43 +00:00
|
|
|
int phase_left_stop = 2;
|
2017-02-26 09:33:03 +00:00
|
|
|
int phase_left_moving = (int)(phase_left_stop + (*width - max_width));
|
2017-01-17 13:15:43 +00:00
|
|
|
int phase_right_stop = phase_left_moving + 2;
|
2015-09-25 20:28:08 +00:00
|
|
|
|
2017-01-17 13:15:43 +00:00
|
|
|
int left_offset = phase - phase_left_stop;
|
2017-02-26 09:33:03 +00:00
|
|
|
int right_offset = (int)((*width - max_width) - (phase - phase_right_stop));
|
2015-09-25 20:28:08 +00:00
|
|
|
|
|
|
|
if (phase < phase_left_stop)
|
|
|
|
*offset = 0;
|
|
|
|
else if (phase < phase_left_moving)
|
2016-02-24 19:25:53 +00:00
|
|
|
*offset = left_offset;
|
2015-09-25 20:28:08 +00:00
|
|
|
else if (phase < phase_right_stop)
|
2016-02-24 19:25:53 +00:00
|
|
|
*offset = *width - max_width;
|
2015-09-25 20:28:08 +00:00
|
|
|
else
|
2016-02-24 19:25:53 +00:00
|
|
|
*offset = right_offset;
|
2015-09-25 20:28:08 +00:00
|
|
|
|
|
|
|
*width = max_width;
|
|
|
|
}
|
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
void menu_animation_init(void)
|
|
|
|
{
|
|
|
|
da_init(anim.list);
|
|
|
|
da_init(anim.pending);
|
|
|
|
}
|
|
|
|
|
|
|
|
void menu_animation_free(void)
|
|
|
|
{
|
|
|
|
da_free(anim.list);
|
|
|
|
da_free(anim.pending);
|
|
|
|
}
|
|
|
|
|
2019-01-23 11:05:53 +00:00
|
|
|
static void menu_delayed_animation_cb(void *userdata)
|
|
|
|
{
|
|
|
|
menu_delayed_animation_t *delayed_animation = (menu_delayed_animation_t*) userdata;
|
|
|
|
|
|
|
|
menu_animation_push(&delayed_animation->entry);
|
|
|
|
|
|
|
|
free(delayed_animation);
|
|
|
|
}
|
|
|
|
|
|
|
|
void menu_animation_push_delayed(unsigned delay, menu_animation_ctx_entry_t *entry)
|
|
|
|
{
|
|
|
|
menu_timer_ctx_entry_t timer_entry;
|
|
|
|
menu_delayed_animation_t *delayed_animation = (menu_delayed_animation_t*) malloc(sizeof(menu_delayed_animation_t));
|
|
|
|
|
|
|
|
memcpy(&delayed_animation->entry, entry, sizeof(menu_animation_ctx_entry_t));
|
|
|
|
|
|
|
|
timer_entry.cb = menu_delayed_animation_cb;
|
|
|
|
timer_entry.duration = delay;
|
|
|
|
timer_entry.userdata = delayed_animation;
|
|
|
|
|
|
|
|
menu_timer_start(&delayed_animation->timer, &timer_entry);
|
|
|
|
}
|
|
|
|
|
2017-01-17 15:53:06 +00:00
|
|
|
bool menu_animation_push(menu_animation_ctx_entry_t *entry)
|
2015-02-11 00:15:16 +00:00
|
|
|
{
|
2015-06-22 18:49:59 +00:00
|
|
|
struct tween t;
|
2015-02-11 00:15:16 +00:00
|
|
|
|
2017-01-17 15:53:06 +00:00
|
|
|
t.duration = entry->duration;
|
|
|
|
t.running_since = 0;
|
|
|
|
t.initial_value = *entry->subject;
|
|
|
|
t.target_value = entry->target_value;
|
|
|
|
t.subject = entry->subject;
|
|
|
|
t.tag = entry->tag;
|
|
|
|
t.cb = entry->cb;
|
2018-09-18 13:13:33 +00:00
|
|
|
t.userdata = entry->userdata;
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = NULL;
|
2018-12-19 00:12:19 +00:00
|
|
|
t.deleted = false;
|
2016-02-25 14:44:30 +00:00
|
|
|
|
|
|
|
switch (entry->easing_enum)
|
2015-02-11 00:15:16 +00:00
|
|
|
{
|
|
|
|
case EASING_LINEAR:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_linear;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
/* Quad */
|
|
|
|
case EASING_IN_QUAD:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_quad;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_QUAD:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_quad;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_IN_OUT_QUAD:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_out_quad;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_IN_QUAD:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_in_quad;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
/* Cubic */
|
|
|
|
case EASING_IN_CUBIC:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_cubic;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_CUBIC:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_cubic;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_IN_OUT_CUBIC:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_out_cubic;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_IN_CUBIC:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_in_cubic;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
/* Quart */
|
|
|
|
case EASING_IN_QUART:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_quart;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_QUART:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_quart;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_IN_OUT_QUART:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_out_quart;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_IN_QUART:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_in_quart;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
/* Quint */
|
|
|
|
case EASING_IN_QUINT:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_quint;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_QUINT:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_quint;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_IN_OUT_QUINT:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_out_quint;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_IN_QUINT:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_in_quint;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
/* Sine */
|
|
|
|
case EASING_IN_SINE:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_sine;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_SINE:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_sine;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_IN_OUT_SINE:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_out_sine;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_IN_SINE:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_in_sine;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
/* Expo */
|
|
|
|
case EASING_IN_EXPO:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_expo;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_EXPO:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_expo;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_IN_OUT_EXPO:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_out_expo;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_IN_EXPO:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_in_expo;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
/* Circ */
|
|
|
|
case EASING_IN_CIRC:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_circ;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_CIRC:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_circ;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_IN_OUT_CIRC:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_out_circ;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_IN_CIRC:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_in_circ;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
/* Bounce */
|
|
|
|
case EASING_IN_BOUNCE:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_bounce;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_BOUNCE:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_bounce;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_IN_OUT_BOUNCE:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_in_out_bounce;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
case EASING_OUT_IN_BOUNCE:
|
2017-01-17 15:53:06 +00:00
|
|
|
t.easing = &easing_out_in_bounce;
|
2015-02-11 00:15:16 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-06-22 18:49:59 +00:00
|
|
|
/* ignore born dead tweens */
|
|
|
|
if (!t.easing || t.duration == 0 || t.initial_value == t.target_value)
|
|
|
|
return false;
|
2019-02-03 23:49:35 +00:00
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
if (anim.in_update)
|
|
|
|
da_push(anim.pending, t);
|
2017-01-17 15:53:06 +00:00
|
|
|
else
|
2018-12-10 02:12:57 +00:00
|
|
|
da_push(anim.list, t);
|
2017-08-13 00:21:10 +00:00
|
|
|
|
2015-02-11 00:15:16 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-08 06:26:43 +00:00
|
|
|
bool menu_animation_update(float anim_delta_time)
|
2017-01-09 15:39:09 +00:00
|
|
|
{
|
|
|
|
unsigned i;
|
2018-11-22 14:45:52 +00:00
|
|
|
|
2018-12-19 00:12:19 +00:00
|
|
|
anim.in_update = true;
|
|
|
|
anim.pending_deletes = false;
|
2017-01-09 15:39:09 +00:00
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
for(i = 0; i < da_count(anim.list); i++)
|
2017-01-09 15:39:09 +00:00
|
|
|
{
|
2019-01-11 00:35:18 +00:00
|
|
|
struct tween *tween = da_getptr(anim.list, i);
|
2019-02-08 06:26:43 +00:00
|
|
|
tween->running_since += anim_delta_time;
|
2017-01-09 15:39:09 +00:00
|
|
|
|
|
|
|
*tween->subject = tween->easing(
|
|
|
|
tween->running_since,
|
|
|
|
tween->initial_value,
|
|
|
|
tween->target_value - tween->initial_value,
|
|
|
|
tween->duration);
|
|
|
|
|
|
|
|
if (tween->running_since >= tween->duration)
|
|
|
|
{
|
|
|
|
*tween->subject = tween->target_value;
|
|
|
|
|
|
|
|
if (tween->cb)
|
2018-09-18 13:13:33 +00:00
|
|
|
tween->cb(tween->userdata);
|
2019-02-03 23:49:35 +00:00
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
da_delete(anim.list, i);
|
|
|
|
i--;
|
2017-01-09 15:39:09 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-03 23:49:35 +00:00
|
|
|
|
2018-12-19 00:12:19 +00:00
|
|
|
if (anim.pending_deletes)
|
|
|
|
{
|
|
|
|
for(i = 0; i < da_count(anim.list); i++)
|
|
|
|
{
|
|
|
|
struct tween *tween = da_getptr(anim.list, i);
|
|
|
|
if (tween->deleted)
|
|
|
|
{
|
|
|
|
da_delete(anim.list, i);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
anim.pending_deletes = false;
|
|
|
|
}
|
2019-02-03 23:49:35 +00:00
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
if (da_count(anim.pending) > 0)
|
2017-01-09 15:39:09 +00:00
|
|
|
{
|
2018-12-10 02:12:57 +00:00
|
|
|
da_addn(anim.list, anim.pending.p, da_count(anim.pending));
|
|
|
|
da_clear(anim.pending);
|
2017-01-09 15:39:09 +00:00
|
|
|
}
|
|
|
|
|
2019-01-11 00:35:18 +00:00
|
|
|
anim.in_update = false;
|
2018-12-10 02:12:57 +00:00
|
|
|
animation_is_active = da_count(anim.list) > 0;
|
2017-08-09 01:37:37 +00:00
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
return animation_is_active;
|
2017-01-09 15:39:09 +00:00
|
|
|
}
|
2016-02-25 15:05:30 +00:00
|
|
|
|
2017-01-17 15:29:23 +00:00
|
|
|
bool menu_animation_ticker(const menu_animation_ctx_ticker_t *ticker)
|
|
|
|
{
|
|
|
|
size_t str_len = utf8len(ticker->str);
|
|
|
|
size_t offset = 0;
|
|
|
|
|
|
|
|
if ((size_t)str_len <= ticker->len)
|
|
|
|
{
|
|
|
|
utf8cpy(ticker->s,
|
|
|
|
PATH_MAX_LENGTH,
|
|
|
|
ticker->str,
|
|
|
|
ticker->len);
|
2019-02-07 11:09:21 +00:00
|
|
|
return false;
|
2017-01-17 15:29:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!ticker->selected)
|
|
|
|
{
|
|
|
|
utf8cpy(ticker->s, PATH_MAX_LENGTH, ticker->str, ticker->len - 3);
|
|
|
|
strlcat(ticker->s, "...", PATH_MAX_LENGTH);
|
2019-02-07 11:09:21 +00:00
|
|
|
return false;
|
2017-01-17 15:29:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (str_len > ticker->len)
|
|
|
|
menu_animation_ticker_generic(
|
|
|
|
ticker->idx,
|
|
|
|
ticker->len,
|
|
|
|
&offset,
|
|
|
|
&str_len);
|
|
|
|
|
|
|
|
utf8cpy(
|
|
|
|
ticker->s,
|
|
|
|
PATH_MAX_LENGTH,
|
|
|
|
utf8skip(ticker->str, offset),
|
|
|
|
str_len);
|
|
|
|
|
|
|
|
animation_is_active = true;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-01-17 15:55:34 +00:00
|
|
|
void menu_animation_update_time(bool timedate_enable)
|
2017-01-17 15:40:48 +00:00
|
|
|
{
|
2017-12-12 07:55:31 +00:00
|
|
|
static retro_time_t
|
2017-01-17 15:55:34 +00:00
|
|
|
last_clock_update = 0;
|
2017-01-17 15:40:48 +00:00
|
|
|
|
2019-02-08 06:26:43 +00:00
|
|
|
cur_time = cpu_features_get_time_usec();
|
|
|
|
delta_time = cur_time - old_time;
|
|
|
|
|
|
|
|
if (delta_time >= IDEAL_DELTA_TIME* 4)
|
|
|
|
delta_time = IDEAL_DELTA_TIME * 4;
|
|
|
|
if (delta_time <= IDEAL_DELTA_TIME / 4)
|
|
|
|
delta_time = IDEAL_DELTA_TIME / 4;
|
|
|
|
|
2017-01-17 15:55:34 +00:00
|
|
|
old_time = cur_time;
|
2017-01-17 15:40:48 +00:00
|
|
|
|
2019-02-08 06:26:43 +00:00
|
|
|
if (((cur_time - last_clock_update) > 1000000)
|
2017-01-17 15:55:34 +00:00
|
|
|
&& timedate_enable)
|
2017-01-17 15:40:48 +00:00
|
|
|
{
|
|
|
|
animation_is_active = true;
|
|
|
|
last_clock_update = cur_time;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool menu_animation_is_active(void)
|
|
|
|
{
|
|
|
|
return animation_is_active;
|
|
|
|
}
|
|
|
|
|
2018-10-17 04:49:24 +00:00
|
|
|
bool menu_animation_kill_by_tag(menu_animation_ctx_tag *tag)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
if (!tag || *tag == (uintptr_t)-1)
|
|
|
|
return false;
|
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
for (i = 0; i < da_count(anim.list); ++i)
|
2018-10-17 04:49:24 +00:00
|
|
|
{
|
2018-12-10 02:12:57 +00:00
|
|
|
struct tween *t = da_getptr(anim.list, i);
|
|
|
|
if (t->tag != *tag)
|
2018-10-17 04:49:24 +00:00
|
|
|
continue;
|
2019-02-03 23:49:35 +00:00
|
|
|
|
2018-12-19 00:12:19 +00:00
|
|
|
if (anim.in_update)
|
|
|
|
{
|
|
|
|
t->deleted = true;
|
|
|
|
anim.pending_deletes = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
da_delete(anim.list, i);
|
|
|
|
--i;
|
|
|
|
}
|
2018-10-17 04:49:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void menu_animation_kill_by_subject(menu_animation_ctx_subject_t *subject)
|
|
|
|
{
|
|
|
|
unsigned i, j, killed = 0;
|
|
|
|
float **sub = (float**)subject->data;
|
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
for (i = 0; i < da_count(anim.list) && killed < subject->count; ++i)
|
2018-10-17 04:49:24 +00:00
|
|
|
{
|
2018-12-10 02:12:57 +00:00
|
|
|
struct tween *t = da_getptr(anim.list, i);
|
2018-10-17 04:49:24 +00:00
|
|
|
|
|
|
|
for (j = 0; j < subject->count; ++j)
|
|
|
|
{
|
2018-12-10 02:12:57 +00:00
|
|
|
if (t->subject != sub[j])
|
2018-10-17 04:49:24 +00:00
|
|
|
continue;
|
2019-02-03 23:49:35 +00:00
|
|
|
|
2018-12-19 00:12:19 +00:00
|
|
|
if (anim.in_update)
|
|
|
|
{
|
|
|
|
t->deleted = true;
|
|
|
|
anim.pending_deletes = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
da_delete(anim.list, i);
|
|
|
|
--i;
|
|
|
|
}
|
2018-10-17 04:49:24 +00:00
|
|
|
|
|
|
|
killed++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-08 23:18:27 +00:00
|
|
|
void menu_animation_get_time(menu_animation_ctx_delta_t *delta)
|
2018-10-17 04:55:49 +00:00
|
|
|
{
|
2019-02-08 23:18:27 +00:00
|
|
|
delta->current = delta_time;
|
|
|
|
delta->ideal = delta_time / IDEAL_DELTA_TIME;
|
2018-10-17 04:55:49 +00:00
|
|
|
}
|
|
|
|
|
2015-09-25 21:33:11 +00:00
|
|
|
bool menu_animation_ctl(enum menu_animation_ctl_state state, void *data)
|
2015-09-06 00:41:36 +00:00
|
|
|
{
|
2015-09-25 21:33:11 +00:00
|
|
|
switch (state)
|
|
|
|
{
|
2015-12-11 11:00:49 +00:00
|
|
|
case MENU_ANIMATION_CTL_DEINIT:
|
2016-02-25 12:26:51 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
for (i = 0; i < da_count(anim.list); i++)
|
2016-02-25 12:26:51 +00:00
|
|
|
{
|
2018-12-10 02:12:57 +00:00
|
|
|
struct tween *t = da_getptr(anim.list, i);
|
|
|
|
if (t->subject)
|
|
|
|
t->subject = NULL;
|
2016-02-25 12:26:51 +00:00
|
|
|
}
|
|
|
|
|
2018-12-10 02:12:57 +00:00
|
|
|
da_free(anim.list);
|
2016-02-25 12:26:51 +00:00
|
|
|
|
2016-02-25 14:47:03 +00:00
|
|
|
memset(&anim, 0, sizeof(menu_animation_t));
|
2016-02-25 12:26:51 +00:00
|
|
|
}
|
2016-02-25 14:25:16 +00:00
|
|
|
cur_time = 0;
|
|
|
|
old_time = 0;
|
|
|
|
delta_time = 0.0f;
|
2015-12-11 11:00:49 +00:00
|
|
|
break;
|
2015-09-25 21:39:02 +00:00
|
|
|
case MENU_ANIMATION_CTL_CLEAR_ACTIVE:
|
2016-02-25 14:25:16 +00:00
|
|
|
animation_is_active = false;
|
2016-02-11 00:54:09 +00:00
|
|
|
break;
|
2015-09-25 21:42:00 +00:00
|
|
|
case MENU_ANIMATION_CTL_SET_ACTIVE:
|
2016-02-25 14:25:16 +00:00
|
|
|
animation_is_active = true;
|
2016-02-11 00:54:09 +00:00
|
|
|
break;
|
|
|
|
case MENU_ANIMATION_CTL_NONE:
|
2016-02-25 14:05:18 +00:00
|
|
|
default:
|
2016-02-11 00:54:09 +00:00
|
|
|
break;
|
2015-09-25 21:33:11 +00:00
|
|
|
}
|
|
|
|
|
2016-02-11 00:54:09 +00:00
|
|
|
return true;
|
2015-09-06 00:41:36 +00:00
|
|
|
}
|
2018-11-13 13:33:32 +00:00
|
|
|
|
|
|
|
void menu_timer_start(menu_timer_t *timer, menu_timer_ctx_entry_t *timer_entry)
|
|
|
|
{
|
2018-11-19 03:22:49 +00:00
|
|
|
menu_animation_ctx_entry_t entry;
|
2018-11-13 13:33:32 +00:00
|
|
|
menu_animation_ctx_tag tag = (uintptr_t) timer;
|
|
|
|
|
|
|
|
menu_timer_kill(timer);
|
|
|
|
|
|
|
|
*timer = 0.0f;
|
|
|
|
|
|
|
|
entry.easing_enum = EASING_LINEAR;
|
|
|
|
entry.tag = tag;
|
|
|
|
entry.duration = timer_entry->duration;
|
|
|
|
entry.target_value = 1.0f;
|
|
|
|
entry.subject = timer;
|
|
|
|
entry.cb = timer_entry->cb;
|
|
|
|
entry.userdata = timer_entry->userdata;
|
|
|
|
|
|
|
|
menu_animation_push(&entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void menu_timer_kill(menu_timer_t *timer)
|
|
|
|
{
|
|
|
|
menu_animation_ctx_tag tag = (uintptr_t) timer;
|
|
|
|
menu_animation_kill_by_tag(&tag);
|
|
|
|
}
|