1/*
2 * Copyright (C) 2015 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 */
16package com.example.android.rs.vr.engine;
17
18
19import android.graphics.Color;
20import android.renderscript.Allocation;
21import android.renderscript.Element;
22import android.renderscript.RenderScript;
23import android.renderscript.Type;
24
25/**
26 * Defines the material properties of a pixel value
27 * RGB, Opacity diffuse specular, ambient
28 */
29public class Material {
30    public static final int SIZE = 64 * 1024;
31    public static final int STRIDE = 8;
32
33    Allocation mOpacityAllocation;
34    Allocation mColorMapAllocation;
35
36    public byte[] mOpacityTable = new byte[SIZE];
37    MaterialProp[] mMaterialProp = new MaterialProp[0];
38    public byte[] mColor = new byte[SIZE * STRIDE]; // table contain r, g, b, A, S, D
39    public static final int RED = 0;
40    public static final int GREEN = 1;
41    public static final int BLUE = 2;
42    public static final int DIFF = 4;
43    public static final int SPEC = 5;
44    public static final int AMB = 6;
45
46    public static class MaterialProp {
47        int mPos;
48        int mRed;
49        int mGreen;
50        int mBlue;
51        float mDiffuse;
52        float mSpecular;
53        float mAmbient;
54    }
55
56    /**
57     * Clamp limits to less than or equal to 255
58     * this is done with a very efficient bit fiddling trick
59     * @param c value being clamped
60     * @return values in the range 0-255
61     */
62    private static int clamp(int c) {
63        final int N = 255; // the value clamp is limiting to
64        c &= ~(c >> 31);
65        c -= N;
66        c &= (c >> 31);
67        c += N;
68        return c;
69    }
70
71    public static class Opactiy {
72        int mPos;
73        float mValue;
74    }
75
76    public Opactiy[] mOpacity = new Opactiy[0];
77
78    public Material() {
79        simpleSetup(1150, 1300);
80    }
81
82    public void simpleSetup(int start, int end) {
83        float diffuse = .7f;
84        float specular = .0f;
85        float ambient = .3f;
86        for (int i = Short.MIN_VALUE; i < Short.MAX_VALUE; i++) {
87            int off = i & 0xFFFF;
88            int p = STRIDE * (off);
89            byte v = (byte) clamp((int) (255 * (i - start) / (end - start)));
90            mColor[p + RED] = v;
91            mColor[p + GREEN] = v;
92            mColor[p + BLUE] = v;
93            mColor[p + DIFF] = (byte) (255 * diffuse);
94            mColor[p + SPEC] = (byte) (255 * specular);
95            mColor[p + AMB] = (byte) (255 * ambient);
96            mOpacityTable[off] = v;
97        }
98    }
99
100    public void setup(int[] means, int start, int end) {
101        int[] pos = new int[means.length - 1];
102        int[] red = new int[means.length - 1];
103        int[] green = new int[means.length - 1];
104        int[] blue = new int[means.length - 1];
105
106        for (int i = 0; i < pos.length; i++) {
107            pos[i] = (means[i] + means[i + 1]) / 2;
108            float f = i / (float) (pos.length - 1);
109            float h = 1 - f * f * f;
110            float s = (float) (1 / (1 + Math.exp((f - .5) * 5)));
111            int rgb = Color.HSVToColor(new float[]{360 * h, s, f});
112            red[i] = (rgb >> 16) & 0xff;
113            green[i] = (rgb >> 8) & 0xff;
114            blue[i] = (rgb >> 0) & 0xff;
115        }
116        mMaterialProp = new MaterialProp[pos.length];
117
118        float diffuse = .7f;
119        float specular = .0f;
120        float ambient = .3f;
121        for (int i = 0; i < pos.length; i++) {
122            mMaterialProp[i] = new MaterialProp();
123            mMaterialProp[i].mAmbient = ambient;
124            mMaterialProp[i].mSpecular = specular;
125            mMaterialProp[i].mDiffuse = diffuse;
126            mMaterialProp[i].mPos = pos[i];
127            float t = i / (float) (pos.length - 1);
128
129            mMaterialProp[i].mRed = red[i];
130            mMaterialProp[i].mGreen = green[i];
131            mMaterialProp[i].mBlue = blue[i];
132
133        }
134        mOpacity = new Opactiy[2];
135        mOpacity[0] = new Opactiy();
136        mOpacity[0].mPos = start;
137        mOpacity[0].mValue = 0;
138
139        mOpacity[1] = new Opactiy();
140        mOpacity[1].mPos = end;
141        mOpacity[1].mValue = 1;
142
143        buildOpacityTable();
144        buildMaterialProp();
145    }
146
147    public void setup(int[][] opacity, int[][] material) {
148        mMaterialProp = new MaterialProp[material.length];
149
150        for (int i = 0; i < material.length; i++) {
151            int rgb = material[i][1] & 0xFFFFFF;
152
153            float ambient = (material[i].length > 2) ? material[i][2] / 100.f : .2f;
154            float diffuse = (material[i].length > 3) ? material[i][3] / 100.f : .6f;
155            float specular = (material[i].length > 4) ? material[i][4] / 100.f : .2f;
156
157            mMaterialProp[i] = new MaterialProp();
158            mMaterialProp[i].mAmbient = ambient;
159            mMaterialProp[i].mSpecular = specular;
160            mMaterialProp[i].mDiffuse = diffuse;
161            mMaterialProp[i].mRed = (rgb >> 16) & 0xff;
162            mMaterialProp[i].mGreen = (rgb >> 8) & 0xff;
163            mMaterialProp[i].mBlue = (rgb >> 0) & 0xff;
164
165            mMaterialProp[i].mPos = material[i][0];
166
167        }
168        mOpacity = new Opactiy[opacity.length];
169        for (int i = 0; i < opacity.length; i++) {
170            mOpacity[i] = new Opactiy();
171            mOpacity[i].mPos = opacity[i][0];
172            mOpacity[i].mValue = opacity[i][1] / 255.f;
173        }
174        buildOpacityTable();
175        buildMaterialProp();
176    }
177
178    public void setup(int start, int end) {
179        int[] pos = {1050, 1140, 1200, 1210, 1231};
180
181        mMaterialProp = new MaterialProp[pos.length];
182
183        float diffuse = .7f;
184        float specular = .0f;
185        float ambient = .3f;
186        for (int i = 0; i < pos.length; i++) {
187            mMaterialProp[i] = new MaterialProp();
188            mMaterialProp[i].mAmbient = ambient;
189            mMaterialProp[i].mSpecular = specular;
190            mMaterialProp[i].mDiffuse = diffuse;
191            mMaterialProp[i].mPos = pos[i];
192            float t = i / (float) (pos.length - 1);
193            int rgb = (int) (Math.random() * 0xFFFFFF);
194            mMaterialProp[i].mRed = (rgb >> 16) & 0xff;
195            mMaterialProp[i].mGreen = (rgb >> 8) & 0xff;
196            mMaterialProp[i].mBlue = (rgb >> 0) & 0xff;
197        }
198        mOpacity = new Opactiy[2];
199        mOpacity[0] = new Opactiy();
200        mOpacity[0].mPos = start;
201        mOpacity[0].mValue = 0;
202
203        mOpacity[1] = new Opactiy();
204        mOpacity[1].mPos = end;
205        mOpacity[1].mValue = 1;
206
207        buildOpacityTable();
208        buildMaterialProp();
209    }
210
211    void buildOpacityTable() {
212        if (mOpacity.length == 0) {
213            return;
214        }
215        for (int i = Short.MIN_VALUE; i <= mOpacity[0].mPos; i++) {
216            int p = i & 0xFFFF;
217            mOpacityTable[p] = (byte) (mOpacity[0].mValue * 255);
218        }
219        for (int k = 0; k < mOpacity.length - 1; k++) {
220            for (int i = mOpacity[k].mPos; i < mOpacity[k + 1].mPos; i++) {
221                int p = i & 0xFFFF;
222                float dist = mOpacity[k + 1].mPos - mOpacity[k].mPos;
223                float t = (i - mOpacity[k].mPos) / dist;
224                float v = mOpacity[k].mValue * (1 - t) + t * mOpacity[k + 1].mValue;
225                mOpacityTable[p] = (byte) (v * 255);
226            }
227        }
228        int last = mOpacity.length - 1;
229        for (int i = mOpacity[last].mPos; i <= Short.MAX_VALUE; i++) {
230            int p = i & 0xFFFF;
231            mOpacityTable[p] = (byte) (mOpacity[last].mValue * 255);
232
233        }
234    }
235
236    public void buildMaterialProp() {
237        MaterialProp[] m = mMaterialProp;
238        if (m.length == 0) {
239            return;
240        }
241        {
242            MaterialProp mp = m[0];
243            int red = m[0].mRed;
244            int green = m[0].mGreen;
245            int blue = m[0].mBlue;
246
247            for (int i = Short.MIN_VALUE; i <= m[0].mPos; i++) {
248                int p = STRIDE * (i & 0xFFFF);
249                mColor[p + RED] = (byte) red;
250                mColor[p + GREEN] = (byte) green;
251                mColor[p + BLUE] = (byte) blue;
252
253                mColor[p + DIFF] = (byte) (255 * mp.mDiffuse);
254                mColor[p + SPEC] = (byte) (255 * mp.mSpecular);
255                mColor[p + AMB] = (byte) (255 * mp.mAmbient);
256            }
257        }
258        for (int k = 0; k < m.length - 1; k++) {
259            for (int i = m[k].mPos; i < m[k + 1].mPos; i++) {
260                int p = STRIDE * (i & 0xFFFF);
261                float dist = m[k + 1].mPos - m[k].mPos;
262                float t2 = (i - m[k].mPos) / dist;
263                float t1 = 1 - t2;
264
265
266                int red = (int) (m[k].mRed * t1 + m[k + 1].mRed * t2);
267                int green = (int) (m[k].mGreen * t1 + m[k + 1].mGreen * t2);
268                int blue = (int) (m[k].mBlue * t1 + m[k + 1].mBlue * t2);
269
270                float diffuse = m[k].mDiffuse * t1 + m[k + 1].mDiffuse * t2;
271                float specular = m[k].mSpecular * t1 + m[k + 1].mSpecular * t2;
272                float ambient = m[k].mAmbient * t1 + m[k + 1].mAmbient * t2;
273
274
275                mColor[p + RED] = (byte) red;
276                mColor[p + GREEN] = (byte) green;
277                mColor[p + BLUE] = (byte) blue;
278
279                mColor[p + DIFF] = (byte) (255 * diffuse);
280                mColor[p + SPEC] = (byte) (255 * specular);
281                mColor[p + AMB] = (byte) (255 * ambient);
282            }
283        }
284        {
285            int last = m.length - 1;
286            MaterialProp mp = m[last];
287            int red = mp.mRed;
288            int green = mp.mGreen;
289            int blue = mp.mBlue;
290            for (int i = mp.mPos; i <= Short.MAX_VALUE; i++) {
291                int p = STRIDE * (i & 0xFFFF);
292                mColor[p + RED] = (byte) red;
293                mColor[p + GREEN] = (byte) green;
294                mColor[p + BLUE] = (byte) blue;
295
296                mColor[p + DIFF] = (byte) (255 * mp.mDiffuse);
297                mColor[p + SPEC] = (byte) (255 * mp.mSpecular);
298                mColor[p + AMB] = (byte) (255 * mp.mAmbient);
299            }
300        }
301    }
302
303    public Allocation getOpacityAllocation(RenderScript rs) {
304        if (mOpacityAllocation == null) {
305            Type.Builder b = new Type.Builder(rs, Element.U8(rs));
306            b.setX(mOpacityTable.length);
307            mOpacityAllocation = Allocation.createTyped(rs, b.create());
308        }
309        mOpacityAllocation.copyFromUnchecked(mOpacityTable);
310        return mOpacityAllocation;
311    }
312
313    public Allocation getColorMapAllocation(RenderScript rs) {
314        if (mColorMapAllocation == null) {
315            Type.Builder b = new Type.Builder(rs, Element.U8_4(rs));
316            b.setX(mColor.length / 4);
317            mColorMapAllocation = Allocation.createTyped(rs, b.create());
318        }
319        mColorMapAllocation.copyFromUnchecked(mColor);
320        return mColorMapAllocation;
321    }
322}
323