实现三星S3蒲公英水波纹效果(二)——Renderscript准备篇

这篇主要是关于Android RenderScript 的使用。

RenderScript简介:RenderScript是Android平台的一种类C脚本语言,Google虽然一直在之前的各个Android版本内置的动态墙纸中使用该技术实现3D图形特效,但一直未将其集成在公开发布的SDK中。至Android3.0版本开始,SDK中已将RenderScript技术集成了进来,开发者可在Eclipse下开发基于RenderScript的3D应用,并在Android3.0版本以上的平板电脑中运行。

SDK链接:http://developer.android.com/guide/topics/renderscript/index.html

要使用Renderscript渲染功能,需要实现的功能如下:

fall.rs          实现RenderScript的代码,是水波纹效果实现的关键代码(但关于.rs文件的资料少之又少,希望今后会多起来)

FallRS.java      .rs文件的辅助类,用以简化操作fall.rs文件 
FallView.java    一个继承于RSSurfaceView的类,用于显示RenderScript的渲染或者用来处理用户的触摸等视图

Fall.java        这是一个Activity,Android 应用程序的界面类。

 

好了先来看fall.rs文件(中文是我加的注释):

// Copyright (C) 2009 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.

//编译指示声明(#pragma version(1)),声明了要使用的Renderscript的版本(目前只能是1)
#pragma version(1)

//编译指示声明(#pragma rs java_package_name(package.name)),它声明了该Renderscript反射所对应的*.java类名
#pragma rs java_package_name(com.harlan.waterscreen)

#include "rs_graphics.rsh"

#define LEAVES_TEXTURES_COUNT 8
#define LEAF_SIZE 0.55f
#define LEAVES_COUNT 14

// Things we need to set from the application
float g_glWidth;
float g_glHeight;
float g_meshWidth;
float g_meshHeight;
float g_xOffset;
float g_rotate;

//着色器处理程序类分为4类:ProgramFragment ProgramFragmentStore ProgramVertext Mesh
//ProgramFragment对应片断处理程序,对光栅化的每一个片断做独立的处理,包括映射纹理点,混合,着色等。
//ProgramFragmentStore主要负责一些跟片断处理相关的辅助功能,如设置混合模式等。
//ProgramVertext对应顶点处理程序,对每一个顶点做独立的处理,包括视景投影变换,法线变换等。
//Mesh又叫网格,是方便对一组顶点的处理的类。
//以上四个类最终都会被调用setupGL或render这样方法,在这些方法中将用户的配置转换为OpenGL的具体操作序列。

rs_program_vertex g_PVWater;
rs_program_vertex g_PVSky;

rs_program_fragment g_PFSky;
rs_program_store g_PFSLeaf;
rs_program_fragment g_PFBackground;

rs_allocation g_TLeaves;
rs_allocation g_TRiverbed;

rs_mesh g_WaterMesh;

//存储类,主要用来进行数据的存储以及和上层java的交换,包括Type,Element,Allocation。Element可以理解为一个结构体。
//下面是一个element;Constants是对这个结构体的类型的命名,Constants_t 就是这个Constants。
typedef struct Constants {
    float4 Drop01;
    float4 Drop02;
    float4 Drop03;
    float4 Drop04;
    float4 Drop05;
    float4 Drop06;
    float4 Drop07;
    float4 Drop08;
    float4 Drop09;
    float4 Drop10;
    float4 Offset;
    float Rotate;
} Constants_t;
//这是一个Constants_t的一个实例,是一个Allocation
//在RenderScript运行之前,必要的Allocation要分配好,它们可能是定点坐标,可能是纹理,也可能是用户的数据
Constants_t *g_Constants;
rs_program_store g_PFSBackground;

//float skyOffsetX;
//float skyOffsetY;
static float g_DT;
static int64_t g_LastTime;

typedef struct Drop {
    float ampS;
    float ampE;
    float spread;
    float x;
    float y;
} Drop_t;
static Drop_t gDrops[10];
static int gMaxDrops;

