• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.internal.widget.remotecompose.core.operations.utilities;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 
21 import com.android.internal.widget.remotecompose.core.operations.utilities.easing.MonotonicSpline;
22 
23 import java.util.Random;
24 
25 /** high performance floating point expression evaluator used in animation */
26 public class AnimatedFloatExpression {
27     @NonNull static IntMap<String> sNames = new IntMap<>();
28 
29     /** The START POINT in the float NaN space for operators */
30     public static final int OFFSET = 0x310_000;
31 
32     /** ADD operator */
33     public static final float ADD = asNan(OFFSET + 1);
34 
35     /** SUB operator */
36     public static final float SUB = asNan(OFFSET + 2);
37 
38     /** MUL operator */
39     public static final float MUL = asNan(OFFSET + 3);
40 
41     /** DIV operator */
42     public static final float DIV = asNan(OFFSET + 4);
43 
44     /** MOD operator */
45     public static final float MOD = asNan(OFFSET + 5);
46 
47     /** MIN operator */
48     public static final float MIN = asNan(OFFSET + 6);
49 
50     /** MAX operator */
51     public static final float MAX = asNan(OFFSET + 7);
52 
53     /** POW operator */
54     public static final float POW = asNan(OFFSET + 8);
55 
56     /** SQRT operator */
57     public static final float SQRT = asNan(OFFSET + 9);
58 
59     /** ABS operator */
60     public static final float ABS = asNan(OFFSET + 10);
61 
62     /** SIGN operator */
63     public static final float SIGN = asNan(OFFSET + 11);
64 
65     /** COPY_SIGN operator */
66     public static final float COPY_SIGN = asNan(OFFSET + 12);
67 
68     /** EXP operator */
69     public static final float EXP = asNan(OFFSET + 13);
70 
71     /** FLOOR operator */
72     public static final float FLOOR = asNan(OFFSET + 14);
73 
74     /** LOG operator */
75     public static final float LOG = asNan(OFFSET + 15);
76 
77     /** LN operator */
78     public static final float LN = asNan(OFFSET + 16);
79 
80     /** ROUND operator */
81     public static final float ROUND = asNan(OFFSET + 17);
82 
83     /** SIN operator */
84     public static final float SIN = asNan(OFFSET + 18);
85 
86     /** COS operator */
87     public static final float COS = asNan(OFFSET + 19);
88 
89     /** TAN operator */
90     public static final float TAN = asNan(OFFSET + 20);
91 
92     /** ASIN operator */
93     public static final float ASIN = asNan(OFFSET + 21);
94 
95     /** ACOS operator */
96     public static final float ACOS = asNan(OFFSET + 22);
97 
98     /** ATAN operator */
99     public static final float ATAN = asNan(OFFSET + 23);
100 
101     /** ATAN2 operator */
102     public static final float ATAN2 = asNan(OFFSET + 24);
103 
104     /** MAD operator */
105     public static final float MAD = asNan(OFFSET + 25);
106 
107     /** IFELSE operator */
108     public static final float IFELSE = asNan(OFFSET + 26);
109 
110     /** CLAMP operator */
111     public static final float CLAMP = asNan(OFFSET + 27);
112 
113     /** CBRT operator */
114     public static final float CBRT = asNan(OFFSET + 28);
115 
116     /** DEG operator */
117     public static final float DEG = asNan(OFFSET + 29);
118 
119     /** RAD operator */
120     public static final float RAD = asNan(OFFSET + 30);
121 
122     /** CEIL operator */
123     public static final float CEIL = asNan(OFFSET + 31);
124 
125     // Array ops
126     /** A DEREF operator */
127     public static final float A_DEREF = asNan(OFFSET + 32);
128 
129     /** Array MAX operator */
130     public static final float A_MAX = asNan(OFFSET + 33);
131 
132     /** Array MIN operator */
133     public static final float A_MIN = asNan(OFFSET + 34);
134 
135     /** A_SUM operator */
136     public static final float A_SUM = asNan(OFFSET + 35);
137 
138     /** A_AVG operator */
139     public static final float A_AVG = asNan(OFFSET + 36);
140 
141     /** A_LEN operator */
142     public static final float A_LEN = asNan(OFFSET + 37);
143 
144     /** A_SPLINE operator */
145     public static final float A_SPLINE = asNan(OFFSET + 38);
146 
147     /** RAND Random number 0..1 */
148     public static final float RAND = asNan(OFFSET + 39);
149 
150     /** RAND_SEED operator */
151     public static final float RAND_SEED = asNan(OFFSET + 40);
152 
153     /** NOISE_FROM operator calculate a random 0..1 number based on a seed */
154     public static final float NOISE_FROM = asNan(OFFSET + 41);
155 
156     /** RANDOM_IN_RANGE random number in range */
157     public static final float RAND_IN_RANGE = asNan(OFFSET + 42);
158 
159     /** SQUARE_SUM the sum of the square of two numbers */
160     public static final float SQUARE_SUM = asNan(OFFSET + 43);
161 
162     /** STEP x > edge ? 1 : 0; */
163     public static final float STEP = asNan(OFFSET + 44);
164 
165     /** SQUARE x*x; */
166     public static final float SQUARE = asNan(OFFSET + 45);
167 
168     /** DUP x,x; */
169     public static final float DUP = asNan(OFFSET + 46);
170 
171     /** HYPOT sqrt(x*x+y*y); */
172     public static final float HYPOT = asNan(OFFSET + 47);
173 
174     /** SWAP y,x; */
175     public static final float SWAP = asNan(OFFSET + 48);
176 
177     /** LERP (1-t)*x+t*y; */
178     public static final float LERP = asNan(OFFSET + 49);
179 
180     /** SMOOTH_STEP (1-smoothstep(edge0,edge1,x)); */
181     public static final float SMOOTH_STEP = asNan(OFFSET + 50);
182 
183     /** LAST valid operator */
184     public static final int LAST_OP = OFFSET + 50;
185 
186     /** VAR1 operator */
187     public static final float VAR1 = asNan(OFFSET + 51);
188 
189     /** VAR2 operator */
190     public static final float VAR2 = asNan(OFFSET + 52);
191 
192     /** VAR2 operator */
193     public static final float VAR3 = asNan(OFFSET + 53);
194 
195     // TODO SQUARE, DUP, HYPOT, SWAP
196     //    private static final float FP_PI = (float) Math.PI;
197     private static final float FP_TO_RAD = 57.29578f; // 180/PI
198     private static final float FP_TO_DEG = 0.017453292f; // 180/PI
199 
200     @NonNull float[] mStack = new float[0];
201     @NonNull float[] mLocalStack = new float[128];
202     @NonNull float[] mVar = new float[0];
203     @Nullable CollectionsAccess mCollectionsAccess;
204     IntMap<MonotonicSpline> mSplineMap = new IntMap<>();
205     private static Random sRandom;
206 
getSplineValue(int arrayId, float pos)207     private float getSplineValue(int arrayId, float pos) {
208         MonotonicSpline fit = mSplineMap.get(arrayId);
209         float[] f = mCollectionsAccess.getFloats(arrayId);
210         if (fit != null) {
211             if (fit.getArray() == f) { // the array has not changed.
212                 return fit.getPos(pos);
213             }
214         }
215 
216         fit = new MonotonicSpline(null, f);
217         mSplineMap.put(arrayId, fit);
218         return fit.getPos(pos);
219     }
220 
221     /**
222      * is float a math operator
223      *
224      * @param v
225      * @return
226      */
isMathOperator(float v)227     public static boolean isMathOperator(float v) {
228         if (Float.isNaN(v)) {
229             int pos = fromNaN(v);
230             // a data variable is a type of math operator for expressions
231             // it dereference to a value
232             if (NanMap.isDataVariable(v)) {
233                 return false;
234             }
235             return pos > OFFSET && pos <= LAST_OP;
236         }
237         return false;
238     }
239 
240     interface Op {
eval(int sp)241         int eval(int sp);
242     }
243 
244     /**
245      * Evaluate a float expression This system works by processing an Array of float (float[]) in
246      * reverse polish notation (rpn) Within that array some floats are commands they are encoded
247      * within an NaN. After processing the array the last item on the array is returned. The system
248      * supports variables allowing expressions like. sin(sqrt(x*x+y*y))/sqrt(x*x+y*y) Where x & y
249      * are passe as parameters Examples: (1+2) (1, 2, ADD) adds two numbers returns 3 eval(new
250      * float[]{ Var1, Var * }
251      *
252      * @param exp
253      * @param var
254      * @return
255      */
eval(@onNull float[] exp, @NonNull float... var)256     public float eval(@NonNull float[] exp, @NonNull float... var) {
257         mStack = exp;
258         mVar = var;
259         int sp = -1;
260         for (int i = 0; i < mStack.length; i++) {
261             float v = mStack[i];
262             if (Float.isNaN(v)) {
263                 sp = opEval(sp, fromNaN(v));
264             } else {
265                 mStack[++sp] = v;
266             }
267         }
268         return mStack[sp];
269     }
270 
271     /**
272      * Evaluate a float expression
273      *
274      * @param ca Access to float array collections
275      * @param exp the expressions
276      * @param len the length of the expression array
277      * @param var variables if the expression contains VAR tags
278      * @return the value the expression evaluated to
279      */
eval( @onNull CollectionsAccess ca, @NonNull float[] exp, int len, @NonNull float... var)280     public float eval(
281             @NonNull CollectionsAccess ca, @NonNull float[] exp, int len, @NonNull float... var) {
282         System.arraycopy(exp, 0, mLocalStack, 0, len);
283         mStack = mLocalStack;
284         mVar = var;
285         mCollectionsAccess = ca;
286         int sp = -1;
287 
288         for (int i = 0; i < mStack.length; i++) {
289             float v = mStack[i];
290             if (Float.isNaN(v)) {
291                 int id = fromNaN(v);
292                 if ((id & NanMap.ID_REGION_MASK) != NanMap.ID_REGION_ARRAY) {
293                     sp = opEval(sp, id);
294                 } else {
295                     mStack[++sp] = v;
296                 }
297             } else {
298                 mStack[++sp] = v;
299             }
300         }
301         return mStack[sp];
302     }
303 
304     /**
305      * Evaluate a float expression
306      *
307      * @param ca The access to float arrays
308      * @param exp the expression
309      * @param len the length of the expression sections
310      * @return the value the expression evaluated to
311      */
eval(@onNull CollectionsAccess ca, @NonNull float[] exp, int len)312     public float eval(@NonNull CollectionsAccess ca, @NonNull float[] exp, int len) {
313         System.arraycopy(exp, 0, mLocalStack, 0, len);
314         mStack = mLocalStack;
315         mCollectionsAccess = ca;
316         int sp = -1;
317 
318         for (int i = 0; i < len; i++) {
319             float v = mStack[i];
320             if (Float.isNaN(v)) {
321                 int id = fromNaN(v);
322                 if ((id & NanMap.ID_REGION_MASK) != NanMap.ID_REGION_ARRAY) {
323                     sp = opEval(sp, id);
324                 } else {
325                     mStack[++sp] = v;
326                 }
327             } else {
328                 mStack[++sp] = v;
329             }
330         }
331         return mStack[sp];
332     }
333 
dereference(@onNull CollectionsAccess ca, int id, int sp)334     private int dereference(@NonNull CollectionsAccess ca, int id, int sp) {
335         mStack[sp] = ca.getFloatValue(id, (int) (mStack[sp]));
336         return sp;
337     }
338 
339     /**
340      * Evaluate a float expression
341      *
342      * @param exp
343      * @param len
344      * @param var
345      * @return
346      */
eval(@onNull float[] exp, int len, @NonNull float... var)347     public float eval(@NonNull float[] exp, int len, @NonNull float... var) {
348         System.arraycopy(exp, 0, mLocalStack, 0, len);
349         mStack = mLocalStack;
350         mVar = var;
351         int sp = -1;
352 
353         for (int i = 0; i < len; i++) {
354             float v = mStack[i];
355             if (Float.isNaN(v)) {
356                 sp = opEval(sp, fromNaN(v));
357             } else {
358                 mStack[++sp] = v;
359             }
360         }
361         return mStack[sp];
362     }
363 
364     /**
365      * Evaluate a float expression
366      *
367      * @param exp
368      * @param var
369      * @return
370      */
evalDB(@onNull float[] exp, @NonNull float... var)371     public float evalDB(@NonNull float[] exp, @NonNull float... var) {
372         mStack = exp;
373         mVar = var;
374         int sp = -1;
375 
376         for (float v : exp) {
377             if (Float.isNaN(v)) {
378                 sp = opEval(sp, fromNaN(v));
379             } else {
380                 System.out.print(" " + v);
381                 mStack[++sp] = v;
382             }
383         }
384         return mStack[sp];
385     }
386 
387     static {
388         int k = 0;
389         sNames.put(k++, "NOP");
390         sNames.put(k++, "+");
391         sNames.put(k++, "-");
392         sNames.put(k++, "*");
393         sNames.put(k++, "/");
394         sNames.put(k++, "%");
395         sNames.put(k++, "min");
396         sNames.put(k++, "max");
397         sNames.put(k++, "pow");
398         sNames.put(k++, "sqrt");
399         sNames.put(k++, "abs");
400         sNames.put(k++, "sign");
401         sNames.put(k++, "copySign");
402         sNames.put(k++, "exp");
403         sNames.put(k++, "floor");
404         sNames.put(k++, "log");
405         sNames.put(k++, "ln");
406         sNames.put(k++, "round");
407         sNames.put(k++, "sin");
408         sNames.put(k++, "cos");
409         sNames.put(k++, "tan");
410         sNames.put(k++, "asin");
411         sNames.put(k++, "acos");
412         sNames.put(k++, "atan");
413         sNames.put(k++, "atan2");
414         sNames.put(k++, "mad");
415         sNames.put(k++, "ifElse");
416         sNames.put(k++, "clamp");
417         sNames.put(k++, "cbrt");
418         sNames.put(k++, "deg");
419         sNames.put(k++, "rad");
420         sNames.put(k++, "ceil");
421 
422         sNames.put(k++, "A_DEREF");
423         sNames.put(k++, "A_MAX");
424         sNames.put(k++, "A_MIN");
425         sNames.put(k++, "A_SUM");
426         sNames.put(k++, "A_AVG");
427         sNames.put(k++, "A_LEN");
428         sNames.put(k++, "A_SPLINE");
429         sNames.put(k++, "RAND");
430         sNames.put(k++, "RAND_SEED");
431 
432         sNames.put(k++, "noise_from");
433         sNames.put(k++, "rand_in_range");
434         sNames.put(k++, "square_sum");
435         sNames.put(k++, "step");
436         sNames.put(k++, "square");
437         sNames.put(k++, "dup");
438         sNames.put(k++, "hypot");
439         sNames.put(k++, "swap");
440         sNames.put(k++, "lerp");
441         sNames.put(k++, "smooth_step");
442 
443         sNames.put(k++, "a[0]");
444         sNames.put(k++, "a[1]");
445         sNames.put(k++, "a[2]");
446     }
447 
448     /**
449      * given a float command return its math name (e.g sin, cos etc.)
450      *
451      * @param f
452      * @return
453      */
454     @Nullable
toMathName(float f)455     public static String toMathName(float f) {
456         int id = fromNaN(f) - OFFSET;
457         return sNames.get(id);
458     }
459 
460     /**
461      * Convert an expression encoded as an array of floats int ot a string
462      *
463      * @param exp
464      * @param labels
465      * @return
466      */
467     @NonNull
toString(@onNull float[] exp, @Nullable String[] labels)468     public static String toString(@NonNull float[] exp, @Nullable String[] labels) {
469         StringBuilder s = new StringBuilder();
470         for (int i = 0; i < exp.length; i++) {
471             float v = exp[i];
472             if (Float.isNaN(v)) {
473                 if (isMathOperator(v)) {
474                     s.append(toMathName(v));
475                 } else {
476                     int id = fromNaN(v);
477                     String idString =
478                             (id > NanMap.ID_REGION_ARRAY) ? ("A_" + (id & 0xFFFFF)) : "" + id;
479                     s.append("[");
480                     s.append(idString);
481                     s.append("]");
482                 }
483             } else {
484                 if (labels != null && labels[i] != null) {
485                     s.append(labels[i]);
486                     if (!labels[i].contains("_")) {
487                         s.append(v);
488                     }
489                 } else {
490                     s.append(v);
491                 }
492             }
493             s.append(" ");
494         }
495         return s.toString();
496     }
497 
toString(@onNull float[] exp, int sp)498     static String toString(@NonNull float[] exp, int sp) {
499         //        String[] str = new String[exp.length];
500         if (Float.isNaN(exp[sp])) {
501             int id = fromNaN(exp[sp]) - OFFSET;
502             switch (NO_OF_OPS[id]) {
503                 case -1:
504                     return "nop";
505                 case 1:
506                     return sNames.get(id) + "(" + toString(exp, sp + 1) + ") ";
507                 case 2:
508                     if (infix(id)) {
509                         return "("
510                                 + toString(exp, sp + 1)
511                                 + sNames.get(id)
512                                 + " "
513                                 + toString(exp, sp + 2)
514                                 + ") ";
515                     } else {
516                         return sNames.get(id)
517                                 + "("
518                                 + toString(exp, sp + 1)
519                                 + ", "
520                                 + toString(exp, sp + 2)
521                                 + ")";
522                     }
523                 case 3:
524                     if (infix(id)) {
525                         return "(("
526                                 + toString(exp, sp + 1)
527                                 + ") ? "
528                                 + toString(exp, sp + 2)
529                                 + ":"
530                                 + toString(exp, sp + 3)
531                                 + ")";
532                     } else {
533                         return sNames.get(id)
534                                 + "("
535                                 + toString(exp, sp + 1)
536                                 + ", "
537                                 + toString(exp, sp + 2)
538                                 + ", "
539                                 + toString(exp, sp + 3)
540                                 + ")";
541                     }
542             }
543         }
544         return Float.toString(exp[sp]);
545     }
546 
547     static final int[] NO_OF_OPS = {
548         -1, // no op
549         2,
550         2,
551         2,
552         2,
553         2, // + - * / %
554         2,
555         2,
556         2, // min max, power
557         1,
558         1,
559         1,
560         1,
561         1,
562         1,
563         1,
564         1, // sqrt,abs,CopySign,exp,floor,log,ln
565         1,
566         1,
567         1,
568         1,
569         1,
570         1,
571         1,
572         2, // round,sin,cos,tan,asin,acos,atan,atan2
573         3,
574         3,
575         3,
576         1,
577         1,
578         1,
579         1,
580         0,
581         0,
582         0 // mad, ?:,
583         // a[0],a[1],a[2]
584     };
585 
586     /**
587      * to be used by parser to determine if command is infix
588      *
589      * @param n
590      * @return
591      */
infix(int n)592     static boolean infix(int n) {
593         return ((n < 6) || (n == 25) || (n == 26));
594     }
595 
596     /**
597      * Convert an id into a NaN object
598      *
599      * @param v
600      * @return
601      */
asNan(int v)602     public static float asNan(int v) {
603         return Float.intBitsToFloat(v | -0x800000);
604     }
605 
606     /**
607      * Get ID from a NaN float
608      *
609      * @param v
610      * @return
611      */
fromNaN(float v)612     public static int fromNaN(float v) {
613         int b = Float.floatToRawIntBits(v);
614         return b & 0x7FFFFF;
615     }
616 
617     // ================= New approach ========
618     private static final int OP_ADD = OFFSET + 1;
619     private static final int OP_SUB = OFFSET + 2;
620     private static final int OP_MUL = OFFSET + 3;
621     private static final int OP_DIV = OFFSET + 4;
622     private static final int OP_MOD = OFFSET + 5;
623     private static final int OP_MIN = OFFSET + 6;
624     private static final int OP_MAX = OFFSET + 7;
625     private static final int OP_POW = OFFSET + 8;
626     private static final int OP_SQRT = OFFSET + 9;
627     private static final int OP_ABS = OFFSET + 10;
628     private static final int OP_SIGN = OFFSET + 11;
629     private static final int OP_COPY_SIGN = OFFSET + 12;
630     private static final int OP_EXP = OFFSET + 13;
631     private static final int OP_FLOOR = OFFSET + 14;
632     private static final int OP_LOG = OFFSET + 15;
633     private static final int OP_LN = OFFSET + 16;
634     private static final int OP_ROUND = OFFSET + 17;
635     private static final int OP_SIN = OFFSET + 18;
636     private static final int OP_COS = OFFSET + 19;
637     private static final int OP_TAN = OFFSET + 20;
638     private static final int OP_ASIN = OFFSET + 21;
639     private static final int OP_ACOS = OFFSET + 22;
640     private static final int OP_ATAN = OFFSET + 23;
641     private static final int OP_ATAN2 = OFFSET + 24;
642     private static final int OP_MAD = OFFSET + 25;
643     private static final int OP_TERNARY_CONDITIONAL = OFFSET + 26;
644     private static final int OP_CLAMP = OFFSET + 27;
645     private static final int OP_CBRT = OFFSET + 28;
646     private static final int OP_DEG = OFFSET + 29;
647     private static final int OP_RAD = OFFSET + 30;
648     private static final int OP_CEIL = OFFSET + 31;
649     private static final int OP_A_DEREF = OFFSET + 32;
650     private static final int OP_A_MAX = OFFSET + 33;
651     private static final int OP_A_MIN = OFFSET + 34;
652     private static final int OP_A_SUM = OFFSET + 35;
653     private static final int OP_A_AVG = OFFSET + 36;
654     private static final int OP_A_LEN = OFFSET + 37;
655     private static final int OP_A_SPLINE = OFFSET + 38;
656     private static final int OP_RAND = OFFSET + 39;
657     private static final int OP_RAND_SEED = OFFSET + 40;
658 
659     private static final int OP_NOISE_FROM = OFFSET + 41;
660     private static final int OP_RAND_IN_RANGE = OFFSET + 42;
661     private static final int OP_SQUARE_SUM = OFFSET + 43;
662     private static final int OP_STEP = OFFSET + 44;
663     private static final int OP_SQUARE = OFFSET + 45;
664     private static final int OP_DUP = OFFSET + 46;
665     private static final int OP_HYPOT = OFFSET + 47;
666     private static final int OP_SWAP = OFFSET + 48;
667     private static final int OP_LERP = OFFSET + 49;
668     private static final int OP_SMOOTH_STEP = OFFSET + 50;
669 
670     private static final int OP_FIRST_VAR = OFFSET + 51;
671     private static final int OP_SECOND_VAR = OFFSET + 52;
672     private static final int OP_THIRD_VAR = OFFSET + 53;
673 
opEval(int sp, int id)674     int opEval(int sp, int id) {
675         float[] array;
676 
677         switch (id) {
678             case OP_ADD:
679                 mStack[sp - 1] = mStack[sp - 1] + mStack[sp];
680                 return sp - 1;
681 
682             case OP_SUB:
683                 mStack[sp - 1] = mStack[sp - 1] - mStack[sp];
684                 return sp - 1;
685 
686             case OP_MUL:
687                 mStack[sp - 1] = mStack[sp - 1] * mStack[sp];
688                 return sp - 1;
689 
690             case OP_DIV:
691                 mStack[sp - 1] = mStack[sp - 1] / mStack[sp];
692                 return sp - 1;
693 
694             case OP_MOD:
695                 mStack[sp - 1] = mStack[sp - 1] % mStack[sp];
696                 return sp - 1;
697 
698             case OP_MIN:
699                 mStack[sp - 1] = (float) Math.min(mStack[sp - 1], mStack[sp]);
700                 return sp - 1;
701 
702             case OP_MAX:
703                 mStack[sp - 1] = (float) Math.max(mStack[sp - 1], mStack[sp]);
704                 return sp - 1;
705 
706             case OP_POW:
707                 mStack[sp - 1] = (float) Math.pow(mStack[sp - 1], mStack[sp]);
708                 return sp - 1;
709 
710             case OP_SQRT:
711                 mStack[sp] = (float) Math.sqrt(mStack[sp]);
712                 return sp;
713 
714             case OP_ABS:
715                 mStack[sp] = (float) Math.abs(mStack[sp]);
716                 return sp;
717 
718             case OP_SIGN:
719                 mStack[sp] = (float) Math.signum(mStack[sp]);
720                 return sp;
721 
722             case OP_COPY_SIGN:
723                 mStack[sp - 1] = (float) Math.copySign(mStack[sp - 1], mStack[sp]);
724                 return sp - 1;
725 
726             case OP_EXP:
727                 mStack[sp] = (float) Math.exp(mStack[sp]);
728                 return sp;
729 
730             case OP_FLOOR:
731                 mStack[sp] = (float) Math.floor(mStack[sp]);
732                 return sp;
733 
734             case OP_LOG:
735                 mStack[sp] = (float) Math.log10(mStack[sp]);
736                 return sp;
737 
738             case OP_LN:
739                 mStack[sp] = (float) Math.log(mStack[sp]);
740                 return sp;
741 
742             case OP_ROUND:
743                 mStack[sp] = (float) Math.round(mStack[sp]);
744                 return sp;
745 
746             case OP_SIN:
747                 mStack[sp] = (float) Math.sin(mStack[sp]);
748                 return sp;
749 
750             case OP_COS:
751                 mStack[sp] = (float) Math.cos(mStack[sp]);
752                 return sp;
753 
754             case OP_TAN:
755                 mStack[sp] = (float) Math.tan(mStack[sp]);
756                 return sp;
757 
758             case OP_ASIN:
759                 mStack[sp] = (float) Math.asin(mStack[sp]);
760                 return sp;
761 
762             case OP_ACOS:
763                 mStack[sp] = (float) Math.acos(mStack[sp]);
764                 return sp;
765 
766             case OP_ATAN:
767                 mStack[sp] = (float) Math.atan(mStack[sp]);
768                 return sp;
769 
770             case OP_ATAN2:
771                 mStack[sp - 1] = (float) Math.atan2(mStack[sp - 1], mStack[sp]);
772                 return sp - 1;
773 
774             case OP_MAD:
775                 mStack[sp - 2] = mStack[sp] + mStack[sp - 1] * mStack[sp - 2];
776                 return sp - 2;
777 
778             case OP_TERNARY_CONDITIONAL:
779                 mStack[sp - 2] = (mStack[sp] > 0) ? mStack[sp - 1] : mStack[sp - 2];
780                 return sp - 2;
781 
782             case OP_CLAMP:
783                 mStack[sp - 2] = Math.min(Math.max(mStack[sp - 2], mStack[sp]), mStack[sp - 1]);
784                 return sp - 2;
785 
786             case OP_CBRT:
787                 mStack[sp] = (float) Math.pow(mStack[sp], 1 / 3.);
788                 return sp;
789 
790             case OP_DEG:
791                 mStack[sp] = mStack[sp] * FP_TO_RAD;
792                 return sp;
793 
794             case OP_RAD:
795                 mStack[sp] = mStack[sp] * FP_TO_DEG;
796                 return sp;
797 
798             case OP_CEIL:
799                 mStack[sp] = (float) Math.ceil(mStack[sp]);
800                 return sp;
801 
802             case OP_A_DEREF:
803                 id = fromNaN(mStack[sp - 1]);
804                 mStack[sp - 1] = mCollectionsAccess.getFloatValue(id, (int) mStack[sp]);
805                 return sp - 1;
806 
807             case OP_A_MAX:
808                 id = fromNaN(mStack[sp]);
809                 array = mCollectionsAccess.getFloats(id);
810                 float max = array[0];
811                 for (int i = 1; i < array.length; i++) {
812                     max = Math.max(max, array[i]);
813                 }
814                 mStack[sp] = max;
815                 return sp;
816 
817             case OP_A_MIN:
818                 id = fromNaN(mStack[sp]);
819                 array = mCollectionsAccess.getFloats(id);
820                 if (array.length == 0) {
821                     return sp;
822                 }
823                 float min = array[0];
824                 for (int i = 1; i < array.length; i++) {
825                     min = Math.min(min, array[i]);
826                 }
827                 mStack[sp] = min;
828                 return sp;
829 
830             case OP_A_SUM:
831                 id = fromNaN(mStack[sp]);
832                 array = mCollectionsAccess.getFloats(id);
833                 float sum = 0;
834                 for (int i = 0; i < array.length; i++) {
835                     sum += array[i];
836                 }
837                 mStack[sp] = sum;
838                 return sp;
839 
840             case OP_A_AVG:
841                 id = fromNaN(mStack[sp]);
842                 array = mCollectionsAccess.getFloats(id);
843                 sum = 0;
844                 for (int i = 0; i < array.length; i++) {
845                     sum += array[i];
846                 }
847                 mStack[sp] = sum / array.length;
848                 return sp;
849 
850             case OP_A_LEN:
851                 id = fromNaN(mStack[sp]);
852                 mStack[sp] = mCollectionsAccess.getListLength(id);
853                 return sp;
854 
855             case OP_A_SPLINE:
856                 id = fromNaN(mStack[sp - 1]);
857                 mStack[sp - 1] = getSplineValue(id, mStack[sp]);
858                 return sp - 1;
859 
860             case OP_RAND:
861                 if (sRandom == null) {
862                     sRandom = new Random();
863                 }
864                 mStack[sp + 1] = sRandom.nextFloat();
865                 return sp + 1;
866 
867             case OP_RAND_SEED:
868                 float seed = mStack[sp];
869                 if (seed == 0) {
870                     sRandom = new Random();
871                 } else {
872                     if (sRandom == null) {
873                         sRandom = new Random(Float.floatToRawIntBits(seed));
874                     } else {
875                         sRandom.setSeed(Float.floatToRawIntBits(seed));
876                     }
877                 }
878                 return sp - 1;
879             case OP_NOISE_FROM:
880                 int x = Float.floatToRawIntBits(mStack[sp]);
881                 x = (x << 13) ^ x; // / Bitwise scrambling return
882                 mStack[sp] =
883                         (1.0f
884                                 - ((x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff)
885                                         / 1073741824.0f);
886                 return sp;
887 
888             case OP_RAND_IN_RANGE:
889                 if (sRandom == null) {
890                     sRandom = new Random();
891                 }
892                 mStack[sp] = sRandom.nextFloat() * (mStack[sp] - mStack[sp - 1]) + mStack[sp - 1];
893                 return sp;
894             case OP_SQUARE_SUM:
895                 mStack[sp - 1] = mStack[sp - 1] * mStack[sp - 1] + mStack[sp] * mStack[sp];
896                 return sp - 1;
897             case OP_STEP:
898                 System.out.println(mStack[sp] + " > " + mStack[sp - 1]);
899                 mStack[sp - 1] = (mStack[sp - 1] > mStack[sp]) ? 1f : 0f;
900                 return sp - 1;
901             case OP_SQUARE:
902                 mStack[sp] = mStack[sp] * mStack[sp];
903                 return sp;
904             case OP_DUP:
905                 mStack[sp + 1] = mStack[sp];
906                 return sp + 1;
907             case OP_HYPOT:
908                 mStack[sp - 1] = (float) Math.hypot(mStack[sp - 1], mStack[sp]);
909                 return sp - 1;
910             case OP_SWAP:
911                 float swap = mStack[sp - 1];
912                 mStack[sp - 1] = mStack[sp];
913                 mStack[sp] = swap;
914                 return sp;
915             case OP_LERP:
916                 float tmp1 = mStack[sp - 2];
917                 float tmp2 = mStack[sp - 1];
918                 float tmp3 = mStack[sp];
919                 mStack[sp - 2] = tmp1 + (tmp2 - tmp1) * tmp3;
920                 return sp - 2;
921             case OP_SMOOTH_STEP:
922                 float val3 = mStack[sp - 2];
923                 float max2 = mStack[sp - 1];
924                 float min1 = mStack[sp];
925                 System.out.println("val3 = " + val3 + " min1 = " + min1 + " max2 = " + max2);
926                 if (val3 < min1) {
927                     mStack[sp - 2] = 0f;
928                     System.out.println("below min ");
929                 } else if (val3 > max2) {
930                     mStack[sp - 2] = 1f;
931                     System.out.println("above max ");
932 
933                 } else {
934                     float v = (val3 - min1) / (max2 - min1);
935                     System.out.println("v = " + v);
936                     mStack[sp - 2] = v * v * (3 - 2 * v);
937                 }
938                 return sp - 2;
939 
940             case OP_FIRST_VAR:
941                 mStack[sp] = mVar[0];
942                 return sp;
943 
944             case OP_SECOND_VAR:
945                 mStack[sp] = mVar[1];
946                 return sp;
947 
948             case OP_THIRD_VAR:
949                 mStack[sp] = mVar[2];
950                 return sp;
951         }
952         return sp;
953     }
954 }
955