/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.rs.vr.engine; import android.graphics.Color; import android.renderscript.Allocation; import android.renderscript.Element; import android.renderscript.RenderScript; import android.renderscript.Type; /** * Defines the material properties of a pixel value * RGB, Opacity diffuse specular, ambient */ public class Material { public static final int SIZE = 64 * 1024; public static final int STRIDE = 8; Allocation mOpacityAllocation; Allocation mColorMapAllocation; public byte[] mOpacityTable = new byte[SIZE]; MaterialProp[] mMaterialProp = new MaterialProp[0]; public byte[] mColor = new byte[SIZE * STRIDE]; // table contain r, g, b, A, S, D public static final int RED = 0; public static final int GREEN = 1; public static final int BLUE = 2; public static final int DIFF = 4; public static final int SPEC = 5; public static final int AMB = 6; public static class MaterialProp { int mPos; int mRed; int mGreen; int mBlue; float mDiffuse; float mSpecular; float mAmbient; } /** * Clamp limits to less than or equal to 255 * this is done with a very efficient bit fiddling trick * @param c value being clamped * @return values in the range 0-255 */ private static int clamp(int c) { final int N = 255; // the value clamp is limiting to c &= ~(c >> 31); c -= N; c &= (c >> 31); c += N; return c; } public static class Opactiy { int mPos; float mValue; } public Opactiy[] mOpacity = new Opactiy[0]; public Material() { simpleSetup(1150, 1300); } public void simpleSetup(int start, int end) { float diffuse = .7f; float specular = .0f; float ambient = .3f; for (int i = Short.MIN_VALUE; i < Short.MAX_VALUE; i++) { int off = i & 0xFFFF; int p = STRIDE * (off); byte v = (byte) clamp((int) (255 * (i - start) / (end - start))); mColor[p + RED] = v; mColor[p + GREEN] = v; mColor[p + BLUE] = v; mColor[p + DIFF] = (byte) (255 * diffuse); mColor[p + SPEC] = (byte) (255 * specular); mColor[p + AMB] = (byte) (255 * ambient); mOpacityTable[off] = v; } } public void setup(int[] means, int start, int end) { int[] pos = new int[means.length - 1]; int[] red = new int[means.length - 1]; int[] green = new int[means.length - 1]; int[] blue = new int[means.length - 1]; for (int i = 0; i < pos.length; i++) { pos[i] = (means[i] + means[i + 1]) / 2; float f = i / (float) (pos.length - 1); float h = 1 - f * f * f; float s = (float) (1 / (1 + Math.exp((f - .5) * 5))); int rgb = Color.HSVToColor(new float[]{360 * h, s, f}); red[i] = (rgb >> 16) & 0xff; green[i] = (rgb >> 8) & 0xff; blue[i] = (rgb >> 0) & 0xff; } mMaterialProp = new MaterialProp[pos.length]; float diffuse = .7f; float specular = .0f; float ambient = .3f; for (int i = 0; i < pos.length; i++) { mMaterialProp[i] = new MaterialProp(); mMaterialProp[i].mAmbient = ambient; mMaterialProp[i].mSpecular = specular; mMaterialProp[i].mDiffuse = diffuse; mMaterialProp[i].mPos = pos[i]; float t = i / (float) (pos.length - 1); mMaterialProp[i].mRed = red[i]; mMaterialProp[i].mGreen = green[i]; mMaterialProp[i].mBlue = blue[i]; } mOpacity = new Opactiy[2]; mOpacity[0] = new Opactiy(); mOpacity[0].mPos = start; mOpacity[0].mValue = 0; mOpacity[1] = new Opactiy(); mOpacity[1].mPos = end; mOpacity[1].mValue = 1; buildOpacityTable(); buildMaterialProp(); } public void setup(int[][] opacity, int[][] material) { mMaterialProp = new MaterialProp[material.length]; for (int i = 0; i < material.length; i++) { int rgb = material[i][1] & 0xFFFFFF; float ambient = (material[i].length > 2) ? material[i][2] / 100.f : .2f; float diffuse = (material[i].length > 3) ? material[i][3] / 100.f : .6f; float specular = (material[i].length > 4) ? material[i][4] / 100.f : .2f; mMaterialProp[i] = new MaterialProp(); mMaterialProp[i].mAmbient = ambient; mMaterialProp[i].mSpecular = specular; mMaterialProp[i].mDiffuse = diffuse; mMaterialProp[i].mRed = (rgb >> 16) & 0xff; mMaterialProp[i].mGreen = (rgb >> 8) & 0xff; mMaterialProp[i].mBlue = (rgb >> 0) & 0xff; mMaterialProp[i].mPos = material[i][0]; } mOpacity = new Opactiy[opacity.length]; for (int i = 0; i < opacity.length; i++) { mOpacity[i] = new Opactiy(); mOpacity[i].mPos = opacity[i][0]; mOpacity[i].mValue = opacity[i][1] / 255.f; } buildOpacityTable(); buildMaterialProp(); } public void setup(int start, int end) { int[] pos = {1050, 1140, 1200, 1210, 1231}; mMaterialProp = new MaterialProp[pos.length]; float diffuse = .7f; float specular = .0f; float ambient = .3f; for (int i = 0; i < pos.length; i++) { mMaterialProp[i] = new MaterialProp(); mMaterialProp[i].mAmbient = ambient; mMaterialProp[i].mSpecular = specular; mMaterialProp[i].mDiffuse = diffuse; mMaterialProp[i].mPos = pos[i]; float t = i / (float) (pos.length - 1); int rgb = (int) (Math.random() * 0xFFFFFF); mMaterialProp[i].mRed = (rgb >> 16) & 0xff; mMaterialProp[i].mGreen = (rgb >> 8) & 0xff; mMaterialProp[i].mBlue = (rgb >> 0) & 0xff; } mOpacity = new Opactiy[2]; mOpacity[0] = new Opactiy(); mOpacity[0].mPos = start; mOpacity[0].mValue = 0; mOpacity[1] = new Opactiy(); mOpacity[1].mPos = end; mOpacity[1].mValue = 1; buildOpacityTable(); buildMaterialProp(); } void buildOpacityTable() { if (mOpacity.length == 0) { return; } for (int i = Short.MIN_VALUE; i <= mOpacity[0].mPos; i++) { int p = i & 0xFFFF; mOpacityTable[p] = (byte) (mOpacity[0].mValue * 255); } for (int k = 0; k < mOpacity.length - 1; k++) { for (int i = mOpacity[k].mPos; i < mOpacity[k + 1].mPos; i++) { int p = i & 0xFFFF; float dist = mOpacity[k + 1].mPos - mOpacity[k].mPos; float t = (i - mOpacity[k].mPos) / dist; float v = mOpacity[k].mValue * (1 - t) + t * mOpacity[k + 1].mValue; mOpacityTable[p] = (byte) (v * 255); } } int last = mOpacity.length - 1; for (int i = mOpacity[last].mPos; i <= Short.MAX_VALUE; i++) { int p = i & 0xFFFF; mOpacityTable[p] = (byte) (mOpacity[last].mValue * 255); } } public void buildMaterialProp() { MaterialProp[] m = mMaterialProp; if (m.length == 0) { return; } { MaterialProp mp = m[0]; int red = m[0].mRed; int green = m[0].mGreen; int blue = m[0].mBlue; for (int i = Short.MIN_VALUE; i <= m[0].mPos; i++) { int p = STRIDE * (i & 0xFFFF); mColor[p + RED] = (byte) red; mColor[p + GREEN] = (byte) green; mColor[p + BLUE] = (byte) blue; mColor[p + DIFF] = (byte) (255 * mp.mDiffuse); mColor[p + SPEC] = (byte) (255 * mp.mSpecular); mColor[p + AMB] = (byte) (255 * mp.mAmbient); } } for (int k = 0; k < m.length - 1; k++) { for (int i = m[k].mPos; i < m[k + 1].mPos; i++) { int p = STRIDE * (i & 0xFFFF); float dist = m[k + 1].mPos - m[k].mPos; float t2 = (i - m[k].mPos) / dist; float t1 = 1 - t2; int red = (int) (m[k].mRed * t1 + m[k + 1].mRed * t2); int green = (int) (m[k].mGreen * t1 + m[k + 1].mGreen * t2); int blue = (int) (m[k].mBlue * t1 + m[k + 1].mBlue * t2); float diffuse = m[k].mDiffuse * t1 + m[k + 1].mDiffuse * t2; float specular = m[k].mSpecular * t1 + m[k + 1].mSpecular * t2; float ambient = m[k].mAmbient * t1 + m[k + 1].mAmbient * t2; mColor[p + RED] = (byte) red; mColor[p + GREEN] = (byte) green; mColor[p + BLUE] = (byte) blue; mColor[p + DIFF] = (byte) (255 * diffuse); mColor[p + SPEC] = (byte) (255 * specular); mColor[p + AMB] = (byte) (255 * ambient); } } { int last = m.length - 1; MaterialProp mp = m[last]; int red = mp.mRed; int green = mp.mGreen; int blue = mp.mBlue; for (int i = mp.mPos; i <= Short.MAX_VALUE; i++) { int p = STRIDE * (i & 0xFFFF); mColor[p + RED] = (byte) red; mColor[p + GREEN] = (byte) green; mColor[p + BLUE] = (byte) blue; mColor[p + DIFF] = (byte) (255 * mp.mDiffuse); mColor[p + SPEC] = (byte) (255 * mp.mSpecular); mColor[p + AMB] = (byte) (255 * mp.mAmbient); } } } public Allocation getOpacityAllocation(RenderScript rs) { if (mOpacityAllocation == null) { Type.Builder b = new Type.Builder(rs, Element.U8(rs)); b.setX(mOpacityTable.length); mOpacityAllocation = Allocation.createTyped(rs, b.create()); } mOpacityAllocation.copyFromUnchecked(mOpacityTable); return mOpacityAllocation; } public Allocation getColorMapAllocation(RenderScript rs) { if (mColorMapAllocation == null) { Type.Builder b = new Type.Builder(rs, Element.U8_4(rs)); b.setX(mColor.length / 4); mColorMapAllocation = Allocation.createTyped(rs, b.create()); } mColorMapAllocation.copyFromUnchecked(mColor); return mColorMapAllocation; } }