typedef struct Leaves {
    float x;
    float y;
    float scale;
    float angle;
    float spin;
    float u1;
    float u2;
    float altitude;
    float rippled;
    float deltaX;
    float deltaY;
    int newLeaf;
} Leaves_t;

static Leaves_t gLeavesStore[LEAVES_COUNT];
static Leaves_t* gLeaves[LEAVES_COUNT];
static Leaves_t* gNextLeaves[LEAVES_COUNT];

void initLeaves() {
    Leaves_t *leaf = gLeavesStore;
    // globals haven't been set at this point yet. We need to find the correct
    // function index to call this, we can wait until reflection works
    float width = 2; //g_glWidth;
    float height = 3.333; //g_glHeight;

    int i;
    for (i = 0; i < LEAVES_COUNT; i ++) {
        gLeaves[i] = leaf;
        int sprite = rsRand(LEAVES_TEXTURES_COUNT);
        leaf->x = rsRand(-width, width);
        leaf->y = rsRand(-height * 0.5f, height * 0.5f);
        leaf->scale = rsRand(0.4f, 0.5f);
        leaf->angle = rsRand(0.0f, 360.0f);
        leaf->spin = degrees(rsRand(-0.02f, 0.02f)) * 0.25f;
        leaf->u1 = (float)sprite / (float) LEAVES_TEXTURES_COUNT;
        leaf->u2 = (float)(sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
        leaf->altitude = -1.0f;
        leaf->rippled = 1.0f;
        leaf->deltaX = rsRand(-0.01f, 0.01f);
        leaf->deltaY = -rsRand(0.036f, 0.044f);
        leaf++;
    }
}

//一个可选的init()方法,在root()方法调用之前做一些初始化工作,如初始化变量等。
//这个函数运行一次,并且在Renderscript启动时,Renderscript中其他工作被执行之前,该方法会被自动的调用。
void init() {
    int ct;
    gMaxDrops = 10;
    for (ct=0; ct<gMaxDrops; ct++) {
        gDrops[ct].ampS = 0;
        gDrops[ct].ampE = 0;
        gDrops[ct].spread = 1;
    }

    initLeaves();
    g_LastTime = rsUptimeMillis();
    g_DT = 0.1f;
}

static void updateDrop(int ct) {
    gDrops[ct].spread += 30.f * g_DT;
    gDrops[ct].ampE = gDrops[ct].ampS / gDrops[ct].spread;
}

static void drop(int x, int y, float s) {
    int ct;
    int iMin = 0;
    float minAmp = 10000.f;
    for (ct = 0; ct < gMaxDrops; ct++) {
        if (gDrops[ct].ampE < minAmp) {
            iMin = ct;
            minAmp = gDrops[ct].ampE;
        }
    }
    gDrops[iMin].ampS = s;
    gDrops[iMin].spread = 0;
    gDrops[iMin].x = x;
    gDrops[iMin].y = g_meshHeight - y - 1;
    updateDrop(iMin);
}

//绘制水波纹涟漪
static void generateRipples() {
    int ct;
    for (ct = 0; ct < gMaxDrops; ct++) {
        Drop_t * d = &gDrops[ct];
        float *v = (float*)&g_Constants->Drop01;
        v += ct*4;
        *(v++) = d->x;
        *(v++) = d->y;
        *(v++) = d->ampE * 0.12f;
        *(v++) = d->spread;
    }
    g_Constants->Offset.x = g_xOffset;

    for (ct = 0; ct < gMaxDrops; ct++) {
        updateDrop(ct);
    }
}

//根据落叶位置绘制水波纹
static void genLeafDrop(Leaves_t *leaf, float amp) {
    float nx = (leaf->x + g_glWidth * 0.5f) / g_glWidth;
    float ny = (leaf->y + g_glHeight * 0.5f) / g_glHeight;
    drop(nx * g_meshWidth, g_meshHeight - ny * g_meshHeight, amp);
}

//绘制单片落叶
static int drawLeaf(Leaves_t *leaf) {

    float x = leaf->x;
    float y = leaf->y;

    float u1 = leaf->u1;
    float u2 = leaf->u2;

    float a = leaf->altitude;
    float s = leaf->scale;
    float r = leaf->angle;

    float tz = 0.0f;
    if (a > 0.0f) {
        tz = -a;
    }

    rs_matrix4x4 matrix;
    if (a > 0.0f) {

        float alpha = 1.0f;
        if (a >= 0.4f) alpha = 1.0f - (a - 0.4f) / 0.1f;

        rsgProgramFragmentConstantColor(g_PFSky, 0.0f, 0.0f, 0.0f, alpha * 0.15f);

        rsMatrixLoadIdentity(&matrix);
        if (!g_rotate) {
            rsMatrixTranslate(&matrix, x - g_xOffset * 2, y, 0);
        } else {
            rsMatrixTranslate(&matrix, x, y, 0);
            rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f);
        }

        float shadowOffet = a * 0.2f;

        rsMatrixScale(&matrix, s, s, 1.0f);
        rsMatrixRotate(&matrix, r, 0.0f, 0.0f, 1.0f);
        rsgProgramVertexLoadModelMatrix(&matrix);

        rsgDrawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f,
                           LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f,
                           LEAF_SIZE,  LEAF_SIZE, 0, u2, 0.0f,
                          -LEAF_SIZE,  LEAF_SIZE, 0, u1, 0.0f);

        rsgProgramFragmentConstantColor(g_PFSky, 1.0f, 1.0f, 1.0f, alpha);
    } else {
        rsgProgramFragmentConstantColor(g_PFSky, 1.0f, 1.0f, 1.0f, 1.0f);
    }

    rsMatrixLoadIdentity(&matrix);
    if (!g_rotate) {
        rsMatrixTranslate(&matrix, x - g_xOffset * 2, y, tz);
    } else {
        rsMatrixTranslate(&matrix, x, y, tz);
        rsMatrixRotate(&matrix, 90.0f, 0.0f, 0.0f, 1.0f);
    }
    rsMatrixScale(&matrix, s, s, 1.0f);
    rsMatrixRotate(&matrix, r, 0.0f, 0.0f, 1.0f);
    rsgProgramVertexLoadModelMatrix(&matrix);

    rsgDrawQuadTexCoords(-LEAF_SIZE, -LEAF_SIZE, 0, u1, 1.0f,
                       LEAF_SIZE, -LEAF_SIZE, 0, u2, 1.0f,
                       LEAF_SIZE,  LEAF_SIZE, 0, u2, 0.0f,
                      -LEAF_SIZE,  LEAF_SIZE, 0, u1, 0.0f);

    float spin = leaf->spin;
    if (a <= 0.0f) {
        float rippled = leaf->rippled;
        if (rippled < 0.0f) {
            genLeafDrop(leaf, 1.5f);
            //drop(((x + g_glWidth * 0.5f) / g_glWidth) * meshWidth,
            //     meshHeight - ((y + g_glHeight * 0.5f) / g_glHeight) * meshHeight, 1);
            spin *= 0.25f;
            leaf->spin = spin;
            leaf->rippled = 1.0f;
        }
        leaf->x = x + leaf->deltaX * g_DT;
        leaf->y = y + leaf->deltaY * g_DT;
        r += spin;
        leaf->angle = r;
    } else {
        a -= 0.15f * g_DT;
        leaf->altitude = a;
        r += spin * 2.0f;
        leaf->angle = r;
    }

    int newLeaf = 0;
    if (-LEAF_SIZE * s + x > g_glWidth || LEAF_SIZE * s + x < -g_glWidth ||
            LEAF_SIZE * s + y < -g_glHeight * 0.5f) {

        int sprite = rsRand(LEAVES_TEXTURES_COUNT);

        leaf->x = rsRand(-g_glWidth, g_glWidth);
        leaf->y = rsRand(-g_glHeight * 0.5f, g_glHeight * 0.5f);

        leaf->scale = rsRand(0.4f, 0.5f);
        leaf->spin = degrees(rsRand(-0.02f, 0.02f)) * 0.35f;
        leaf->u1 = sprite / (float) LEAVES_TEXTURES_COUNT;
        leaf->u2 = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
        leaf->altitude = 0.7f;
        leaf->rippled = -1.0f;
        leaf->deltaX = rsRand(-0.01f, 0.01f);
        leaf->deltaY = -rsRand(0.036f, 0.044f);
        leaf->newLeaf = 1;
        newLeaf = 1;
    }
    return newLeaf;
}

