Hello Rendering

Rendering with RenderScript is a little bit more complicated than simply invoking a script function, and requires a little more work before you can see anything on the screen. You will need to:

  • Create a script that does the rendering.
  • Create a RenderScriptGL context object.
  • Create a class that extends RSSurfaceView.
  • Set your RSSurfaceView as the content view for your activity.

Creating a Rendering Script

Our first rendering script will be extremely simple as it will only change the background color to some random color. The script is shown in Listing 9–5 and is in a file called hellorendering.rs. The names of the RenderScript files are important as they define the resource name (in that case R.raw.hellorendering, which is simply defined as an integer in R.java).

Listing 9–5. Changing Background Color

#pragma version(1)
#pragma rs java_package_name(com.apress.proandroid.ch9)

#include "rs_graphics.rsh"

// invoked automatically when the script is created
void init() {
    // do whatever you need to do here...
}

int root() {
    float red = rsRand(1.0f);
    float green = rsRand(1.0f);
    float blue = rsRand(1.0f);

    // clear the background color with random color
    rsgClearColor(red, green, blue, 1.0f); // alpha is 1.0f, i.e. opaque

    // 50 frames per second = 20 milliseconds per frame
    return 20;
}

The first two lines of the files are the same as in Listing 9–1. The following line is to include the rs_graphics.rsh header file, where rsgClearColor() is defined. Header files are automatically included except for rs_graphics.rsh, so you will have to explicitly include that file when you use graphics RenderScript functions such as rsgClearColor() or rsgBindFont().

The init() function here is for informational purpose only as its implementation is empty. The init() function is optional and, if present, will be called automatically when the script is created. This allows you to perform any initialization before other routines are executed. A script that does no rendering, like the one shown in Listing 9–1, could also have an init() function.

The root() function is where the rendering actually happens. The implementation here is trivial as all it does is clear the background with a random color. What is interesting though is the return value of the function as it specifies how often rendering will occur. In this particular case we return 20, which means the frame should be updated every 20 milliseconds (that is, frame rate of 50 frames per second).

NOTE: init() and root() are reserved functions and do not result in invoke_init() and invoke_root() methods being created in the reflected layer (ScriptC_hellorendering.java in this case).

Creating a RenderScriptGL Context

Now that the rendering script is complete, you will need a RenderScriptGL context object. Here the RenderScriptGL context object is created when the RSSurfaceView's surfaceChanged() method is called. The HelloRenderingView implementation is shown in Listing 9–6.

Listing 9–6. HelloRenderingView.java

public class HelloRenderingView extends RSSurfaceView {

    public HelloRenderingView(Context context) {
        super(context);
    }

    private RenderScriptGL mRS;
    private HelloRenderingRS mRender; // helper class

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        super.surfaceChanged(holder, format, w, h);
        if (mRS == null) {
            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
            mRS = createRenderScriptGL(sc);
            mRender = new HelloRenderingRS();
            mRender.init(mRS, getResources());
        }
        mRS.setSurface(holder, w, h);
    }

    @Override
    protected void onDetachedFromWindow() {
        if(mRS != null) {
            mRS = null;
            destroyRenderScriptGL();
        }
    }
}

As you can see in Listing 9–6, a HelloRenderingRS helper class is used as well.

Extending RSSurfaceView

The implementation of this class is shown in Listing 9–7.

Listing 9–7. HelloRenderingRS.java

public class HelloRenderingRS {

    public HelloRenderingRS() {
    }

    private Resources mRes;
    private RenderScriptGL mRS;
    private ScriptC_hellorendering mScript;

    public void init(RenderScriptGL rs, Resources res) {
        mRS = rs;
        mRes = res;

        mScript = new ScriptC_hellorendering(mRS, mRes, R.raw.hellorendering);

        mRS.bindRootScript(mScript);
    }
}

In this class, we create the actual ScriptC_hellorendering script and bind it to the RenderScriptGL object. Without the call to bindRootScript(), nothing would actually get rendered as the script's root() function would not be called. If you find yourself staring at a black screen when you were expecting some rendering to happen, first check you did not forget to call bindRootScript().

Setting the Content View

Now that all these files exist, you can create an instance of HelloRenderingView and set the activity's content to this instance, as shown in Listing 9–8.

Listing 9–8. Activity

public class Chapter9Activity extends Activity {
    static final String TAG = "Chapter9Activity";

    private HelloRenderingView mHelloRenderingView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.main); // we don't use the XML layout anymore here so we comment it out

        HelloWorldRenderScript();

        mHelloRenderingView = new HelloRenderingView(this);
        setContentView(mHelloRenderingView);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mHelloRenderingView.pause(); // to pause the rendering thread
    }

    @Override
    protected void onResume() {
        super.onResume();
        mHelloRenderingView.resume(); // to resume the rendering thread
    }

    private void HelloWorldRenderScript() {
        // see Listing 9–3 for implementation
    }
}

While most of this file should be trivial to you now, there is one thing in this file worth noting: the RSSurfaceView must be told when the activity is paused and resumed. Without the calls to RSSurfaceView.pause() and RSSurfaceView.resume(), the rendering thread would not be aware of the activity's state and would carry on rendering things even when the activity is not necessarily visible.

In Android 4.0 two new important features are added:

  • Your application can use an allocation as an off-screen buffer by setting the Allocation.USAGE_GRAPHICS_RENDER_TARGET flag when creating the allocation object.
  • You can use an RSTextureView in your layout (together with other views). While an RSSurfaceView creates a separate window, an RSTextureView does not.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.103.206