Add refraction and bettr normals computation to FallRS
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
<application android:label="FallRS">
|
||||
|
||||
<activity
|
||||
android:screenOrientation="portrait"
|
||||
android:name="Fall"
|
||||
android:theme="@android:style/Theme.NoTitleBar">
|
||||
|
||||
|
||||
BIN
libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
Normal file
BIN
libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 223 KiB |
@@ -27,6 +27,7 @@
|
||||
#define RSID_RIPPLE_INDEX 6
|
||||
#define RSID_DROP_X 7
|
||||
#define RSID_DROP_Y 8
|
||||
#define RSID_RUNNING 9
|
||||
|
||||
#define RSID_TEXTURES 1
|
||||
|
||||
@@ -35,7 +36,7 @@
|
||||
#define RSID_REFRACTION_MAP 3
|
||||
|
||||
#define REFRACTION 1.333f
|
||||
#define DAMP 4
|
||||
#define DAMP 3
|
||||
|
||||
#define DROP_RADIUS 2
|
||||
// The higher, the smaller the ripple
|
||||
@@ -113,6 +114,20 @@ void updateRipples() {
|
||||
}
|
||||
}
|
||||
|
||||
int refraction(int d, int wave) {
|
||||
int* map = loadArrayI32(RSID_REFRACTION_MAP, 0);
|
||||
int i = d;
|
||||
if (i < 0) i = -i;
|
||||
if (i > 512) i = 512;
|
||||
int w = (wave + 0x10000) >> 8;
|
||||
w &= ~(w >> 31);
|
||||
int r = (map[i] * w) >> 3;
|
||||
if (d < 0) {
|
||||
return -r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void generateRipples() {
|
||||
int rippleMapSize = loadI32(RSID_STATE, RSID_RIPPLE_MAP_SIZE);
|
||||
int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
|
||||
@@ -135,6 +150,19 @@ void generateRipples() {
|
||||
int dx = nextWave - wave;
|
||||
int dy = current[b] - wave;
|
||||
|
||||
int offsetx = refraction(dx, wave) >> 16;
|
||||
int u = (width - w) + offsetx;
|
||||
u &= ~(u >> 31);
|
||||
if (u >= width) u = width - 1;
|
||||
|
||||
int offsety = refraction(dy, wave) >> 16;
|
||||
int v = (height - h) + offsety;
|
||||
v &= ~(v >> 31);
|
||||
if (v >= height) v = height - 1;
|
||||
|
||||
vertices[(offset + w) * 8 + 3] = u / (float) width;
|
||||
vertices[(offset + w) * 8 + 4] = v / (float) height;
|
||||
|
||||
// Update Z coordinate of the vertex
|
||||
vertices[(offset + w) * 8 + 7] = (dy / 512.0f) / RIPPLE_HEIGHT;
|
||||
|
||||
@@ -187,13 +215,67 @@ void generateRipples() {
|
||||
n3x /= len;
|
||||
n3y /= len;
|
||||
n3z /= len;
|
||||
|
||||
// V2
|
||||
v2x = vertices[(yOffset + width + x + 1) * 8 + 5];
|
||||
v2y = vertices[(yOffset + width + x + 1) * 8 + 6];
|
||||
v2z = vertices[(yOffset + width + x + 1) * 8 + 7];
|
||||
|
||||
vertices[(yOffset + x) * 8 + 0] = -n3x;
|
||||
vertices[(yOffset + x) * 8 + 1] = -n3y;
|
||||
// N1
|
||||
n1x = v2x - v1x;
|
||||
n1y = v2y - v1y;
|
||||
n1z = v2z - v1z;
|
||||
|
||||
// N2
|
||||
n2x = v3x - v1x;
|
||||
n2y = v3y - v1y;
|
||||
n2z = v3z - v1z;
|
||||
|
||||
// Avegare of previous normal and N1 x N2
|
||||
n3x = n3x / 2.0f + (n1y * n2z - n1z * n2y) / 2.0f;
|
||||
n3y = n3y / 2.0f + (n1z * n2x - n1x * n2z) / 2.0f;
|
||||
n3z = n3z / 2.0f + (n1x * n2y - n1y * n2x) / 2.0f;
|
||||
|
||||
// Normalize
|
||||
len = magf3(n3x, n3y, n3z);
|
||||
n3x /= len;
|
||||
n3y /= len;
|
||||
n3z /= len;
|
||||
|
||||
vertices[(yOffset + x) * 8 + 0] = n3x;
|
||||
vertices[(yOffset + x) * 8 + 1] = n3y;
|
||||
vertices[(yOffset + x) * 8 + 2] = -n3z;
|
||||
|
||||
// reset Z
|
||||
vertices[(yOffset + x) * 8 + 7] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawNormals() {
|
||||
int width = loadI32(RSID_STATE, RSID_MESH_WIDTH);
|
||||
int height = loadI32(RSID_STATE, RSID_MESH_HEIGHT);
|
||||
|
||||
float *vertices = loadTriangleMeshVerticesF(NAMED_mesh);
|
||||
|
||||
bindProgramVertex(NAMED_PVLines);
|
||||
color(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
int y = 0;
|
||||
for ( ; y < height; y++) {
|
||||
int yOffset = y * width;
|
||||
int x = 0;
|
||||
for ( ; x < width; x++) {
|
||||
float vx = vertices[(yOffset + x) * 8 + 5];
|
||||
float vy = vertices[(yOffset + x) * 8 + 6];
|
||||
float vz = vertices[(yOffset + x) * 8 + 7];
|
||||
float nx = vertices[(yOffset + x) * 8 + 0];
|
||||
float ny = vertices[(yOffset + x) * 8 + 1];
|
||||
float nz = vertices[(yOffset + x) * 8 + 2];
|
||||
drawLine(vx, vy, vz, vx + nx / 10.0f, vy + ny / 10.0f, vz + nz / 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int index) {
|
||||
int dropX = loadI32(RSID_STATE, RSID_DROP_X);
|
||||
@@ -204,13 +286,33 @@ int main(int index) {
|
||||
storeI32(RSID_STATE, RSID_DROP_Y, -1);
|
||||
}
|
||||
|
||||
updateRipples();
|
||||
generateRipples();
|
||||
updateTriangleMesh(NAMED_mesh);
|
||||
int isRunning = loadI32(RSID_STATE, RSID_RUNNING);
|
||||
if (isRunning) {
|
||||
updateRipples();
|
||||
generateRipples();
|
||||
updateTriangleMesh(NAMED_mesh);
|
||||
}
|
||||
|
||||
ambient(0.0f, 0.1f, 0.9f, 1.0f);
|
||||
diffuse(0.0f, 0.1f, 0.9f, 1.0f);
|
||||
drawTriangleMesh(NAMED_mesh);
|
||||
bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
|
||||
drawTriangleMesh(NAMED_mesh);
|
||||
|
||||
ambient(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
diffuse(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
specular(0.44f, 0.44f, 0.44f, 1.0f);
|
||||
shininess(40.0f);
|
||||
bindProgramFragment(NAMED_PFLighting);
|
||||
drawTriangleMesh(NAMED_mesh);
|
||||
|
||||
// bindProgramVertex(NAMED_PVSky);
|
||||
// bindProgramFragment(NAMED_PFSky);
|
||||
// bindProgramFragmentStore(NAMED_PFSSky);
|
||||
// color(1.0f, 1.0f, 1.0f, 0.30f);
|
||||
// bindTexture(NAMED_PFSky, 0, NAMED_TSky);
|
||||
// drawTriangleMesh(NAMED_mesh);
|
||||
|
||||
if (!isRunning) {
|
||||
drawNormals();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ import static android.renderscript.ProgramStore.BlendDstFunc;
|
||||
import static android.renderscript.ProgramStore.BlendSrcFunc;
|
||||
import static android.renderscript.ProgramFragment.EnvMode.*;
|
||||
import static android.renderscript.Element.*;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
@@ -51,17 +49,20 @@ class FallRS {
|
||||
private static final int RSID_STATE_RIPPLE_INDEX = 6;
|
||||
private static final int RSID_STATE_DROP_X = 7;
|
||||
private static final int RSID_STATE_DROP_Y = 8;
|
||||
private static final int RSID_STATE_RUNNING = 9;
|
||||
|
||||
private static final int RSID_TEXTURES = 1;
|
||||
private static final int TEXTURES_COUNT = 0;
|
||||
private static final int TEXTURES_COUNT = 1;
|
||||
private static final int RSID_TEXTURE_RIVERBED = 0;
|
||||
|
||||
private static final int RSID_RIPPLE_MAP = 2;
|
||||
|
||||
private static final int RSID_REFRACTION_MAP = 3;
|
||||
|
||||
private boolean mIsRunning = true;
|
||||
|
||||
private Resources mResources;
|
||||
private RenderScript mRS;
|
||||
private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
|
||||
|
||||
private final int mWidth;
|
||||
private final int mHeight;
|
||||
@@ -69,8 +70,10 @@ class FallRS {
|
||||
private ScriptC mScript;
|
||||
private Sampler mSampler;
|
||||
private ProgramFragment mPfBackground;
|
||||
private ProgramFragment mPfLighting;
|
||||
private ProgramStore mPfsBackground;
|
||||
private ProgramVertex mPvBackground;
|
||||
private ProgramVertex mPvLines;
|
||||
private ProgramVertex.MatrixAllocation mPvOrthoAlloc;
|
||||
private Light mLight;
|
||||
|
||||
@@ -89,8 +92,6 @@ class FallRS {
|
||||
public FallRS(int width, int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mBitmapOptions.inScaled = false;
|
||||
mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
||||
}
|
||||
|
||||
public void init(RenderScript rs, Resources res) {
|
||||
@@ -116,6 +117,8 @@ class FallRS {
|
||||
mLight.destroy();
|
||||
mRippleMap.destroy();
|
||||
mRefractionMap.destroy();
|
||||
mPvLines.destroy();
|
||||
mPfLighting.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,10 +180,11 @@ class FallRS {
|
||||
|
||||
for (int y = 0; y <= hResolution; y++) {
|
||||
final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
|
||||
final float t = 1.0f - y / (float) hResolution;
|
||||
for (int x = 0; x <= wResolution; x++) {
|
||||
rs.triangleMeshAddVertex_XYZ_ST_NORM(
|
||||
-1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
|
||||
x / (float) wResolution, y / (float) wResolution,
|
||||
x / (float) wResolution, t,
|
||||
0.0f, 0.0f, -1.0f);
|
||||
}
|
||||
}
|
||||
@@ -204,7 +208,7 @@ class FallRS {
|
||||
private void createScriptStructures() {
|
||||
final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
|
||||
|
||||
final int[] data = new int[9];
|
||||
final int[] data = new int[10];
|
||||
mState = Allocation.createSized(mRS, USER_I32, data.length);
|
||||
data[RSID_STATE_FRAMECOUNT] = 0;
|
||||
data[RSID_STATE_WIDTH] = mWidth;
|
||||
@@ -215,6 +219,7 @@ class FallRS {
|
||||
data[RSID_STATE_RIPPLE_INDEX] = 0;
|
||||
data[RSID_STATE_DROP_X] = mMeshWidth / 2;
|
||||
data[RSID_STATE_DROP_Y] = mMeshHeight / 2;
|
||||
data[RSID_STATE_RUNNING] = 1;
|
||||
mState.data(data);
|
||||
|
||||
final int[] rippleMap = new int[rippleMapSize * 2];
|
||||
@@ -236,7 +241,7 @@ class FallRS {
|
||||
mTexturesIDs = Allocation.createSized(mRS, USER_FLOAT, TEXTURES_COUNT);
|
||||
|
||||
final Allocation[] textures = mTextures;
|
||||
// TOOD: Load textures
|
||||
textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
|
||||
|
||||
final int[] bufferIds = mTextureBufferIDs;
|
||||
final int count = textures.length;
|
||||
@@ -257,15 +262,6 @@ class FallRS {
|
||||
return allocation;
|
||||
}
|
||||
|
||||
private Allocation loadTextureARGB(int id, String name) {
|
||||
// Forces ARGB 32 bits, because pngcrush sometimes optimize our PNGs to
|
||||
// indexed pictures, which are not well supported
|
||||
final Bitmap b = BitmapFactory.decodeResource(mResources, id, mBitmapOptions);
|
||||
final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false);
|
||||
allocation.setName(name);
|
||||
return allocation;
|
||||
}
|
||||
|
||||
private void createProgramFragment() {
|
||||
Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
|
||||
sampleBuilder.setMin(LINEAR);
|
||||
@@ -280,12 +276,18 @@ class FallRS {
|
||||
mPfBackground = builder.create();
|
||||
mPfBackground.setName("PFBackground");
|
||||
mPfBackground.bindSampler(mSampler, 0);
|
||||
|
||||
builder = new ProgramFragment.Builder(mRS, null, null);
|
||||
builder.setTexEnable(false, 0);
|
||||
mPfLighting = builder.create();
|
||||
mPfLighting.setName("PFLighting");
|
||||
mPfLighting.bindSampler(mSampler, 0);
|
||||
}
|
||||
|
||||
private void createProgramFragmentStore() {
|
||||
ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
|
||||
builder.setDepthFunc(LESS);
|
||||
builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
|
||||
builder.setDepthFunc(ALWAYS);
|
||||
builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
|
||||
builder.setDitherEnable(true);
|
||||
builder.setDepthMask(true);
|
||||
mPfsBackground = builder.create();
|
||||
@@ -297,7 +299,7 @@ class FallRS {
|
||||
mPvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
|
||||
|
||||
mLight = new Light.Builder(mRS).create();
|
||||
mLight.setPosition(0.0f, 0.0f, -1.0f);
|
||||
mLight.setPosition(0.0f, 2.0f, -8.0f);
|
||||
|
||||
ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
|
||||
builder.setTextureMatrixEnable(true);
|
||||
@@ -305,11 +307,21 @@ class FallRS {
|
||||
mPvBackground = builder.create();
|
||||
mPvBackground.bindAllocation(mPvOrthoAlloc);
|
||||
mPvBackground.setName("PVBackground");
|
||||
|
||||
builder = new ProgramVertex.Builder(mRS, null, null);
|
||||
mPvLines = builder.create();
|
||||
mPvLines.bindAllocation(mPvOrthoAlloc);
|
||||
mPvLines.setName("PVLines");
|
||||
}
|
||||
|
||||
public void addDrop(float x, float y) {
|
||||
void addDrop(float x, float y) {
|
||||
mState.subData1D(RSID_STATE_DROP_X, 2, new int[] {
|
||||
(int) ((x / mWidth) * mMeshWidth), (int) ((y / mHeight) * mMeshHeight)
|
||||
});
|
||||
}
|
||||
|
||||
void togglePause() {
|
||||
mIsRunning = !mIsRunning;
|
||||
mState.subData1D(RSID_STATE_RUNNING, 1, new int[] { mIsRunning ? 1 : 0 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.android.fall.rs;
|
||||
import android.content.Context;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.KeyEvent;
|
||||
import android.renderscript.RenderScript;
|
||||
import android.renderscript.RSSurfaceView;
|
||||
|
||||
@@ -28,6 +29,8 @@ class FallView extends RSSurfaceView {
|
||||
|
||||
public FallView(Context context) {
|
||||
super(context);
|
||||
setFocusable(true);
|
||||
setFocusableInTouchMode(true);
|
||||
}
|
||||
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
||||
@@ -43,6 +46,15 @@ class FallView extends RSSurfaceView {
|
||||
if (mRender != null) mRender.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
|
||||
keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
mRender.togglePause();
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
switch (event.getAction()) {
|
||||
|
||||
@@ -544,6 +544,24 @@ static void SC_drawTriangleArray(int ialloc, uint32_t count)
|
||||
glDrawArrays(GL_TRIANGLES, 0, count * 3);
|
||||
}
|
||||
|
||||
static void SC_drawLine(float x1, float y1, float z1,
|
||||
float x2, float y2, float z2)
|
||||
{
|
||||
GET_TLS();
|
||||
rsc->setupCheck();
|
||||
|
||||
float vtx[] = { x1, y1, z1, x2, y2, z2 };
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glVertexPointer(3, GL_FLOAT, 0, vtx);
|
||||
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glDrawArrays(GL_LINES, 0, 2);
|
||||
}
|
||||
|
||||
static void SC_drawQuad(float x1, float y1, float z1,
|
||||
float x2, float y2, float z2,
|
||||
float x3, float y3, float z3,
|
||||
@@ -627,10 +645,9 @@ static void SC_emission(float r, float g, float b, float a)
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, params);
|
||||
}
|
||||
|
||||
static void SC_shininess(float r, float g, float b, float a)
|
||||
static void SC_shininess(float s)
|
||||
{
|
||||
GLfloat params[] = { r, g, b, a };
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, params);
|
||||
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, s);
|
||||
}
|
||||
|
||||
static void SC_hsb(float h, float s, float b, float a)
|
||||
@@ -686,25 +703,6 @@ static void SC_hsb(float h, float s, float b, float a)
|
||||
glColor4f(red, green, blue, a);
|
||||
}
|
||||
|
||||
/*
|
||||
extern "C" void materialDiffuse(float r, float g, float b, float a)
|
||||
{
|
||||
float v[] = {r, g, b, a};
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, v);
|
||||
}
|
||||
|
||||
extern "C" void materialSpecular(float r, float g, float b, float a)
|
||||
{
|
||||
float v[] = {r, g, b, a};
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
|
||||
}
|
||||
|
||||
extern "C" void materialShininess(float s)
|
||||
{
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &s);
|
||||
}
|
||||
*/
|
||||
|
||||
static void SC_uploadToTexture(RsAllocation va, uint32_t baseMipLevel)
|
||||
{
|
||||
GET_TLS();
|
||||
@@ -903,6 +901,8 @@ ScriptCState::SymbolTable_t ScriptCState::gSyms[] = {
|
||||
"void", "(int mesh)" },
|
||||
{ "drawTriangleMeshRange", (void *)&SC_drawTriangleMeshRange,
|
||||
"void", "(int mesh, int start, int count)" },
|
||||
{ "drawLine", (void *)&SC_drawLine,
|
||||
"void", "(float x1, float y1, float z1, float x2, float y2, float z2)" },
|
||||
|
||||
|
||||
// misc
|
||||
@@ -921,7 +921,7 @@ ScriptCState::SymbolTable_t ScriptCState::gSyms[] = {
|
||||
{ "emission", (void *)&SC_emission,
|
||||
"void", "(float, float, float, float)" },
|
||||
{ "shininess", (void *)&SC_shininess,
|
||||
"void", "(float, float, float, float)" },
|
||||
"void", "(float)" },
|
||||
|
||||
{ "uploadToTexture", (void *)&SC_uploadToTexture,
|
||||
"void", "(int, int)" },
|
||||
|
||||
Reference in New Issue
Block a user