//绘制落叶
static void drawLeaves() {
    rsgBindProgramFragment(g_PFSky);
    rsgBindProgramStore(g_PFSLeaf);
    rsgBindProgramVertex(g_PVSky);
    rsgBindTexture(g_PFSky, 0, g_TLeaves);

    int newLeaves = 0;
    int i = 0;
    for ( ; i < LEAVES_COUNT; i += 1) {
        if (drawLeaf(gLeaves[i])) {
            newLeaves = 1;

        }
    }

    if (newLeaves > 0) {
        int index = 0;

        // Copy all the old leaves to the beginning of gNextLeaves
        for (i=0; i < LEAVES_COUNT; i++) {
            if (gLeaves[i]->newLeaf == 0) {
                gNextLeaves[index] = gLeaves[i];
                index++;
            }
        }

        // Now copy all the newly falling leaves to the end of gNextLeaves
        for (i=0; i < LEAVES_COUNT; i++) {
            if (gLeaves[i]->newLeaf > 0) {
                gNextLeaves[index] = gLeaves[i];
                gNextLeaves[index]->newLeaf = 0;
                index++;
            }
        }

        // And move everything in gNextLeaves back to gLeaves
        for (i=0; i < LEAVES_COUNT; i++) {
            gLeaves[i] = gNextLeaves[i];
        }
    }

    rs_matrix4x4 matrix;
    rsMatrixLoadIdentity(&matrix);
    rsgProgramVertexLoadModelMatrix(&matrix);
}

