1/*
2 * Copyright (C) 2008 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 android.content.res.Resources;
20import android.util.Log;
21
22import java.io.IOException;
23import java.io.InputStream;
24import java.util.Map.Entry;
25import java.util.HashMap;
26
27import java.lang.reflect.Field;
28import java.lang.reflect.Modifier;
29
30/**
31 * @hide
32 **/
33public class ScriptC extends Script {
34    private static final String TAG = "ScriptC";
35
36    ScriptC(int id, RenderScript rs) {
37        super(id, rs);
38    }
39
40    public static class Builder extends Script.Builder {
41        byte[] mProgram;
42        int mProgramLength;
43        HashMap<String,Integer> mIntDefines = new HashMap();
44        HashMap<String,Float> mFloatDefines = new HashMap();
45
46        public Builder(RenderScript rs) {
47            super(rs);
48        }
49
50        public void setScript(String s) {
51            try {
52                mProgram = s.getBytes("UTF-8");
53                mProgramLength = mProgram.length;
54            } catch (java.io.UnsupportedEncodingException e) {
55                throw new RuntimeException(e);
56            }
57        }
58
59        public void setScript(Resources resources, int id) {
60            InputStream is = resources.openRawResource(id);
61            try {
62                try {
63                    setScript(is);
64                } finally {
65                    is.close();
66                }
67            } catch(IOException e) {
68                throw new Resources.NotFoundException();
69            }
70        }
71
72        public void setScript(InputStream is) throws IOException {
73            byte[] buf = new byte[1024];
74            int currentPos = 0;
75            while(true) {
76                int bytesLeft = buf.length - currentPos;
77                if (bytesLeft == 0) {
78                    byte[] buf2 = new byte[buf.length * 2];
79                    System.arraycopy(buf, 0, buf2, 0, buf.length);
80                    buf = buf2;
81                    bytesLeft = buf.length - currentPos;
82                }
83                int bytesRead = is.read(buf, currentPos, bytesLeft);
84                if (bytesRead <= 0) {
85                    break;
86                }
87                currentPos += bytesRead;
88            }
89            mProgram = buf;
90            mProgramLength = currentPos;
91        }
92
93        static synchronized ScriptC internalCreate(Builder b) {
94            b.mRS.nScriptCBegin();
95            b.transferCreate();
96
97            for (Entry<String,Integer> e: b.mIntDefines.entrySet()) {
98                b.mRS.nScriptCAddDefineI32(e.getKey(), e.getValue().intValue());
99            }
100            for (Entry<String,Float> e: b.mFloatDefines.entrySet()) {
101                b.mRS.nScriptCAddDefineF(e.getKey(), e.getValue().floatValue());
102            }
103
104            b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength);
105
106            int id = b.mRS.nScriptCCreate();
107            ScriptC obj = new ScriptC(id, b.mRS);
108            b.transferObject(obj);
109
110            return obj;
111        }
112
113        public void addDefine(String name, int value) {
114            mIntDefines.put(name, value);
115        }
116
117        public void addDefine(String name, float value) {
118            mFloatDefines.put(name, value);
119        }
120
121        /**
122         * Takes the all public static final fields for a class, and adds defines
123         * for them, using the name of the field as the name of the define.
124         */
125        public void addDefines(Class cl) {
126            addDefines(cl.getFields(), (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC), null);
127        }
128
129        /**
130         * Takes the all public fields for an object, and adds defines
131         * for them, using the name of the field as the name of the define.
132         */
133        public void addDefines(Object o) {
134            addDefines(o.getClass().getFields(), Modifier.PUBLIC, o);
135        }
136
137        void addDefines(Field[] fields, int mask, Object o) {
138            for (Field f: fields) {
139                try {
140                    if ((f.getModifiers() & mask) == mask) {
141                        Class t = f.getType();
142                        if (t == int.class) {
143                            mIntDefines.put(f.getName(), f.getInt(o));
144                        }
145                        else if (t == float.class) {
146                            mFloatDefines.put(f.getName(), f.getFloat(o));
147                        }
148                    }
149                } catch (IllegalAccessException ex) {
150                    // TODO: Do we want this log?
151                    Log.d(TAG, "addDefines skipping field " + f.getName());
152                }
153            }
154        }
155
156        public ScriptC create() {
157            return internalCreate(this);
158        }
159    }
160}
161
162