LCOV - code coverage report
Current view: top level - shumate/vector - shumate-vector-expression-interpolate.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 148 192 77.1 %
Date: 2024-05-11 21:41:31 Functions: 12 13 92.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 62 110 56.4 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2021 James Westman <james@jwestman.net>
       3                 :            :  *
       4                 :            :  * This library is free software; you can redistribute it and/or
       5                 :            :  * modify it under the terms of the GNU Lesser General Public
       6                 :            :  * License as published by the Free Software Foundation; either
       7                 :            :  * version 2.1 of the License, or (at your option) any later version.
       8                 :            :  *
       9                 :            :  * This library is distributed in the hope that it will be useful,
      10                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12                 :            :  * Lesser General Public License for more details.
      13                 :            :  *
      14                 :            :  * You should have received a copy of the GNU Lesser General Public
      15                 :            :  * License along with this library; if not, see <https://www.gnu.org/licenses/>.
      16                 :            :  */
      17                 :            : 
      18                 :            : #include "shumate-vector-renderer.h"
      19                 :            : #include "shumate-vector-expression-interpolate-private.h"
      20                 :            : #include "shumate-vector-expression-filter-private.h"
      21                 :            : #include "shumate-vector-utils-private.h"
      22                 :            : 
      23                 :            : typedef struct {
      24                 :            :   double point;
      25                 :            :   ShumateVectorExpression *expr;
      26                 :            : } Stop;
      27                 :            : 
      28                 :            : typedef enum {
      29                 :            :   STEP,
      30                 :            :   LINEAR,
      31                 :            :   EXPONENTIAL,
      32                 :            : } InterpolationType;
      33                 :            : 
      34                 :            : struct _ShumateVectorExpressionInterpolate
      35                 :            : {
      36                 :            :   ShumateVectorExpression parent_instance;
      37                 :            : 
      38                 :            :   ShumateVectorExpression *input;
      39                 :            :   InterpolationType interpolation;
      40                 :            :   double base;
      41                 :            :   GPtrArray *stops;
      42                 :            : };
      43                 :            : 
      44   [ +  +  +  - ]:         36 : G_DEFINE_TYPE (ShumateVectorExpressionInterpolate, shumate_vector_expression_interpolate, SHUMATE_TYPE_VECTOR_EXPRESSION)
      45                 :            : 
      46                 :            : 
      47                 :            : ShumateVectorExpression *
      48                 :          9 : shumate_vector_expression_interpolate_from_json_obj (JsonObject *object, GError **error)
      49                 :            : {
      50                 :          9 :   g_autoptr(ShumateVectorExpressionInterpolate) self = g_object_new (SHUMATE_TYPE_VECTOR_EXPRESSION_INTERPOLATE, NULL);
      51                 :          9 :   JsonNode *stops_node;
      52                 :            : 
      53                 :          9 :   self->interpolation = EXPONENTIAL;
      54                 :          9 :   self->base = json_object_get_double_member_with_default (object, "base", 1.0);
      55                 :            : 
      56         [ +  - ]:          9 :   if ((stops_node = json_object_get_member (object, "stops")))
      57                 :            :     {
      58                 :          9 :       JsonArray *stops;
      59                 :            : 
      60         [ +  - ]:          9 :       if (!shumate_vector_json_get_array (stops_node, &stops, error))
      61                 :          0 :         return NULL;
      62                 :            : 
      63         [ +  + ]:         39 :       for (int i = 0, n = json_array_get_length (stops); i < n; i ++)
      64                 :            :         {
      65                 :         30 :           JsonNode *stop_node = json_array_get_element (stops, i);
      66                 :         30 :           JsonArray *stop_array;
      67                 :         30 :           Stop *stop;
      68                 :         30 :           JsonNode *point_node;
      69                 :         30 :           JsonNode *value_node;
      70                 :         30 :           g_auto(GValue) gvalue = G_VALUE_INIT;
      71                 :         30 :           g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
      72                 :            : 
      73         [ +  - ]:         30 :           if (!shumate_vector_json_get_array (stop_node, &stop_array, error))
      74                 :            :             return NULL;
      75                 :            : 
      76         [ -  + ]:         30 :           if (json_array_get_length (stop_array) != 2)
      77                 :            :             {
      78                 :          0 :               g_set_error (error,
      79                 :            :                            SHUMATE_STYLE_ERROR,
      80                 :            :                            SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
      81                 :            :                            "Expected element of \"stops\" to have exactly 2 elements");
      82                 :          0 :               return NULL;
      83                 :            :             }
      84                 :            : 
      85                 :         30 :           point_node = json_array_get_element (stop_array, 0);
      86                 :         30 :           value_node = json_array_get_element (stop_array, 1);
      87                 :            : 
      88         [ +  - ]:         30 :           if (!JSON_NODE_HOLDS_VALUE (point_node)
      89         [ -  + ]:         30 :               || !g_value_type_transformable (json_node_get_value_type (point_node), G_TYPE_DOUBLE))
      90                 :            :             {
      91                 :          0 :               g_set_error (error,
      92                 :            :                            SHUMATE_STYLE_ERROR,
      93                 :            :                            SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
      94                 :            :                            "Expected element 1 of \"stops\" to be a number");
      95                 :          0 :               return NULL;
      96                 :            :             }
      97                 :            : 
      98         [ -  + ]:         30 :           if (!JSON_NODE_HOLDS_VALUE (value_node))
      99                 :            :             {
     100                 :          0 :               g_set_error (error,
     101                 :            :                            SHUMATE_STYLE_ERROR,
     102                 :            :                            SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     103                 :            :                            "Expected element 2 of \"stops\" to be a literal value");
     104                 :          0 :               return NULL;
     105                 :            :             }
     106                 :            : 
     107                 :         30 :           json_node_get_value (value_node, &gvalue);
     108                 :            : 
     109         [ -  + ]:         30 :           if (!shumate_vector_value_set_from_g_value (&value, &gvalue))
     110                 :            :             {
     111                 :          0 :               g_set_error (error,
     112                 :            :                            SHUMATE_STYLE_ERROR,
     113                 :            :                            SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     114                 :            :                            "Could not parse literal value");
     115                 :          0 :               return NULL;
     116                 :            :             }
     117                 :            : 
     118                 :         30 :           stop = g_new0 (Stop, 1);
     119                 :         30 :           stop->point = json_node_get_double (point_node);
     120                 :         30 :           stop->expr = shumate_vector_expression_filter_from_literal (&value);
     121                 :            : 
     122                 :         30 :           g_ptr_array_add (self->stops, stop);
     123                 :            :         }
     124                 :            :     }
     125                 :            : 
     126                 :            :   return (ShumateVectorExpression *)g_steal_pointer (&self);
     127                 :            : }
     128                 :            : 
     129                 :            : static gboolean
     130                 :         18 : add_stops (ShumateVectorExpressionInterpolate  *self,
     131                 :            :            JsonArray                           *array,
     132                 :            :            int                                  start,
     133                 :            :            ShumateVectorExpressionContext      *ctx,
     134                 :            :            GError                             **error)
     135                 :            : {
     136                 :         18 :   double prev_point;
     137                 :            : 
     138                 :            :   /* Stops */
     139         [ +  + ]:         60 :   for (int i = start, n = json_array_get_length (array); i < n; i += 2)
     140                 :            :     {
     141                 :         42 :       g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
     142                 :         42 :       g_autoptr(ShumateVectorExpression) expr = NULL;
     143                 :         42 :       Stop *stop;
     144                 :         42 :       double point;
     145                 :            : 
     146         [ +  - ]:         42 :       if (!shumate_vector_value_set_from_json_literal (&value, json_array_get_element (array, i), error))
     147                 :            :         return FALSE;
     148                 :            : 
     149         [ -  + ]:         42 :       if (!shumate_vector_value_get_number (&value, &point))
     150                 :            :         {
     151                 :          0 :           g_set_error (error,
     152                 :            :                        SHUMATE_STYLE_ERROR,
     153                 :            :                        SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     154                 :            :                        "Expected stop input to be a number");
     155                 :          0 :           return FALSE;
     156                 :            :         }
     157                 :            : 
     158   [ +  +  -  + ]:         42 :       if (i > start && point <= prev_point)
     159                 :            :         {
     160                 :          0 :           g_set_error (error,
     161                 :            :                        SHUMATE_STYLE_ERROR,
     162                 :            :                        SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     163                 :            :                        "Stop inputs must be in strictly ascending order");
     164                 :          0 :           return FALSE;
     165                 :            :         }
     166                 :         42 :       prev_point = point;
     167                 :            : 
     168                 :         42 :       expr = shumate_vector_expression_filter_from_array_or_literal (
     169                 :         42 :         json_array_get_element (array, i + 1),
     170                 :            :         ctx,
     171                 :            :         error
     172                 :            :       );
     173         [ +  - ]:         42 :       if (!expr)
     174                 :            :         return FALSE;
     175                 :            : 
     176                 :         42 :       stop = g_new0 (Stop, 1);
     177                 :         42 :       stop->point = point;
     178                 :         42 :       stop->expr = g_steal_pointer (&expr);
     179                 :         42 :       g_ptr_array_add (self->stops, stop);
     180                 :            :     }
     181                 :            : 
     182                 :            :   return TRUE;
     183                 :            : }
     184                 :            : 
     185                 :            : ShumateVectorExpression *
     186                 :          6 : shumate_vector_expression_interpolate_from_json_array (JsonArray                       *array,
     187                 :            :                                                        ShumateVectorExpressionContext  *ctx,
     188                 :            :                                                        GError                         **error)
     189                 :            : {
     190                 :          6 :   g_autoptr(ShumateVectorExpressionInterpolate) self = g_object_new (SHUMATE_TYPE_VECTOR_EXPRESSION_INTERPOLATE, NULL);
     191                 :          6 :   JsonArray *interpolation;
     192                 :          6 :   const char *interpolation_type;
     193                 :            : 
     194         [ -  + ]:          6 :   if (json_array_get_length (array) < 5)
     195                 :            :     {
     196                 :          0 :       g_set_error (error,
     197                 :            :                    SHUMATE_STYLE_ERROR,
     198                 :            :                    SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     199                 :            :                    "Operator `interpolate` expected at least 4 arguments");
     200                 :          0 :       return NULL;
     201                 :            :     }
     202                 :            : 
     203         [ -  + ]:          6 :   if (json_array_get_length (array) % 2 == 0)
     204                 :            :     {
     205                 :          0 :       g_set_error (error,
     206                 :            :                    SHUMATE_STYLE_ERROR,
     207                 :            :                    SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     208                 :            :                    "Operator `interpolate` expected an even number of arguments");
     209                 :          0 :       return NULL;
     210                 :            :     }
     211                 :            : 
     212                 :            :   /* Interpolation type */
     213         [ +  - ]:          6 :   if (!shumate_vector_json_get_array (json_array_get_element (array, 1), &interpolation, error))
     214                 :            :     return NULL;
     215                 :            : 
     216         [ -  + ]:          6 :   if (json_array_get_length (interpolation) == 0)
     217                 :            :     {
     218                 :          0 :       g_set_error (error,
     219                 :            :                    SHUMATE_STYLE_ERROR,
     220                 :            :                    SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     221                 :            :                    "Expected an interpolation type");
     222                 :          0 :       return NULL;
     223                 :            :     }
     224                 :            : 
     225         [ +  - ]:          6 :   if (!shumate_vector_json_get_string (json_array_get_element (interpolation, 0), &interpolation_type, error))
     226                 :            :     return NULL;
     227                 :            : 
     228         [ +  - ]:          6 :   if (g_strcmp0 ("linear", interpolation_type) == 0)
     229                 :            :     {
     230         [ -  + ]:          6 :       if (json_array_get_length (interpolation) != 1)
     231                 :            :         {
     232                 :          0 :           g_set_error (error,
     233                 :            :                        SHUMATE_STYLE_ERROR,
     234                 :            :                        SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     235                 :            :                        "Interpolation type `linear` expected 0 arguments");
     236                 :          0 :           return NULL;
     237                 :            :         }
     238                 :            : 
     239                 :          6 :       self->interpolation = LINEAR;
     240                 :            :     }
     241         [ #  # ]:          0 :   else if (g_strcmp0 ("exponential", interpolation_type) == 0)
     242                 :            :     {
     243                 :          0 :       g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
     244                 :            : 
     245         [ #  # ]:          0 :       if (json_array_get_length (interpolation) != 2)
     246                 :            :         {
     247                 :          0 :           g_set_error (error,
     248                 :            :                        SHUMATE_STYLE_ERROR,
     249                 :            :                        SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     250                 :            :                        "Interpolation type `exponential` expected 1 argument");
     251                 :          0 :           return NULL;
     252                 :            :         }
     253                 :            : 
     254         [ #  # ]:          0 :       if (!shumate_vector_value_set_from_json_literal (&value, json_array_get_element (interpolation, 1), error))
     255                 :            :         return NULL;
     256                 :            : 
     257                 :          0 :       self->interpolation = EXPONENTIAL;
     258         [ #  # ]:          0 :       if (!shumate_vector_value_get_number (&value, &self->base))
     259                 :            :         {
     260                 :          0 :           g_set_error (error,
     261                 :            :                        SHUMATE_STYLE_ERROR,
     262                 :            :                        SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     263                 :            :                        "Expected argument of `exponential` to be a number");
     264                 :          0 :           return NULL;
     265                 :            :         }
     266                 :            :     }
     267                 :            :   else
     268                 :            :     {
     269                 :          0 :       g_set_error (error,
     270                 :            :                    SHUMATE_STYLE_ERROR,
     271                 :            :                    SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     272                 :            :                    "Unknown interpolation type `%s`",
     273                 :            :                    interpolation_type);
     274                 :            :     }
     275                 :            : 
     276                 :            :   /* Input */
     277                 :          6 :   self->input = shumate_vector_expression_filter_from_array_or_literal (
     278                 :            :     json_array_get_element (array, 2),
     279                 :            :     ctx,
     280                 :            :     error
     281                 :            :   );
     282         [ +  - ]:          6 :   if (!self->input)
     283                 :            :     return NULL;
     284                 :            : 
     285                 :            :   /* Stops */
     286         [ -  + ]:          6 :   if (!add_stops (self, array, 3, ctx, error))
     287                 :            :     return NULL;
     288                 :            : 
     289                 :            :   return (ShumateVectorExpression *)g_steal_pointer (&self);
     290                 :            : }
     291                 :            : 
     292                 :            : ShumateVectorExpression *
     293                 :         12 : shumate_vector_expression_step_from_json_array (JsonArray                       *array,
     294                 :            :                                                 ShumateVectorExpressionContext  *ctx,
     295                 :            :                                                 GError                         **error)
     296                 :            : {
     297                 :         12 :   g_autoptr(ShumateVectorExpressionInterpolate) self = g_object_new (SHUMATE_TYPE_VECTOR_EXPRESSION_INTERPOLATE, NULL);
     298                 :         12 :   Stop *stop;
     299                 :            : 
     300                 :         12 :   self->interpolation = STEP;
     301                 :            : 
     302         [ -  + ]:         12 :   if (json_array_get_length (array) < 5)
     303                 :            :     {
     304                 :          0 :       g_set_error (error,
     305                 :            :                    SHUMATE_STYLE_ERROR,
     306                 :            :                    SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     307                 :            :                    "Operator `interpolate` expected at least 4 arguments");
     308                 :          0 :       return NULL;
     309                 :            :     }
     310                 :            : 
     311         [ -  + ]:         12 :   if (json_array_get_length (array) % 2 == 0)
     312                 :            :     {
     313                 :          0 :       g_set_error (error,
     314                 :            :                    SHUMATE_STYLE_ERROR,
     315                 :            :                    SHUMATE_STYLE_ERROR_INVALID_EXPRESSION,
     316                 :            :                    "Operator `interpolate` expected an even number of arguments");
     317                 :          0 :       return NULL;
     318                 :            :     }
     319                 :            : 
     320                 :            :   /* Input */
     321                 :         12 :   self->input = shumate_vector_expression_filter_from_array_or_literal (
     322                 :            :     json_array_get_element (array, 1),
     323                 :            :     ctx,
     324                 :            :     error
     325                 :            :   );
     326         [ +  - ]:         12 :   if (!self->input)
     327                 :            :     return NULL;
     328                 :            : 
     329                 :            :   /* First stop */
     330                 :         12 :   stop = g_new0 (Stop, 1);
     331                 :         12 :   g_ptr_array_add (self->stops, stop);
     332                 :         12 :   stop->point = -G_MAXDOUBLE;
     333                 :         12 :   stop->expr = shumate_vector_expression_filter_from_array_or_literal (
     334                 :            :     json_array_get_element (array, 2),
     335                 :            :     ctx,
     336                 :            :     error
     337                 :            :   );
     338         [ +  - ]:         12 :   if (!stop->expr)
     339                 :            :     return NULL;
     340                 :            : 
     341                 :            :   /* Stops */
     342         [ -  + ]:         12 :   if (!add_stops (self, array, 3, ctx, error))
     343                 :            :     return NULL;
     344                 :            : 
     345                 :            :   return (ShumateVectorExpression *)g_steal_pointer (&self);
     346                 :            : }
     347                 :            : 
     348                 :            : 
     349                 :            : static void
     350                 :         84 : stop_free (Stop *stop)
     351                 :            : {
     352         [ +  - ]:         84 :   g_clear_object (&stop->expr);
     353                 :         84 :   g_free (stop);
     354                 :         84 : }
     355                 :            : 
     356                 :            : 
     357                 :            : static double
     358                 :         42 : lerp_double (double a, double b, double pos)
     359                 :            : {
     360                 :         42 :   return (b - a) * pos + a;
     361                 :            : }
     362                 :            : 
     363                 :            : 
     364                 :            : static void
     365                 :         42 : lerp (ShumateVectorValue *last_value, ShumateVectorValue *next_value, double pos, ShumateVectorValue *out)
     366                 :            : {
     367                 :         42 :   gdouble last_double, next_double;
     368                 :         42 :   GdkRGBA last_color, next_color;
     369                 :            : 
     370         [ +  + ]:         42 :   if (shumate_vector_value_get_number (last_value, &last_double)
     371         [ +  - ]:         30 :       && shumate_vector_value_get_number (next_value, &next_double))
     372                 :         30 :     shumate_vector_value_set_number (out, lerp_double (last_double, next_double, pos));
     373         [ +  - ]:         12 :   else if (shumate_vector_value_get_color (last_value, &last_color)
     374         [ +  - ]:         12 :       && shumate_vector_value_get_color (next_value, &next_color))
     375                 :         12 :     {
     376                 :         12 :       GdkRGBA color = {
     377                 :         12 :         .red = lerp_double (last_color.red, next_color.red, pos),
     378                 :         12 :         .green = lerp_double (last_color.green, next_color.green, pos),
     379                 :         12 :         .blue = lerp_double (last_color.blue, next_color.blue, pos),
     380                 :         12 :         .alpha = lerp_double (last_color.alpha, next_color.alpha, pos),
     381                 :            :       };
     382                 :         12 :       shumate_vector_value_set_color (out, &color);
     383                 :            :     }
     384                 :            :   else
     385                 :          0 :     shumate_vector_value_steal (last_value, out);
     386                 :         42 : }
     387                 :            : 
     388                 :            : 
     389                 :            : static void
     390                 :          0 : exp_interp (double last_point,
     391                 :            :             double next_point,
     392                 :            :             ShumateVectorValue *last_value,
     393                 :            :             ShumateVectorValue *next_value,
     394                 :            :             double input,
     395                 :            :             double base,
     396                 :            :             ShumateVectorValue *dest)
     397                 :            : {
     398                 :          0 :   double diff = next_point - last_point;
     399                 :          0 :   double pos = input - last_point;
     400                 :            : 
     401                 :          0 :   lerp (last_value, next_value, (pow (base, pos) - 1.0) / (pow (base, diff) - 1.0), dest);
     402                 :          0 : }
     403                 :            : 
     404                 :            : 
     405                 :            : static void
     406                 :         27 : shumate_vector_expression_interpolate_finalize (GObject *object)
     407                 :            : {
     408                 :         27 :   ShumateVectorExpressionInterpolate *self = (ShumateVectorExpressionInterpolate *)object;
     409                 :            : 
     410         [ +  + ]:         27 :   g_clear_object (&self->input);
     411         [ +  - ]:         27 :   g_clear_pointer (&self->stops, g_ptr_array_unref);
     412                 :            : 
     413                 :         27 :   G_OBJECT_CLASS (shumate_vector_expression_interpolate_parent_class)->finalize (object);
     414                 :         27 : }
     415                 :            : 
     416                 :            : 
     417                 :            : static gboolean
     418                 :         78 : shumate_vector_expression_interpolate_eval (ShumateVectorExpression  *expr,
     419                 :            :                                             ShumateVectorRenderScope *scope,
     420                 :            :                                             ShumateVectorValue       *out)
     421                 :            : {
     422                 :         78 :   ShumateVectorExpressionInterpolate *self = (ShumateVectorExpressionInterpolate *)expr;
     423                 :        156 :   g_auto(ShumateVectorValue) value = SHUMATE_VECTOR_VALUE_INIT;
     424                 :         78 :   double input;
     425                 :         78 :   Stop **stops = (Stop **)self->stops->pdata;
     426                 :         78 :   guint n_stops = self->stops->len;
     427                 :            : 
     428         [ -  + ]:         78 :   if (n_stops == 0)
     429                 :            :     return FALSE;
     430                 :            : 
     431         [ +  + ]:         78 :   if (self->input != NULL)
     432                 :            :     {
     433         [ -  + ]:         45 :       if (!shumate_vector_expression_eval (self->input, scope, &value))
     434                 :            :         return FALSE;
     435         [ -  + ]:         45 :       if (!shumate_vector_value_get_number (&value, &input))
     436                 :            :         return FALSE;
     437                 :            :     }
     438                 :            :   else
     439                 :         33 :     input = scope->zoom_level;
     440                 :            : 
     441         [ +  + ]:         78 :   if (input < stops[0]->point)
     442                 :          6 :     return shumate_vector_expression_eval (stops[0]->expr, scope, out);
     443                 :            : 
     444         [ +  + ]:        159 :   for (int i = 1; i < n_stops; i ++)
     445                 :            :     {
     446                 :        135 :       Stop *last = stops[i - 1];
     447                 :        135 :       Stop *next = stops[i];
     448   [ +  -  +  + ]:        135 :       if (last->point <= input && input < next->point)
     449                 :            :         {
     450                 :         48 :           double pos_norm = (input - last->point) / (next->point - last->point);
     451                 :         48 :           g_auto(ShumateVectorValue) last_value = SHUMATE_VECTOR_VALUE_INIT;
     452                 :         48 :           g_auto(ShumateVectorValue) next_value = SHUMATE_VECTOR_VALUE_INIT;
     453                 :            : 
     454         [ +  - ]:         48 :           if (!shumate_vector_expression_eval (last->expr, scope, &last_value))
     455                 :            :             return FALSE;
     456         [ +  - ]:         48 :           if (!shumate_vector_expression_eval (next->expr, scope, &next_value))
     457                 :            :             return FALSE;
     458                 :            : 
     459   [ +  +  +  - ]:         48 :           switch (self->interpolation)
     460                 :            :             {
     461                 :          6 :               case STEP:
     462                 :          6 :                 shumate_vector_value_steal (&last_value, out);
     463                 :          6 :                 return TRUE;
     464                 :         21 :               case LINEAR:
     465                 :         21 :                 lerp (&last_value, &next_value, pos_norm, out);
     466                 :         21 :                 return TRUE;
     467                 :         21 :               case EXPONENTIAL:
     468         [ +  - ]:         21 :                 if (self->base == 1.0)
     469                 :         21 :                   lerp (&last_value, &next_value, pos_norm, out);
     470                 :            :                 else
     471                 :          0 :                   exp_interp (last->point, next->point, &last_value, &next_value, input, self->base, out);
     472                 :         21 :                 return TRUE;
     473                 :          0 :               default:
     474                 :         48 :                 g_assert_not_reached ();
     475                 :            :             }
     476                 :            :         }
     477                 :            :     }
     478                 :            : 
     479                 :         24 :   return shumate_vector_expression_eval (stops[n_stops - 1]->expr, scope, out);
     480                 :            : }
     481                 :            : 
     482                 :            : 
     483                 :            : static void
     484                 :          3 : shumate_vector_expression_interpolate_class_init (ShumateVectorExpressionInterpolateClass *klass)
     485                 :            : {
     486                 :          3 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     487                 :          3 :   ShumateVectorExpressionClass *expr_class = SHUMATE_VECTOR_EXPRESSION_CLASS (klass);
     488                 :            : 
     489                 :          3 :   object_class->finalize = shumate_vector_expression_interpolate_finalize;
     490                 :          3 :   expr_class->eval = shumate_vector_expression_interpolate_eval;
     491                 :            : }
     492                 :            : 
     493                 :            : static void
     494                 :         27 : shumate_vector_expression_interpolate_init (ShumateVectorExpressionInterpolate *self)
     495                 :            : {
     496                 :         27 :   self->stops = g_ptr_array_new_with_free_func ((GDestroyNotify) stop_free);
     497                 :         27 : }

Generated by: LCOV version 1.14