//绘制水中的倒影
static void drawRiverbed() {
    rsgBindProgramFragment(g_PFBackground);
    rsgBindProgramStore(g_PFSBackground);
    rsgBindTexture(g_PFBackground, 0, g_TRiverbed);
    rsgDrawMesh(g_WaterMesh);
}

//增加水滴的方法,该方法可以在java中被调用
void addDrop(int x, int y) {
    drop(x, y, 2);
}

//主函数,按指定频率反复调用
int root(void) {
    rsgClearColor(0.f, 0.f, 0.f, 1.f);

    // Compute dt in seconds.
    int64_t newTime = rsUptimeMillis();
    g_DT = (newTime - g_LastTime) * 0.001f;
    g_DT = min(g_DT, 0.2f);
    g_LastTime = newTime;

    g_Constants->Rotate = (float) g_rotate;

    int ct;
    int add = 0;
    for (ct = 0; ct < gMaxDrops; ct++) {
        if (gDrops[ct].ampE < 0.005f) {
            add = 1;
        }
    }

    if (add) {
        int i = (int)rsRand(LEAVES_COUNT);
        genLeafDrop(gLeaves[i], rsRand(0.3f) + 0.1f);
    }

    rsgBindProgramVertex(g_PVWater);
    generateRipples();
    rsgAllocationSyncAll(rsGetAllocation(g_Constants));
    drawRiverbed();
//程序中我们不需要绘制落叶,所以讲下面这行注释掉
    //drawLeaves();

//这个表示界面刷新的频率,50ms
    return 50;
}

其实整个fall.rs源码我们就只改动了一行,注释掉了主函数中的drawLeaves(),这样,就没有落叶飘下了。

 

下面,是FallRS.java 文件。原来这几行报错:

import static android.util.MathUtils.*;
import com.android.wallpaper.R;
import com.android.wallpaper.RenderScriptScene;

So Easy,ctrl+O解决。顺便将这个工程里类似的错误都改下。

