/*
* 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;
}
}