@@ -5200,129 +5200,65 @@ int Game_Interpreter::ManiacBitmask(int value, int mask) const {
52005200
52015201 return value;
52025202}
5203- std::vector<double > parseBezier (const std::string& bezierParams) {
5204- std::vector<double > params;
5205- std::string temp;
5206- size_t startPos = bezierParams.find (" (" ) + 1 ;
5207- size_t endPos = bezierParams.find (" )" );
5208- std::string valuesString = bezierParams.substr (startPos, endPos - startPos);
52095203
5210- size_t commaPos = valuesString.find (" ," );
5211- while (commaPos != std::string::npos) {
5212- temp = valuesString.substr (0 , commaPos);
5213- params.push_back (std::stod (temp));
5214- valuesString = valuesString.substr (commaPos + 1 );
5215- commaPos = valuesString.find (" ," );
5216- }
5217- // Push the last value into the vector
5218- params.push_back (std::stod (valuesString));
5219-
5220- return params;
5221- }
5222-
5223- // FIXME: cubicBezier is completely Broken
5224- // references to how it should work:
5204+ // references for cubic bezier:
52255205// https://matthewlein.com/tools/ceaser
52265206// https://cubic-bezier.com/
5207+ double cubicBezier (float t, const double & p0,const double & p1, const double & p2, const double & p3) {
52275208
5228- double cubicBezier (double t, double p0, double p1, double p2, double p3) {
5229- double u = 1 - t;
5230- double tt = t * t;
5231- double uu = u * u;
5232- double uuu = uu * u;
5233- double ttt = tt * t;
5209+ float u = 1 - t;
5210+ float tt = t * t;
5211+ float uu = u * u;
5212+ float uuu = uu * u;
5213+ float ttt = tt * t;
52345214
5235- double p = uuu * p0; // (1-t)^3
5236- double q = 3 * uu * t * p1; // 3t(1-t)^2
5237- double r = 3 * u * tt * p2; // 3(1-t)t^2
5238- double s = ttt * p3; // t^3
5215+ // Point2d p = {0,0};
5216+ // p.x = uuu * 0 + 3 * uu * t * p0 + 3 * u * tt * p2 + ttt * 1;
5217+ return uuu * 0 + 3 * uu * t * p1 + 3 * u * tt * p3 + ttt * 1 ;
52395218
5240- return p + q + r + s ;
5219+ // return p.y ;
52415220}
52425221
5243- double getEasedT (const std::string& easingType, double t, double b, double c, double d) {
5244- if (easingType == " linear" ) {
5245- return c * t / d + b;
5246- }
5247- else if (easingType == " quadIn" ) {
5248- t /= d;
5249- return c * t * t + b;
5250- }
5251- else if (easingType == " quadOut" ) {
5252- t /= d;
5253- return -c * t * (t - 2 ) + b;
5254- }
5255- else if (easingType == " quadInOut" ) {
5256- t /= d / 2 ;
5257- if (t < 1 ) {
5258- return c / 2 * t * t + b;
5259- }
5260- else {
5261- t -= 1 ;
5262- return -c / 2 * (t * (t - 2 ) - 1 ) + b;
5263- }
5264- }
5265- else if (easingType == " cubicIn" ) {
5266- t /= d;
5267- return c * t * t * t + b;
5268- }
5269- else if (easingType == " cubicOut" ) {
5270- t = (t / d) - 1 ;
5271- return c * (t * t * t + 1 ) + b;
5272- }
5273- else if (easingType == " cubicInOut" ) {
5274- t /= d / 2 ;
5275- if (t < 1 ) {
5276- return c / 2 * t * t * t + b;
5277- }
5278- else {
5279- t -= 2 ;
5280- return c / 2 * (t * t * t + 2 ) + b;
5281- }
5282- }
5283- else if (easingType == " sinIn" ) {
5284- return -c * cos (t / d * (M_PI / 2 )) + c + b;
5285- }
5286- else if (easingType == " sinOut" ) {
5287- return c * sin (t / d * (M_PI / 2 )) + b;
5288- }
5289- else if (easingType == " sinInOut" ) {
5290- return -c / 2 * (cos (M_PI * t / d) - 1 ) + b;
5291- }
5292- else if (easingType == " expoIn" ) {
5293- return c * pow (2 , 10 * (t / d - 1 )) + b;
5294- }
5295- else if (easingType == " expoOut" ) {
5296- return c * (-pow (2 , -10 * t / d) + 1 ) + b;
5297- }
5298- else if (easingType == " expoInOut" ) {
5299- t /= d / 2 ;
5300- if (t < 1 ) {
5301- return c / 2 * pow (2 , 10 * (t - 1 )) + b;
5302- }
5303- else {
5304- t -= 1 ;
5305- return c / 2 * (-pow (2 , -10 * t) + 2 ) + b;
5306- }
5307- }
5308- else if (easingType == " circIn" ) {
5309- t /= d;
5310- return -c * (sqrt (1 - t * t) - 1 ) + b;
5311- }
5312- else if (easingType == " circOut" ) {
5313- t = (t / d) - 1 ;
5314- return c * sqrt (1 - t * t) + b;
5315- }
5316- else if (easingType == " circInOut" ) {
5317- t /= d / 2 ;
5318- if (t < 1 ) {
5319- return -c / 2 * (sqrt (1 - t * t) - 1 ) + b;
5320- }
5321- else {
5322- t -= 2 ;
5323- return c / 2 * (sqrt (1 - t * t) + 1 ) + b;
5324- }
5325- }
5222+ double getEasedTime (const std::string& easingType, double t, double b, double c, double d) {
5223+ if (easingType == " linear" ) return cubicBezier (t, 0.250 , 0.250 , 0.750 , 0.750 );
5224+
5225+ else if (easingType == " ease" ) return cubicBezier (t, 0.250 , 0.100 , 0.250 , 1.000 );
5226+ else if (easingType == " easeIn" ) return cubicBezier (t, 0.420 , 0.000 , 1.000 , 1.000 );
5227+ else if (easingType == " easeOut" ) return cubicBezier (t, 0.000 , 0.000 , 0.580 , 1.000 );
5228+ else if (easingType == " easeInOut" ) return cubicBezier (t, 0.420 , 0.000 , 0.580 , 1.000 );
5229+
5230+ else if (easingType == " quadIn" ) return cubicBezier (t, 0.550 , 0.085 , 0.680 , 0.530 );
5231+ else if (easingType == " quadOut" ) return cubicBezier (t, 0.250 , 0.460 , 0.450 , 0.940 );
5232+ else if (easingType == " quadInOut" ) return cubicBezier (t, 0.455 , 0.030 , 0.515 , 0.955 );
5233+
5234+ else if (easingType == " cubicIn" ) return cubicBezier (t, 0.550 , 0.055 , 0.675 , 0.190 );
5235+ else if (easingType == " cubicOut" ) return cubicBezier (t, 0.215 , 0.610 , 0.355 , 1.000 );
5236+ else if (easingType == " cubicInOut" ) return cubicBezier (t, 0.645 , 0.045 , 0.355 , 1.000 );
5237+
5238+ else if (easingType == " quartIn" ) return cubicBezier (t, 0.895 , 0.030 , 0.685 , 0.220 );
5239+ else if (easingType == " quartOut" ) return cubicBezier (t, 0.165 , 0.840 , 0.440 , 1.000 );
5240+ else if (easingType == " quartInOut" ) return cubicBezier (t, 0.770 , 0.000 , 0.175 , 1.000 );
5241+
5242+ else if (easingType == " quintIn" ) return cubicBezier (t, 0.755 , 0.050 , 0.855 , 0.060 );
5243+ else if (easingType == " quintOut" ) return cubicBezier (t, 0.230 , 1.000 , 0.320 , 1.000 );
5244+ else if (easingType == " quintInOut" ) return cubicBezier (t, 0.860 , 0.000 , 0.070 , 1.000 );
5245+
5246+ else if (easingType == " sineIn" ) return cubicBezier (t, 0.470 , 0.000 , 0.745 , 0.715 );
5247+ else if (easingType == " sineOut" ) return cubicBezier (t, 0.390 , 0.575 , 0.565 , 1.000 );
5248+ else if (easingType == " sineInOut" ) return cubicBezier (t, 0.445 , 0.050 , 0.550 , 0.950 );
5249+
5250+ else if (easingType == " ExpoIn" ) return cubicBezier (t, 0.950 , 0.050 , 0.795 , 0.035 );
5251+ else if (easingType == " expoOut" ) return cubicBezier (t, 0.190 , 1.000 , 0.220 , 1.000 );
5252+ else if (easingType == " expoInOut" ) return cubicBezier (t, 1.000 , 0.000 , 0.000 , 1.000 );
5253+
5254+ else if (easingType == " circIn" ) return cubicBezier (t, 0.600 , 0.040 , 0.980 , 0.335 );
5255+ else if (easingType == " circOut" ) return cubicBezier (t, 0.075 , 0.820 , 0.165 , 1.000 );
5256+ else if (easingType == " circInOut" ) return cubicBezier (t, 0.785 , 0.135 , 0.150 , 0.860 );
5257+
5258+ else if (easingType == " backIn" ) return cubicBezier (t, 0.600 , -0.280 , 0.735 , 0.045 );
5259+ else if (easingType == " backOut" ) return cubicBezier (t, 0.175 , 0.885 , 0.320 , 1.275 );
5260+ else if (easingType == " backInOut" ) return cubicBezier (t, 0.680 , -0.550 , 0.265 , 1.550 );
5261+
53265262 else if (easingType == " elasticIn" ) {
53275263 if (t == 0 ) {
53285264 return b;
@@ -5372,8 +5308,9 @@ double getEasedT(const std::string& easingType, double t, double b, double c, do
53725308 double postFix = a * pow (2 , -10 * (t -= 1 )); // this is a fix, again, with post-increment operators
53735309 return postFix * sin ((t * d - s) * (2 * M_PI) / p) * 0.5 + c + b;
53745310 }
5311+
53755312 else if (easingType == " bounceIn" ) {
5376- return c - getEasedT (" bounceOut" , d - t, 0 , c, d) + b;
5313+ return c - getEasedTime (" bounceOut" , d - t, 0 , c, d) + b;
53775314 }
53785315 else if (easingType == " bounceOut" ) {
53795316 if ((t /= d) < (1 / 2.75 )) {
@@ -5394,65 +5331,30 @@ double getEasedT(const std::string& easingType, double t, double b, double c, do
53945331 }
53955332 else if (easingType == " bounceInOut" ) {
53965333 if (t < d / 2 ) {
5397- return getEasedT (" bounceIn" , t * 2 , 0 , c, d) * 0.5 + b;
5334+ return getEasedTime (" bounceIn" , t * 2 , 0 , c, d) * 0.5 + b;
53985335 }
53995336 else {
5400- return getEasedT (" bounceOut" , t * 2 - d, 0 , c, d) * 0.5 + c * 0.5 + b;
5401- }
5402- }
5403- if (easingType.substr (0 , 6 ) == " bezier" ) {
5404- std::vector < double > bezierParams = parseBezier (easingType.substr (7 ));
5405- if (bezierParams.size () == 4 ) {
5406- return cubicBezier (t / d, bezierParams[0 ], bezierParams[1 ], bezierParams[2 ], bezierParams[3 ]);
5337+ return getEasedTime (" bounceOut" , t * 2 - d, 0 , c, d) * 0.5 + c * 0.5 + b;
54075338 }
54085339 }
54095340
5410- return c * t / d + b; // Default to linear easing if the easing type is not recognized
5411- }
5412-
5413- std::vector<double > interpolate (double start, double end, double duration, const std::string& easingTypeAtStart, const std::string& easingTypeAtEnd) {
5414- std::vector<double > interpolatedValues;
5415- interpolatedValues.push_back (start);
5341+ if (easingType.substr (0 , 6 ) == " bezier" ) {
5342+ std::vector<double > bezierParams;
54165343
5417- // Calculate the number of steps based on the duration
5418- int numSteps = static_cast < int >(duration); // Convert duration to an integer
5419- double stepSize = 1.0 / numSteps ;
5344+ size_t startPos = easingType. find ( " ( " ) + 1 ;
5345+ size_t endPos = easingType. find ( " ) " );
5346+ std::string valuesString = easingType. substr (startPos, endPos - startPos) ;
54205347
5421- // Calculate the halfway point
5422- double halfway = start + (end - start) * 0.5 ;
5348+ std::istringstream iss (valuesString);
5349+ double value ;
54235350
5424- if (easingTypeAtEnd == " null" ) {
5425- // Use easingTypeAtStart for the entire animation
5426- for (int step = 1 ; step <= numSteps; ++step) {
5427- double t = step * stepSize;
5428- double easedT = getEasedT (easingTypeAtStart, t, 0 , 1 , 1 ); // Call getEasedT with appropriate parameters
5429- double interpolatedValue = start + easedT * (end - start);
5430- interpolatedValues.push_back (interpolatedValue);
5431- }
5432- }
5433- else {
5434- // Generate the first half of the interpolation
5435- for (int step = 1 ; step <= numSteps / 2 ; ++step) {
5436- double t = step * stepSize;
5437- double normalizedT = t / 0.5 ; // Normalize the time for the first half
5438- double easedT = getEasedT (easingTypeAtStart, normalizedT, 0 , 1 , 1 ); // Call getEasedT with appropriate parameters
5439- double interpolatedValue = start + easedT * (halfway - start);
5440- interpolatedValues.push_back (interpolatedValue);
5441- }
5351+ while (iss >> value) bezierParams.push_back (value), iss.ignore ();
54425352
5443- // Generate the second half of the interpolation
5444- for (int step = numSteps / 2 + 1 ; step <= numSteps; ++step) {
5445- double t = step * stepSize;
5446- double normalizedT = (t - 0.5 ) / 0.5 ; // Normalize the time for the second half
5447- double easedT = getEasedT (easingTypeAtEnd, normalizedT, 0 , 1 , 1 ); // Call getEasedT with appropriate parameters
5448- double interpolatedValue = halfway + easedT * (end - halfway);
5449- interpolatedValues.push_back (interpolatedValue);
5450- }
5353+ if (bezierParams.size () == 4 )
5354+ return cubicBezier (t, bezierParams[0 ], bezierParams[1 ], bezierParams[2 ], bezierParams[3 ]);
54515355 }
54525356
5453- interpolatedValues.push_back (end);
5454-
5455- return interpolatedValues;
5357+ return c * t / d + b; // Default to linear easing if the easing type is not recognized
54565358}
54575359
54585360bool Game_Interpreter::CommandAnimateVariable (lcf::rpg::EventCommand const & com) {
@@ -5463,42 +5365,67 @@ bool Game_Interpreter::CommandAnimateVariable(lcf::rpg::EventCommand const& com)
54635365 int32_t end = ValueOrVariable (com.parameters [4 ], com.parameters [5 ]);
54645366 int32_t duration = ValueOrVariable (com.parameters [6 ], com.parameters [7 ]);
54655367
5368+ // Extract easing information
5369+ std::string easingTypeAtStart = ToString (com.string );
5370+ std::string easingTypeAtEnd = " null" ;
5371+
5372+ std::size_t pos = easingTypeAtStart.find (' /' );
5373+
5374+ if (pos != std::string::npos) {
5375+ easingTypeAtEnd = easingTypeAtStart.substr (pos + 1 );
5376+ easingTypeAtStart = easingTypeAtStart.substr (0 , pos);
5377+ }
5378+
54665379 // Prepare animation-related commands
54675380 lcf::rpg::EventCommand waitCom;
54685381 waitCom.code = int (Cmd::Wait);
54695382
54705383 lcf::rpg::EventCommand animatedCom;
54715384 animatedCom.code = int (Cmd::ControlVars);
54725385 std::vector<int32_t > animatedVarParams = { 0 , static_cast <int32_t >(target), 0 , 0 , 0 , static_cast <int32_t >(end) };
5473- animatedCom.parameters = lcf::DBArray<int32_t >(animatedVarParams.begin (), animatedVarParams.end ());
54745386
54755387 std::vector<lcf::rpg::EventCommand> cmdList;
54765388
5477- // Extract easing information
5478- std::string easeStart = ToString (com.string );
5479- std::string easeEnd = " null" ;
5389+ int numSteps = static_cast <int >(duration);
5390+ double stepSize = 1.0 / numSteps;
54805391
5481- std::size_t pos = easeStart.find (' /' );
5392+ for (int step = 1 ; step <= numSteps; ++step) {
5393+ double normalizedTime;
5394+ double currentTime = step * stepSize;
5395+ double halfway;
54825396
5483- if (pos != std::string::npos) {
5484- easeEnd = easeStart.substr (pos + 1 );
5485- easeStart = easeStart.substr (0 , pos);
5486- }
5397+ std::string easingType;
5398+
5399+ if (easingTypeAtEnd == " null" ) { // use a single interpolation.
5400+ normalizedTime = currentTime;
5401+ easingType = easingTypeAtStart;
5402+ halfway = (step <= numSteps / 2 ) ? end : start;
5403+ }
5404+ else {
5405+ if (step <= numSteps / 2 ) { // use 2 interpolations: start and end.
5406+ normalizedTime = currentTime / 0.5 ;
5407+ easingType = easingTypeAtStart;
5408+ }
5409+ else {
5410+ normalizedTime = (currentTime - 0.5 ) / 0.5 ;
5411+ easingType = easingTypeAtEnd;
5412+ }
5413+ halfway = start + 0.5 * (end - start);
5414+ }
5415+
5416+ double easedTime = getEasedTime (easingType, normalizedTime, 0 , 1 , 1 );
54875417
5488- // Insert animation commands
5489- std::vector<double > interpolatedValues = interpolate (start, end, duration, easeStart, easeEnd);
5418+ double startValue = (step <= numSteps / 2 ) ? start : halfway;
5419+ double endValue = (step <= numSteps / 2 ) ? halfway : end;
5420+ double interpolatedValue = startValue + easedTime * (endValue - startValue);
54905421
5491- // Insert animatedCom and waitCom commands for each interpolated value
5492- for (int value : interpolatedValues) {
5493- animatedVarParams.back () = value;
5422+ animatedVarParams.back () = interpolatedValue;
54945423 animatedCom.parameters = lcf::DBArray<int32_t >(animatedVarParams.begin (), animatedVarParams.end ());
5495- animatedCom.indent = com.indent + 1 ;
54965424
54975425 cmdList.push_back (animatedCom);
54985426 cmdList.push_back (waitCom);
54995427 }
55005428
5501- // Update current_command index and return true to indicate success
55025429 Push (cmdList, 0 , false );
55035430 return true ;
55045431}
0 commit comments