结果只报一个错,FallRS.java里面的random(float,float)方法没有定义。

那就加上一个random方法:百度android.util.MathUtils,得到其中的random方法,将其加到FallRS.java文件的末尾:

 public static float random(float howsmall, float howbig) {  

         if (howsmall >= howbig) return howsmall;  
         Random sRandom = new Random(); 
         return sRandom.nextFloat() * (howbig - howsmall) + howsmall;  

    } 


此时,整个工程都没有错误了。

 

FallRS继承自RenderScriptScene,并覆写了其中两个方法:

 @Override
    public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
        mWorldState.xOffset = xOffset;
        mScript.set_g_xOffset(mWorldState.xOffset);
    }

    @Override
    public Bundle onCommand(String action, int x, int y, int z, Bundle extras,
            boolean resultRequested) {
        if (WallpaperManager.COMMAND_TAP.equals(action)
                || WallpaperManager.COMMAND_SECONDARY_TAP.equals(action)
                || WallpaperManager.COMMAND_DROP.equals(action)) {
            addDrop(x + (mWorldState.rotate == 0 ? (mWorldState.width * mWorldState.xOffset) : 0), y);
        }
        return null;
    }

显然,onCommand方法告诉我们,源码只有在壁纸状态上才调用addDrop方法,而我们是要使其在activity中便能生效。

为了直观,将父类的成员直接写到FallRS里。FallRS不再继承RenderScriptScene类。

修改后的FallRS代码(中文是我加的注释)

/*
 * Copyright (C) 2009 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.harlan.waterscreen;

import static android.renderscript.ProgramStore.DepthFunc.ALWAYS;
import static android.renderscript.Sampler.Value.CLAMP;
import static android.renderscript.Sampler.Value.LINEAR;

import java.util.Random;
import java.util.TimeZone;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.renderscript.Allocation;
import android.renderscript.Matrix4f;
import android.renderscript.Mesh;
import android.renderscript.ProgramFragment;
import android.renderscript.ProgramFragmentFixedFunction;
import android.renderscript.ProgramStore;
import android.renderscript.ProgramStore.BlendDstFunc;
import android.renderscript.ProgramStore.BlendSrcFunc;
import android.renderscript.ProgramVertex;
import android.renderscript.ProgramVertexFixedFunction;
import android.renderscript.RenderScriptGL;
import android.renderscript.Sampler;

import com.android.wallpaper.fall.ScriptC_fall;
import com.android.wallpaper.fall.ScriptField_Constants;

//class FallRS extends RenderScriptScene {
class FallRS{
    private static final int MESH_RESOLUTION = 48;

    private static final int RSID_STATE = 0;
    private static final int RSID_CONSTANTS = 1;
    private static final int RSID_DROP = 2;

    private static final int TEXTURES_COUNT = 2;
    private static final int RSID_TEXTURE_RIVERBED = 0;
    private static final int RSID_TEXTURE_LEAVES = 1;

    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();

    @SuppressWarnings({"FieldCanBeLocal"})
    private ProgramFragment mPfBackground;
    @SuppressWarnings({"FieldCanBeLocal"})
    private ProgramFragment mPfSky;
    @SuppressWarnings({"FieldCanBeLocal"})
    private ProgramStore mPfsBackground;
    @SuppressWarnings({"FieldCanBeLocal"})
    private ProgramStore mPfsLeaf;
    @SuppressWarnings({"FieldCanBeLocal"})
    private ProgramVertex mPvSky;
    @SuppressWarnings({"FieldCanBeLocal"})
    private ProgramVertex mPvWater;
    private ProgramVertexFixedFunction.Constants mPvOrthoAlloc;
    @SuppressWarnings({"FieldCanBeLocal"})
    private Sampler mSampler;

    private int mMeshWidth;
    private Allocation mUniformAlloc;

    private int mMeshHeight;
    @SuppressWarnings({"FieldCanBeLocal"})
    private Mesh mMesh;
    private WorldState mWorldState;

    private ScriptC_fall mScript;

    private ScriptField_Constants mConstants;

    private float mGlHeight;
    
    /*******add by harlan****************/
    protected int mWidth;
    protected int mHeight;
    protected boolean mPreview;
    protected Resources mResources;
    protected RenderScriptGL mRS;
