1/*
2 * Copyright (C) 2008-2012 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
17package android.renderscript;
18
19import java.lang.reflect.Field;
20import android.util.Log;
21
22/**
23 * <p>The most basic data type. An element represents one cell of a memory allocation.
24 * Element is the basic data type of Renderscript. An element can be of two forms: Basic elements or Complex forms.
25 * Examples of basic elements are:</p>
26 * <ul>
27 *  <li>Single float value</li>
28 *  <li>4 element float vector</li>
29 *  <li>single RGB-565 color</li>
30 *  <li>single unsigned int 16</li>
31 * </ul>
32 * <p>Complex elements contain a list of sub-elements and names that
33 * represents a structure of data. The fields can be accessed by name
34 * from a script or shader. The memory layout is defined and ordered. Data
35 * alignment is determined by the most basic primitive type. i.e. a float4
36 * vector will be aligned to sizeof(float) and not sizeof(float4). The
37 * ordering of elements in memory will be the order in which they were added
38 * with each component aligned as necessary. No re-ordering will be done.</p>
39 *
40 * <p>The primary source of elements are from scripts. A script that exports a
41 * bind point for a data structure generates a Renderscript element to represent the
42 * data exported by the script. The other common source of elements is from bitmap formats.</p>
43 *
44 * <div class="special reference">
45 * <h3>Developer Guides</h3>
46 * <p>For more information about creating an application that uses Renderscript, read the
47 * <a href="{@docRoot}guide/topics/renderscript/index.html">Renderscript</a> developer guide.</p>
48 * </div>
49 **/
50public class Element extends BaseObj {
51    int mSize;
52    Element[] mElements;
53    String[] mElementNames;
54    int[] mArraySizes;
55    int[] mOffsetInBytes;
56
57    int[] mVisibleElementMap;
58
59    DataType mType;
60    DataKind mKind;
61    boolean mNormalized;
62    int mVectorSize;
63
64    private void updateVisibleSubElements() {
65        if (mElements == null) {
66            return;
67        }
68
69        int noPaddingFieldCount = 0;
70        int fieldCount = mElementNames.length;
71        // Find out how many elements are not padding
72        for (int ct = 0; ct < fieldCount; ct ++) {
73            if (mElementNames[ct].charAt(0) != '#') {
74                noPaddingFieldCount ++;
75            }
76        }
77        mVisibleElementMap = new int[noPaddingFieldCount];
78
79        // Make a map that points us at non-padding elements
80        for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
81            if (mElementNames[ct].charAt(0) != '#') {
82                mVisibleElementMap[ctNoPadding ++] = ct;
83            }
84        }
85    }
86
87    /**
88    * @return element size in bytes
89    */
90    public int getBytesSize() {return mSize;}
91
92    /**
93    * Returns the number of vector components. 2 for float2, 4 for
94    * float4, etc.
95    * @return element vector size
96    */
97    public int getVectorSize() {return mVectorSize;}
98
99
100    /**
101     * DataType represents the basic type information for a basic element.  The
102     * naming convention follows.  For numeric types it is FLOAT,
103     * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
104     * size of the data.  BOOLEAN is a true / false (1,0)
105     * represented in an 8 bit container.  The UNSIGNED variants
106     * with multiple bit definitions are for packed graphical data
107     * formats and represent vectors with per vector member sizes
108     * which are treated as a single unit for packing and alignment
109     * purposes.
110     *
111     * MATRIX the three matrix types contain FLOAT_32 elements and are treated
112     * as 32 bits for alignment purposes.
113     *
114     * RS_* objects.  32 bit opaque handles.
115     */
116    public enum DataType {
117        NONE (0, 0),
118        //FLOAT_16 (1, 2),
119        FLOAT_32 (2, 4),
120        FLOAT_64 (3, 8),
121        SIGNED_8 (4, 1),
122        SIGNED_16 (5, 2),
123        SIGNED_32 (6, 4),
124        SIGNED_64 (7, 8),
125        UNSIGNED_8 (8, 1),
126        UNSIGNED_16 (9, 2),
127        UNSIGNED_32 (10, 4),
128        UNSIGNED_64 (11, 8),
129
130        BOOLEAN(12, 1),
131
132        UNSIGNED_5_6_5 (13, 2),
133        UNSIGNED_5_5_5_1 (14, 2),
134        UNSIGNED_4_4_4_4 (15, 2),
135
136        MATRIX_4X4 (16, 64),
137        MATRIX_3X3 (17, 36),
138        MATRIX_2X2 (18, 16),
139
140        RS_ELEMENT (1000, 4),
141        RS_TYPE (1001, 4),
142        RS_ALLOCATION (1002, 4),
143        RS_SAMPLER (1003, 4),
144        RS_SCRIPT (1004, 4),
145        RS_MESH (1005, 4),
146        RS_PROGRAM_FRAGMENT (1006, 4),
147        RS_PROGRAM_VERTEX (1007, 4),
148        RS_PROGRAM_RASTER (1008, 4),
149        RS_PROGRAM_STORE (1009, 4),
150        RS_FONT (1010, 4);
151
152        int mID;
153        int mSize;
154        DataType(int id, int size) {
155            mID = id;
156            mSize = size;
157        }
158    }
159
160    /**
161     * The special interpretation of the data if required.  This is primarly
162     * useful for graphical data.  USER indicates no special interpretation is
163     * expected.  PIXEL is used in conjunction with the standard data types for
164     * representing texture formats.
165     */
166    public enum DataKind {
167        USER (0),
168
169        PIXEL_L (7),
170        PIXEL_A (8),
171        PIXEL_LA (9),
172        PIXEL_RGB (10),
173        PIXEL_RGBA (11),
174        PIXEL_DEPTH (12);
175
176        int mID;
177        DataKind(int id) {
178            mID = id;
179        }
180    }
181
182    /**
183     * Return if a element is too complex for use as a data source for a Mesh or
184     * a Program.
185     *
186     * @return boolean
187     */
188    public boolean isComplex() {
189        if (mElements == null) {
190            return false;
191        }
192        for (int ct=0; ct < mElements.length; ct++) {
193            if (mElements[ct].mElements != null) {
194                return true;
195            }
196        }
197        return false;
198    }
199
200    /**
201    * Elements could be simple, such as an int or a float, or a
202    * structure with multiple sub elements, such as a collection of
203    * floats, float2, float4. This function returns zero for simple
204    * elements or the number of sub-elements otherwise.
205    * @return number of sub-elements in this element
206    */
207    public int getSubElementCount() {
208        if (mVisibleElementMap == null) {
209            return 0;
210        }
211        return mVisibleElementMap.length;
212    }
213
214    /**
215    * For complex elements, this function will return the
216    * sub-element at index
217    * @param index index of the sub-element to return
218    * @return sub-element in this element at given index
219    */
220    public Element getSubElement(int index) {
221        if (mVisibleElementMap == null) {
222            throw new RSIllegalArgumentException("Element contains no sub-elements");
223        }
224        if (index < 0 || index >= mVisibleElementMap.length) {
225            throw new RSIllegalArgumentException("Illegal sub-element index");
226        }
227        return mElements[mVisibleElementMap[index]];
228    }
229
230    /**
231    * For complex elements, this function will return the
232    * sub-element name at index
233    * @param index index of the sub-element
234    * @return sub-element in this element at given index
235    */
236    public String getSubElementName(int index) {
237        if (mVisibleElementMap == null) {
238            throw new RSIllegalArgumentException("Element contains no sub-elements");
239        }
240        if (index < 0 || index >= mVisibleElementMap.length) {
241            throw new RSIllegalArgumentException("Illegal sub-element index");
242        }
243        return mElementNames[mVisibleElementMap[index]];
244    }
245
246    /**
247    * For complex elements, some sub-elements could be statically
248    * sized arrays. This function will return the array size for
249    * sub-element at index
250    * @param index index of the sub-element
251    * @return array size of sub-element in this element at given index
252    */
253    public int getSubElementArraySize(int index) {
254        if (mVisibleElementMap == null) {
255            throw new RSIllegalArgumentException("Element contains no sub-elements");
256        }
257        if (index < 0 || index >= mVisibleElementMap.length) {
258            throw new RSIllegalArgumentException("Illegal sub-element index");
259        }
260        return mArraySizes[mVisibleElementMap[index]];
261    }
262
263    /**
264    * This function specifies the location of a sub-element within
265    * the element
266    * @param index index of the sub-element
267    * @return offset in bytes of sub-element in this element at given index
268    */
269    public int getSubElementOffsetBytes(int index) {
270        if (mVisibleElementMap == null) {
271            throw new RSIllegalArgumentException("Element contains no sub-elements");
272        }
273        if (index < 0 || index >= mVisibleElementMap.length) {
274            throw new RSIllegalArgumentException("Illegal sub-element index");
275        }
276        return mOffsetInBytes[mVisibleElementMap[index]];
277    }
278
279    /**
280    * @return element data type
281    */
282    public DataType getDataType() {
283        return mType;
284    }
285
286    /**
287    * @return element data kind
288    */
289    public DataKind getDataKind() {
290        return mKind;
291    }
292
293    /**
294     * Utility function for returning an Element containing a single Boolean.
295     *
296     * @param rs Context to which the element will belong.
297     *
298     * @return Element
299     */
300    public static Element BOOLEAN(RenderScript rs) {
301        if(rs.mElement_BOOLEAN == null) {
302            rs.mElement_BOOLEAN = createUser(rs, DataType.BOOLEAN);
303        }
304        return rs.mElement_BOOLEAN;
305    }
306
307    /**
308     * Utility function for returning an Element containing a single UNSIGNED_8.
309     *
310     * @param rs Context to which the element will belong.
311     *
312     * @return Element
313     */
314    public static Element U8(RenderScript rs) {
315        if(rs.mElement_U8 == null) {
316            rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8);
317        }
318        return rs.mElement_U8;
319    }
320
321    /**
322     * Utility function for returning an Element containing a single SIGNED_8.
323     *
324     * @param rs Context to which the element will belong.
325     *
326     * @return Element
327     */
328    public static Element I8(RenderScript rs) {
329        if(rs.mElement_I8 == null) {
330            rs.mElement_I8 = createUser(rs, DataType.SIGNED_8);
331        }
332        return rs.mElement_I8;
333    }
334
335    public static Element U16(RenderScript rs) {
336        if(rs.mElement_U16 == null) {
337            rs.mElement_U16 = createUser(rs, DataType.UNSIGNED_16);
338        }
339        return rs.mElement_U16;
340    }
341
342    public static Element I16(RenderScript rs) {
343        if(rs.mElement_I16 == null) {
344            rs.mElement_I16 = createUser(rs, DataType.SIGNED_16);
345        }
346        return rs.mElement_I16;
347    }
348
349    public static Element U32(RenderScript rs) {
350        if(rs.mElement_U32 == null) {
351            rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32);
352        }
353        return rs.mElement_U32;
354    }
355
356    public static Element I32(RenderScript rs) {
357        if(rs.mElement_I32 == null) {
358            rs.mElement_I32 = createUser(rs, DataType.SIGNED_32);
359        }
360        return rs.mElement_I32;
361    }
362
363    public static Element U64(RenderScript rs) {
364        if(rs.mElement_U64 == null) {
365            rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64);
366        }
367        return rs.mElement_U64;
368    }
369
370    public static Element I64(RenderScript rs) {
371        if(rs.mElement_I64 == null) {
372            rs.mElement_I64 = createUser(rs, DataType.SIGNED_64);
373        }
374        return rs.mElement_I64;
375    }
376
377    public static Element F32(RenderScript rs) {
378        if(rs.mElement_F32 == null) {
379            rs.mElement_F32 = createUser(rs, DataType.FLOAT_32);
380        }
381        return rs.mElement_F32;
382    }
383
384    public static Element F64(RenderScript rs) {
385        if(rs.mElement_F64 == null) {
386            rs.mElement_F64 = createUser(rs, DataType.FLOAT_64);
387        }
388        return rs.mElement_F64;
389    }
390
391    public static Element ELEMENT(RenderScript rs) {
392        if(rs.mElement_ELEMENT == null) {
393            rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT);
394        }
395        return rs.mElement_ELEMENT;
396    }
397
398    public static Element TYPE(RenderScript rs) {
399        if(rs.mElement_TYPE == null) {
400            rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE);
401        }
402        return rs.mElement_TYPE;
403    }
404
405    public static Element ALLOCATION(RenderScript rs) {
406        if(rs.mElement_ALLOCATION == null) {
407            rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION);
408        }
409        return rs.mElement_ALLOCATION;
410    }
411
412    public static Element SAMPLER(RenderScript rs) {
413        if(rs.mElement_SAMPLER == null) {
414            rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER);
415        }
416        return rs.mElement_SAMPLER;
417    }
418
419    public static Element SCRIPT(RenderScript rs) {
420        if(rs.mElement_SCRIPT == null) {
421            rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT);
422        }
423        return rs.mElement_SCRIPT;
424    }
425
426    public static Element MESH(RenderScript rs) {
427        if(rs.mElement_MESH == null) {
428            rs.mElement_MESH = createUser(rs, DataType.RS_MESH);
429        }
430        return rs.mElement_MESH;
431    }
432
433    public static Element PROGRAM_FRAGMENT(RenderScript rs) {
434        if(rs.mElement_PROGRAM_FRAGMENT == null) {
435            rs.mElement_PROGRAM_FRAGMENT = createUser(rs, DataType.RS_PROGRAM_FRAGMENT);
436        }
437        return rs.mElement_PROGRAM_FRAGMENT;
438    }
439
440    public static Element PROGRAM_VERTEX(RenderScript rs) {
441        if(rs.mElement_PROGRAM_VERTEX == null) {
442            rs.mElement_PROGRAM_VERTEX = createUser(rs, DataType.RS_PROGRAM_VERTEX);
443        }
444        return rs.mElement_PROGRAM_VERTEX;
445    }
446
447    public static Element PROGRAM_RASTER(RenderScript rs) {
448        if(rs.mElement_PROGRAM_RASTER == null) {
449            rs.mElement_PROGRAM_RASTER = createUser(rs, DataType.RS_PROGRAM_RASTER);
450        }
451        return rs.mElement_PROGRAM_RASTER;
452    }
453
454    public static Element PROGRAM_STORE(RenderScript rs) {
455        if(rs.mElement_PROGRAM_STORE == null) {
456            rs.mElement_PROGRAM_STORE = createUser(rs, DataType.RS_PROGRAM_STORE);
457        }
458        return rs.mElement_PROGRAM_STORE;
459    }
460
461    public static Element FONT(RenderScript rs) {
462        if(rs.mElement_FONT == null) {
463            rs.mElement_FONT = createUser(rs, DataType.RS_FONT);
464        }
465        return rs.mElement_FONT;
466    }
467
468
469    public static Element A_8(RenderScript rs) {
470        if(rs.mElement_A_8 == null) {
471            rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
472        }
473        return rs.mElement_A_8;
474    }
475
476    public static Element RGB_565(RenderScript rs) {
477        if(rs.mElement_RGB_565 == null) {
478            rs.mElement_RGB_565 = createPixel(rs, DataType.UNSIGNED_5_6_5, DataKind.PIXEL_RGB);
479        }
480        return rs.mElement_RGB_565;
481    }
482
483    public static Element RGB_888(RenderScript rs) {
484        if(rs.mElement_RGB_888 == null) {
485            rs.mElement_RGB_888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGB);
486        }
487        return rs.mElement_RGB_888;
488    }
489
490    public static Element RGBA_5551(RenderScript rs) {
491        if(rs.mElement_RGBA_5551 == null) {
492            rs.mElement_RGBA_5551 = createPixel(rs, DataType.UNSIGNED_5_5_5_1, DataKind.PIXEL_RGBA);
493        }
494        return rs.mElement_RGBA_5551;
495    }
496
497    public static Element RGBA_4444(RenderScript rs) {
498        if(rs.mElement_RGBA_4444 == null) {
499            rs.mElement_RGBA_4444 = createPixel(rs, DataType.UNSIGNED_4_4_4_4, DataKind.PIXEL_RGBA);
500        }
501        return rs.mElement_RGBA_4444;
502    }
503
504    public static Element RGBA_8888(RenderScript rs) {
505        if(rs.mElement_RGBA_8888 == null) {
506            rs.mElement_RGBA_8888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGBA);
507        }
508        return rs.mElement_RGBA_8888;
509    }
510
511    public static Element F32_2(RenderScript rs) {
512        if(rs.mElement_FLOAT_2 == null) {
513            rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2);
514        }
515        return rs.mElement_FLOAT_2;
516    }
517
518    public static Element F32_3(RenderScript rs) {
519        if(rs.mElement_FLOAT_3 == null) {
520            rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3);
521        }
522        return rs.mElement_FLOAT_3;
523    }
524
525    public static Element F32_4(RenderScript rs) {
526        if(rs.mElement_FLOAT_4 == null) {
527            rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4);
528        }
529        return rs.mElement_FLOAT_4;
530    }
531
532    public static Element F64_2(RenderScript rs) {
533        if(rs.mElement_DOUBLE_2 == null) {
534            rs.mElement_DOUBLE_2 = createVector(rs, DataType.FLOAT_64, 2);
535        }
536        return rs.mElement_DOUBLE_2;
537    }
538
539    public static Element F64_3(RenderScript rs) {
540        if(rs.mElement_DOUBLE_3 == null) {
541            rs.mElement_DOUBLE_3 = createVector(rs, DataType.FLOAT_64, 3);
542        }
543        return rs.mElement_DOUBLE_3;
544    }
545
546    public static Element F64_4(RenderScript rs) {
547        if(rs.mElement_DOUBLE_4 == null) {
548            rs.mElement_DOUBLE_4 = createVector(rs, DataType.FLOAT_64, 4);
549        }
550        return rs.mElement_DOUBLE_4;
551    }
552
553    public static Element U8_2(RenderScript rs) {
554        if(rs.mElement_UCHAR_2 == null) {
555            rs.mElement_UCHAR_2 = createVector(rs, DataType.UNSIGNED_8, 2);
556        }
557        return rs.mElement_UCHAR_2;
558    }
559
560    public static Element U8_3(RenderScript rs) {
561        if(rs.mElement_UCHAR_3 == null) {
562            rs.mElement_UCHAR_3 = createVector(rs, DataType.UNSIGNED_8, 3);
563        }
564        return rs.mElement_UCHAR_3;
565    }
566
567    public static Element U8_4(RenderScript rs) {
568        if(rs.mElement_UCHAR_4 == null) {
569            rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4);
570        }
571        return rs.mElement_UCHAR_4;
572    }
573
574    public static Element I8_2(RenderScript rs) {
575        if(rs.mElement_CHAR_2 == null) {
576            rs.mElement_CHAR_2 = createVector(rs, DataType.SIGNED_8, 2);
577        }
578        return rs.mElement_CHAR_2;
579    }
580
581    public static Element I8_3(RenderScript rs) {
582        if(rs.mElement_CHAR_3 == null) {
583            rs.mElement_CHAR_3 = createVector(rs, DataType.SIGNED_8, 3);
584        }
585        return rs.mElement_CHAR_3;
586    }
587
588    public static Element I8_4(RenderScript rs) {
589        if(rs.mElement_CHAR_4 == null) {
590            rs.mElement_CHAR_4 = createVector(rs, DataType.SIGNED_8, 4);
591        }
592        return rs.mElement_CHAR_4;
593    }
594
595    public static Element U16_2(RenderScript rs) {
596        if(rs.mElement_USHORT_2 == null) {
597            rs.mElement_USHORT_2 = createVector(rs, DataType.UNSIGNED_16, 2);
598        }
599        return rs.mElement_USHORT_2;
600    }
601
602    public static Element U16_3(RenderScript rs) {
603        if(rs.mElement_USHORT_3 == null) {
604            rs.mElement_USHORT_3 = createVector(rs, DataType.UNSIGNED_16, 3);
605        }
606        return rs.mElement_USHORT_3;
607    }
608
609    public static Element U16_4(RenderScript rs) {
610        if(rs.mElement_USHORT_4 == null) {
611            rs.mElement_USHORT_4 = createVector(rs, DataType.UNSIGNED_16, 4);
612        }
613        return rs.mElement_USHORT_4;
614    }
615
616    public static Element I16_2(RenderScript rs) {
617        if(rs.mElement_SHORT_2 == null) {
618            rs.mElement_SHORT_2 = createVector(rs, DataType.SIGNED_16, 2);
619        }
620        return rs.mElement_SHORT_2;
621    }
622
623    public static Element I16_3(RenderScript rs) {
624        if(rs.mElement_SHORT_3 == null) {
625            rs.mElement_SHORT_3 = createVector(rs, DataType.SIGNED_16, 3);
626        }
627        return rs.mElement_SHORT_3;
628    }
629
630    public static Element I16_4(RenderScript rs) {
631        if(rs.mElement_SHORT_4 == null) {
632            rs.mElement_SHORT_4 = createVector(rs, DataType.SIGNED_16, 4);
633        }
634        return rs.mElement_SHORT_4;
635    }
636
637    public static Element U32_2(RenderScript rs) {
638        if(rs.mElement_UINT_2 == null) {
639            rs.mElement_UINT_2 = createVector(rs, DataType.UNSIGNED_32, 2);
640        }
641        return rs.mElement_UINT_2;
642    }
643
644    public static Element U32_3(RenderScript rs) {
645        if(rs.mElement_UINT_3 == null) {
646            rs.mElement_UINT_3 = createVector(rs, DataType.UNSIGNED_32, 3);
647        }
648        return rs.mElement_UINT_3;
649    }
650
651    public static Element U32_4(RenderScript rs) {
652        if(rs.mElement_UINT_4 == null) {
653            rs.mElement_UINT_4 = createVector(rs, DataType.UNSIGNED_32, 4);
654        }
655        return rs.mElement_UINT_4;
656    }
657
658    public static Element I32_2(RenderScript rs) {
659        if(rs.mElement_INT_2 == null) {
660            rs.mElement_INT_2 = createVector(rs, DataType.SIGNED_32, 2);
661        }
662        return rs.mElement_INT_2;
663    }
664
665    public static Element I32_3(RenderScript rs) {
666        if(rs.mElement_INT_3 == null) {
667            rs.mElement_INT_3 = createVector(rs, DataType.SIGNED_32, 3);
668        }
669        return rs.mElement_INT_3;
670    }
671
672    public static Element I32_4(RenderScript rs) {
673        if(rs.mElement_INT_4 == null) {
674            rs.mElement_INT_4 = createVector(rs, DataType.SIGNED_32, 4);
675        }
676        return rs.mElement_INT_4;
677    }
678
679    public static Element U64_2(RenderScript rs) {
680        if(rs.mElement_ULONG_2 == null) {
681            rs.mElement_ULONG_2 = createVector(rs, DataType.UNSIGNED_64, 2);
682        }
683        return rs.mElement_ULONG_2;
684    }
685
686    public static Element U64_3(RenderScript rs) {
687        if(rs.mElement_ULONG_3 == null) {
688            rs.mElement_ULONG_3 = createVector(rs, DataType.UNSIGNED_64, 3);
689        }
690        return rs.mElement_ULONG_3;
691    }
692
693    public static Element U64_4(RenderScript rs) {
694        if(rs.mElement_ULONG_4 == null) {
695            rs.mElement_ULONG_4 = createVector(rs, DataType.UNSIGNED_64, 4);
696        }
697        return rs.mElement_ULONG_4;
698    }
699
700    public static Element I64_2(RenderScript rs) {
701        if(rs.mElement_LONG_2 == null) {
702            rs.mElement_LONG_2 = createVector(rs, DataType.SIGNED_64, 2);
703        }
704        return rs.mElement_LONG_2;
705    }
706
707    public static Element I64_3(RenderScript rs) {
708        if(rs.mElement_LONG_3 == null) {
709            rs.mElement_LONG_3 = createVector(rs, DataType.SIGNED_64, 3);
710        }
711        return rs.mElement_LONG_3;
712    }
713
714    public static Element I64_4(RenderScript rs) {
715        if(rs.mElement_LONG_4 == null) {
716            rs.mElement_LONG_4 = createVector(rs, DataType.SIGNED_64, 4);
717        }
718        return rs.mElement_LONG_4;
719    }
720
721    public static Element MATRIX_4X4(RenderScript rs) {
722        if(rs.mElement_MATRIX_4X4 == null) {
723            rs.mElement_MATRIX_4X4 = createUser(rs, DataType.MATRIX_4X4);
724        }
725        return rs.mElement_MATRIX_4X4;
726    }
727
728    /** @deprecated use MATRIX_4X4
729    */
730    public static Element MATRIX4X4(RenderScript rs) {
731        return MATRIX_4X4(rs);
732    }
733
734    public static Element MATRIX_3X3(RenderScript rs) {
735        if(rs.mElement_MATRIX_3X3 == null) {
736            rs.mElement_MATRIX_3X3 = createUser(rs, DataType.MATRIX_3X3);
737        }
738        return rs.mElement_MATRIX_3X3;
739    }
740
741    public static Element MATRIX_2X2(RenderScript rs) {
742        if(rs.mElement_MATRIX_2X2 == null) {
743            rs.mElement_MATRIX_2X2 = createUser(rs, DataType.MATRIX_2X2);
744        }
745        return rs.mElement_MATRIX_2X2;
746    }
747
748    Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
749        super(id, rs);
750        mSize = 0;
751        mVectorSize = 1;
752        mElements = e;
753        mElementNames = n;
754        mArraySizes = as;
755        mType = DataType.NONE;
756        mKind = DataKind.USER;
757        mOffsetInBytes = new int[mElements.length];
758        for (int ct = 0; ct < mElements.length; ct++ ) {
759            mOffsetInBytes[ct] = mSize;
760            mSize += mElements[ct].mSize * mArraySizes[ct];
761        }
762        updateVisibleSubElements();
763    }
764
765    Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
766        super(id, rs);
767        if ((dt != DataType.UNSIGNED_5_6_5) &&
768            (dt != DataType.UNSIGNED_4_4_4_4) &&
769            (dt != DataType.UNSIGNED_5_5_5_1)) {
770            if (size == 3) {
771                mSize = dt.mSize * 4;
772            } else {
773                mSize = dt.mSize * size;
774            }
775        } else {
776            mSize = dt.mSize;
777        }
778        mType = dt;
779        mKind = dk;
780        mNormalized = norm;
781        mVectorSize = size;
782    }
783
784    Element(int id, RenderScript rs) {
785        super(id, rs);
786    }
787
788    @Override
789    void updateFromNative() {
790        super.updateFromNative();
791
792        // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
793        int[] dataBuffer = new int[5];
794        mRS.nElementGetNativeData(getID(mRS), dataBuffer);
795
796        mNormalized = dataBuffer[2] == 1 ? true : false;
797        mVectorSize = dataBuffer[3];
798        mSize = 0;
799        for (DataType dt: DataType.values()) {
800            if(dt.mID == dataBuffer[0]){
801                mType = dt;
802                mSize = mType.mSize * mVectorSize;
803            }
804        }
805        for (DataKind dk: DataKind.values()) {
806            if(dk.mID == dataBuffer[1]){
807                mKind = dk;
808            }
809        }
810
811        int numSubElements = dataBuffer[4];
812        if(numSubElements > 0) {
813            mElements = new Element[numSubElements];
814            mElementNames = new String[numSubElements];
815            mArraySizes = new int[numSubElements];
816            mOffsetInBytes = new int[numSubElements];
817
818            int[] subElementIds = new int[numSubElements];
819            mRS.nElementGetSubElements(getID(mRS), subElementIds, mElementNames, mArraySizes);
820            for(int i = 0; i < numSubElements; i ++) {
821                mElements[i] = new Element(subElementIds[i], mRS);
822                mElements[i].updateFromNative();
823                mOffsetInBytes[i] = mSize;
824                mSize += mElements[i].mSize * mArraySizes[i];
825            }
826        }
827        updateVisibleSubElements();
828    }
829
830    /**
831     * Create a custom Element of the specified DataType.  The DataKind will be
832     * set to USER and the vector size to 1 indicating non-vector.
833     *
834     * @param rs The context associated with the new Element.
835     * @param dt The DataType for the new element.
836     * @return Element
837     */
838    static Element createUser(RenderScript rs, DataType dt) {
839        DataKind dk = DataKind.USER;
840        boolean norm = false;
841        int vecSize = 1;
842        int id = rs.nElementCreate(dt.mID, dk.mID, norm, vecSize);
843        return new Element(id, rs, dt, dk, norm, vecSize);
844    }
845
846    /**
847     * Create a custom vector element of the specified DataType and vector size.
848     * DataKind will be set to USER. Only primitive types (FLOAT_32, FLOAT_64,
849     * SIGNED_8, SIGNED_16, SIGNED_32, SIGNED_64, UNSIGNED_8, UNSIGNED_16,
850     * UNSIGNED_32, UNSIGNED_64, BOOLEAN) are supported.
851     *
852     * @param rs The context associated with the new Element.
853     * @param dt The DataType for the new Element.
854     * @param size Vector size for the new Element.  Range 2-4 inclusive
855     *             supported.
856     *
857     * @return Element
858     */
859    public static Element createVector(RenderScript rs, DataType dt, int size) {
860        if (size < 2 || size > 4) {
861            throw new RSIllegalArgumentException("Vector size out of range 2-4.");
862        }
863
864        switch (dt) {
865        // Support only primitive integer/float/boolean types as vectors.
866        case FLOAT_32:
867        case FLOAT_64:
868        case SIGNED_8:
869        case SIGNED_16:
870        case SIGNED_32:
871        case SIGNED_64:
872        case UNSIGNED_8:
873        case UNSIGNED_16:
874        case UNSIGNED_32:
875        case UNSIGNED_64:
876        case BOOLEAN: {
877            DataKind dk = DataKind.USER;
878            boolean norm = false;
879            int id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
880            return new Element(id, rs, dt, dk, norm, size);
881        }
882
883        default: {
884            throw new RSIllegalArgumentException("Cannot create vector of " +
885                "non-primitive type.");
886        }
887        }
888    }
889
890    /**
891     * Create a new pixel Element type.  A matching DataType and DataKind must
892     * be provided.  The DataType and DataKind must contain the same number of
893     * components.  Vector size will be set to 1.
894     *
895     * @param rs The context associated with the new Element.
896     * @param dt The DataType for the new element.
897     * @param dk The DataKind to specify the mapping of each component in the
898     *           DataType.
899     *
900     * @return Element
901     */
902    public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
903        if (!(dk == DataKind.PIXEL_L ||
904              dk == DataKind.PIXEL_A ||
905              dk == DataKind.PIXEL_LA ||
906              dk == DataKind.PIXEL_RGB ||
907              dk == DataKind.PIXEL_RGBA ||
908              dk == DataKind.PIXEL_DEPTH)) {
909            throw new RSIllegalArgumentException("Unsupported DataKind");
910        }
911        if (!(dt == DataType.UNSIGNED_8 ||
912              dt == DataType.UNSIGNED_16 ||
913              dt == DataType.UNSIGNED_5_6_5 ||
914              dt == DataType.UNSIGNED_4_4_4_4 ||
915              dt == DataType.UNSIGNED_5_5_5_1)) {
916            throw new RSIllegalArgumentException("Unsupported DataType");
917        }
918        if (dt == DataType.UNSIGNED_5_6_5 && dk != DataKind.PIXEL_RGB) {
919            throw new RSIllegalArgumentException("Bad kind and type combo");
920        }
921        if (dt == DataType.UNSIGNED_5_5_5_1 && dk != DataKind.PIXEL_RGBA) {
922            throw new RSIllegalArgumentException("Bad kind and type combo");
923        }
924        if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) {
925            throw new RSIllegalArgumentException("Bad kind and type combo");
926        }
927        if (dt == DataType.UNSIGNED_16 &&
928            dk != DataKind.PIXEL_DEPTH) {
929            throw new RSIllegalArgumentException("Bad kind and type combo");
930        }
931
932        int size = 1;
933        switch (dk) {
934        case PIXEL_LA:
935            size = 2;
936            break;
937        case PIXEL_RGB:
938            size = 3;
939            break;
940        case PIXEL_RGBA:
941            size = 4;
942            break;
943        case PIXEL_DEPTH:
944            size = 2;
945            break;
946        }
947
948        boolean norm = true;
949        int id = rs.nElementCreate(dt.mID, dk.mID, norm, size);
950        return new Element(id, rs, dt, dk, norm, size);
951    }
952
953    /**
954     * Check if the current Element is compatible with another Element.
955     * Primitive Elements are compatible if they share the same underlying
956     * size and type (i.e. U8 is compatible with A_8). User-defined Elements
957     * must be equal in order to be compatible. This requires strict name
958     * equivalence for all sub-Elements (in addition to structural equivalence).
959     *
960     * @param e The Element to check compatibility with.
961     *
962     * @return boolean true if the Elements are compatible, otherwise false.
963     */
964    public boolean isCompatible(Element e) {
965        // Try strict BaseObj equality to start with.
966        if (this.equals(e)) {
967            return true;
968        }
969
970        // Ignore mKind because it is allowed to be different (user vs. pixel).
971        // We also ignore mNormalized because it can be different. The mType
972        // field must not be NONE since we require name equivalence for
973        // all user-created Elements.
974        return ((mSize == e.mSize) &&
975                (mType != DataType.NONE) &&
976                (mType == e.mType) &&
977                (mVectorSize == e.mVectorSize));
978    }
979
980    /**
981     * Builder class for producing complex elements with matching field and name
982     * pairs.  The builder starts empty.  The order in which elements are added
983     * is retained for the layout in memory.
984     *
985     */
986    public static class Builder {
987        RenderScript mRS;
988        Element[] mElements;
989        String[] mElementNames;
990        int[] mArraySizes;
991        int mCount;
992        int mSkipPadding;
993
994        /**
995         * Create a builder object.
996         *
997         * @param rs
998         */
999        public Builder(RenderScript rs) {
1000            mRS = rs;
1001            mCount = 0;
1002            mElements = new Element[8];
1003            mElementNames = new String[8];
1004            mArraySizes = new int[8];
1005        }
1006
1007        /**
1008         * Add an array of elements to this element.
1009         *
1010         * @param element
1011         * @param name
1012         * @param arraySize
1013         */
1014        public Builder add(Element element, String name, int arraySize) {
1015            if (arraySize < 1) {
1016                throw new RSIllegalArgumentException("Array size cannot be less than 1.");
1017            }
1018
1019            // Skip padding fields after a vector 3 type.
1020            if (mSkipPadding != 0) {
1021                if (name.startsWith("#padding_")) {
1022                    mSkipPadding = 0;
1023                    return this;
1024                }
1025            }
1026
1027            if (element.mVectorSize == 3) {
1028                mSkipPadding = 1;
1029            } else {
1030                mSkipPadding = 0;
1031            }
1032
1033            if(mCount == mElements.length) {
1034                Element[] e = new Element[mCount + 8];
1035                String[] s = new String[mCount + 8];
1036                int[] as = new int[mCount + 8];
1037                System.arraycopy(mElements, 0, e, 0, mCount);
1038                System.arraycopy(mElementNames, 0, s, 0, mCount);
1039                System.arraycopy(mArraySizes, 0, as, 0, mCount);
1040                mElements = e;
1041                mElementNames = s;
1042                mArraySizes = as;
1043            }
1044            mElements[mCount] = element;
1045            mElementNames[mCount] = name;
1046            mArraySizes[mCount] = arraySize;
1047            mCount++;
1048            return this;
1049        }
1050
1051        /**
1052         * Add a single element to this Element.
1053         *
1054         * @param element
1055         * @param name
1056         */
1057        public Builder add(Element element, String name) {
1058            return add(element, name, 1);
1059        }
1060
1061        /**
1062         * Create the element from this builder.
1063         *
1064         *
1065         * @return Element
1066         */
1067        public Element create() {
1068            mRS.validate();
1069            Element[] ein = new Element[mCount];
1070            String[] sin = new String[mCount];
1071            int[] asin = new int[mCount];
1072            java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
1073            java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
1074            java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount);
1075
1076            int[] ids = new int[ein.length];
1077            for (int ct = 0; ct < ein.length; ct++ ) {
1078                ids[ct] = ein[ct].getID(mRS);
1079            }
1080            int id = mRS.nElementCreate2(ids, sin, asin);
1081            return new Element(id, mRS, ein, sin, asin);
1082        }
1083    }
1084}
1085
1086