//    protected ScriptC mScript;
    /**************************************/

    public FallRS(int width, int height) {
//        super(width, height);
        mWidth = width;
        mHeight = height;

        mOptionsARGB.inScaled = false;
        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
    }

//    @Override
//    public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
//        mWorldState.xOffset = xOffset;
//        mScript.set_g_xOffset(mWorldState.xOffset);
//    }
//
//    @Override
//    public Bundle onCommand(String action, int x, int y, int z, Bundle extras,
//            boolean resultRequested) {
//        if (WallpaperManager.COMMAND_TAP.equals(action)
//                || WallpaperManager.COMMAND_SECONDARY_TAP.equals(action)
//                || WallpaperManager.COMMAND_DROP.equals(action)) {
//            addDrop(x + (mWorldState.rotate == 0 ? (mWorldState.width * mWorldState.xOffset) : 0), y);
//        }
//        return null;
//    }

    /**
     * 绑定脚本
     * <功能详细描述>
     * @see [类、类#方法、类#成员]
     */
//    @Override
    public void start() {
//        super.start();
        mRS.bindRootScript(mScript);
        
        final WorldState worldState = mWorldState;
        final int width = worldState.width;
        final int x = width / 4 + (int)(Math.random() * (width / 2));
        final int y = worldState.height / 4 + (int)(Math.random() * (worldState.height / 2));
        addDrop(x + (mWorldState.rotate == 0 ? (width * worldState.xOffset) : 0), y);
    }

//    @Override
    public void resize(int width, int height) {
//        super.resize(width, height);
        mWidth = width;
        mHeight = height;

        mWorldState.width = width;
        mWorldState.height = height;
        mWorldState.rotate = width > height ? 1 : 0;

        mScript.set_g_glWidth(mWorldState.width);
        mScript.set_g_glHeight(mWorldState.height);
        mScript.set_g_rotate(mWorldState.rotate);

        mScript.invoke_initLeaves();

        Matrix4f proj = new Matrix4f();
        proj.loadProjectionNormalized(mWidth, mHeight);
        mPvOrthoAlloc.setProjection(proj);
    }

    /**
     *生成脚本文件,并做一系列的初始化工作
     * <功能详细描述>
     * @return
     * @see [类、类#方法、类#成员]
     */
//    @Override
//    protected ScriptC createScript() {
    protected ScriptC_fall createScript() {
        mScript = new ScriptC_fall(mRS, mResources, R.raw.fall);

        createMesh();
        createState();
        createProgramVertex();
        createProgramFragmentStore();
        createProgramFragment();
        loadTextures();

        mScript.setTimeZone(TimeZone.getDefault().getID());

        mScript.bind_g_Constants(mConstants);

        return mScript;
    }

    private void createMesh() {
        Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, 2, 0);

        final int width = mWidth > mHeight ? mHeight : mWidth;
        final int height = mWidth > mHeight ? mWidth : mHeight;

        int wResolution = MESH_RESOLUTION;
        int hResolution = (int) (MESH_RESOLUTION * height / (float) width);

        mGlHeight = 2.0f * height / (float) width;

        wResolution += 2;
        hResolution += 2;

        for (int y = 0; y <= hResolution; y++) {
            final float yOffset = (((float)y / hResolution) * 2.f - 1.f) * height / width;
            for (int x = 0; x <= wResolution; x++) {
                tmb.addVertex(((float)x / wResolution) * 2.f - 1.f, yOffset);
            }
        }

        for (int y = 0; y < hResolution; y++) {
            final boolean shift = (y & 0x1) == 0;
            final int yOffset = y * (wResolution + 1);
            for (int x = 0; x < wResolution; x++) {
                final int index = yOffset + x;
                final int iWR1 = index + wResolution + 1;
                if (shift) {
                    tmb.addTriangle(index, index + 1, iWR1);
                    tmb.addTriangle(index + 1, iWR1 + 1, iWR1);
                } else {
                    tmb.addTriangle(index, iWR1 + 1, iWR1);
                    tmb.addTriangle(index, index + 1, iWR1 + 1);
                }
            }
        }

        mMesh = tmb.create(true);

        mMeshWidth = wResolution + 1;
        mMeshHeight = hResolution + 1;

        mScript.set_g_WaterMesh(mMesh);
    }

    static class WorldState {
        public int frameCount;
        public int width;
        public int height;
        public int meshWidth;
        public int meshHeight;
        public int rippleIndex;
        public float glWidth;
        public float glHeight;
        public float skySpeedX;
        public float skySpeedY;
        public int rotate;
        public int isPreview;
        public float xOffset;
    }

    private void createState() {
        mWorldState = new WorldState();
        mWorldState.width = mWidth;
        mWorldState.height = mHeight;
        mWorldState.meshWidth = mMeshWidth;
        mWorldState.meshHeight = mMeshHeight;
        mWorldState.rippleIndex = 0;
        mWorldState.glWidth = 2.0f;
        mWorldState.glHeight = mGlHeight;
        mWorldState.skySpeedX = random(-0.001f, 0.001f);
        mWorldState.skySpeedY = random(0.00008f, 0.0002f);
        mWorldState.rotate = mWidth > mHeight ? 1 : 0;
//        mWorldState.isPreview = isPreview() ? 1 : 0;

        mScript.set_g_glWidth(mWorldState.glWidth);
        mScript.set_g_glHeight(mWorldState.glHeight);
        mScript.set_g_meshWidth(mWorldState.meshWidth);
        mScript.set_g_meshHeight(mWorldState.meshHeight);
        mScript.set_g_xOffset(0);
        mScript.set_g_rotate(mWorldState.rotate);
    }

    private void loadTextures() {
        mScript.set_g_TLeaves(loadTextureARGB(R.drawable.leaves));
        mScript.set_g_TRiverbed(loadTexture(R.drawable.pond));
    }

    private Allocation loadTexture(int id) {
        final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources, id);
        return allocation;
    }

    private Allocation loadTextureARGB(int id) {
        Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
        final Allocation allocation = Allocation.createFromBitmap(mRS, b);
        return allocation;
    }

    private void createProgramFragment() {
        Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
        sampleBuilder.setMinification(LINEAR);
        sampleBuilder.setMagnification(LINEAR);
        sampleBuilder.setWrapS(CLAMP);
        sampleBuilder.setWrapT(CLAMP);
        mSampler = sampleBuilder.create();

        ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
        mPfBackground = builder.create();
        mPfBackground.bindSampler(mSampler, 0);

        mScript.set_g_PFBackground(mPfBackground);

        builder = new ProgramFragmentFixedFunction.Builder(mRS);
        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
        mPfSky = builder.create();
        mPfSky.bindSampler(mSampler, 0);

        mScript.set_g_PFSky(mPfSky);
    }

    private void createProgramFragmentStore() {
        ProgramStore.Builder builder = new ProgramStore.Builder(mRS);
        builder.setDepthFunc(ALWAYS);
        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
        builder.setDitherEnabled(false);
        builder.setDepthMaskEnabled(true);
        mPfsBackground = builder.create();

        builder = new ProgramStore.Builder(mRS);
        builder.setDepthFunc(ALWAYS);
        builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
        builder.setDitherEnabled(false);
        builder.setDepthMaskEnabled(true);
        mPfsLeaf = builder.create();

        mScript.set_g_PFSLeaf(mPfsLeaf);
        mScript.set_g_PFSBackground(mPfsBackground);
    }

    private void createProgramVertex() {
        mPvOrthoAlloc = new ProgramVertexFixedFunction.Constants(mRS);
        Matrix4f proj = new Matrix4f();
        proj.loadProjectionNormalized(mWidth, mHeight);
        mPvOrthoAlloc.setProjection(proj);


        ProgramVertexFixedFunction.Builder builder = new ProgramVertexFixedFunction.Builder(mRS);
        mPvSky = builder.create();
        ((ProgramVertexFixedFunction)mPvSky).bindConstants(mPvOrthoAlloc);

        mScript.set_g_PVSky(mPvSky);

        mConstants = new ScriptField_Constants(mRS, 1);
        mUniformAlloc = mConstants.getAllocation();

        ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);

        String t = "\n" +
                "varying vec4 varColor;\n" +
                "varying vec2 varTex0;\n" +

                "vec2 addDrop(vec4 d, vec2 pos, float dxMul) {\n" +
                "  vec2 ret = vec2(0.0, 0.0);\n" +
                "  vec2 delta = d.xy - pos;\n" +
                "  delta.x *= dxMul;\n" +
                "  float dist = length(delta);\n" +
                "  if (dist < d.w) { \n" +
                "    float amp = d.z * dist;\n" +
                "    amp /= d.w * d.w;\n" +
                "    amp *= sin(d.w - dist);\n" +
                "    ret = delta * amp;\n" +
                "  }\n" +
                "  return ret;\n" +
                "}\n" +

                "void main() {\n" +
                "  vec2 pos = ATTRIB_position.xy;\n" +
                "  gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);\n" +
                "  float dxMul = 1.0;\n" +

                "  varTex0 = vec2((pos.x + 1.0), (pos.y + 1.6666));\n" +

                "  if (UNI_Rotate < 0.9) {\n" +
                "    varTex0.xy *= vec2(0.25, 0.33);\n" +
                "    varTex0.x += UNI_Offset.x * 0.5;\n" +
                "    pos.x += UNI_Offset.x * 2.0;\n" +
                "  } else {\n" +
                "    varTex0.xy *= vec2(0.5, 0.3125);\n" +
                "    dxMul = 2.5;\n" +
                "  }\n" +

                "  varColor = vec4(1.0, 1.0, 1.0, 1.0);\n" +
                "  pos.xy += vec2(1.0, 1.0);\n" +
                "  pos.xy *= vec2(25.0, 42.0);\n" +

                "  varTex0.xy += addDrop(UNI_Drop01, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop02, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop03, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop04, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop05, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop06, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop07, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop08, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop09, pos, dxMul);\n" +
                "  varTex0.xy += addDrop(UNI_Drop10, pos, dxMul);\n" +
                "}\n";

        sb.setShader(t);
        sb.addConstant(mUniformAlloc.getType());
        sb.addInput(mMesh.getVertexAllocation(0).getType().getElement());
        mPvWater = sb.create();
        mPvWater.bindConstants(mUniformAlloc, 0);

        mScript.set_g_PVWater(mPvWater);

    }

    /**
     * 根据传入的坐标生成水波纹特效
     * <功能详细描述>
     * @param x
     * @param y
     * @see [类、类#方法、类#成员]
     */
    void addDrop(float x, float y) {
        int dropX = (int) ((x / mWidth) * mMeshWidth);
        int dropY = (int) ((y / mHeight) * mMeshHeight);

        mScript.invoke_addDrop(dropX, dropY);
    }
    
    /*******add by harlan************************/
    public static float random(float howsmall, float howbig) {  

         if (howsmall >= howbig) return howsmall;  
         Random sRandom = new Random(); 
         return sRandom.nextFloat() * (howbig - howsmall) + howsmall;  

    } 
    
    public void init(RenderScriptGL rs, Resources res, boolean isPreview) {
        mRS = rs;
        mResources = res;
        mPreview = isPreview;
        mScript = createScript();
    }
    
    public void stop() {
        mRS.bindRootScript(null);
    }

    /****************************************************/

}




好了,至此,RenderScript准备工作完毕,下面就是修改FallView.java文件,以及在activity中加载FallView。

 

 


 

你可能感兴趣的:(android,android,android,三星,水波纹特效)