/************************************************************************* * Copyright (C) 2010-2011 Tavian Barnes * * * * This file is part of The Dimension Android Binding. * * * * The Dimension Android Binding is free software; you can redistribute * * it and/or modify it under the terms of the GNU General Public License * * as published by the Free Software Foundation; either version 3 of the * * License, or (at your option) any later version. * * * * The Dimension Android Binding is distributed in the hope that it will * * be useful, but WITHOUT ANY WARRANTY; without even the implied * * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * * the GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *************************************************************************/ package com.tavianator.dimension.android; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Canvas; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.util.AttributeSet; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * @author Tavian Barnes * @version 1.0 * @since 1.0 */ @SuppressLint("HandlerLeak") public class RaytracedView extends SurfaceView implements SurfaceHolder.Callback { private static final String TAG = RaytracedView.class.getSimpleName(); private static final int NFRAMES = 64; static { System.loadLibrary("dimension"); Log.d(TAG, "libdimension loaded sucessfully!"); } private static final int MSG_RENDER = 0; private static final int MSG_QUIT = 1; private static class RenderPayload { public int width; public int height; public RenderPayload(int width, int height) { this.width = width; this.height = height; } } private class RenderHandler extends Handler { public RenderHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_RENDER: handleRender((RenderPayload) msg.obj); break; case MSG_QUIT: handleQuit(); break; } } private void handleRender(RenderPayload payload) { render(payload.width, payload.height); } private void handleQuit() { getLooper().quit(); } } private RenderHandler m_Handler; private int mWidth, mHeight; private int[] mBitmap; public RaytracedView(Context context) { super(context); init(); } public RaytracedView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public RaytracedView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { SurfaceHolder holder = getHolder(); holder.addCallback(this); holder.setFormat(PixelFormat.TRANSLUCENT); } public void surfaceCreated(SurfaceHolder holder) { HandlerThread thread = new HandlerThread("RenderThread"); thread.start(); m_Handler = new RenderHandler(thread.getLooper()); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { m_Handler.obtainMessage(MSG_RENDER, new RenderPayload(width, height)) .sendToTarget(); } public void surfaceDestroyed(SurfaceHolder holder) { m_Handler.sendEmptyMessage(MSG_QUIT); } private void render(int width, int height) { mBitmap = new int[width * height]; mWidth = width; mHeight = height; renderNative(width, height); for (int i = 0; i < NFRAMES; ++i) { waitNative(((double) i) / NFRAMES); draw(); } joinNative(); draw(); } private void draw() { SurfaceHolder holder = getHolder(); Canvas canvas = holder.lockCanvas(); if (canvas == null) { return; } canvas.drawColor(0, PorterDuff.Mode.CLEAR); canvas.drawBitmap(mBitmap, 0, mWidth, 0.0F, 0.0F, mWidth, mHeight, true, null); holder.unlockCanvasAndPost(canvas); } /** Start the render. */ private native void renderNative(int width, int height); /** Wait for the render to reach a certain amount of progress. */ private native void waitNative(double progress); /** Wait for the render to complete. */ private native void joinNative(); /** Called by JNI code to set the pixel colors. */ private void setPixel(int x, int y, int color) { y = mHeight - y - 1; mBitmap[y * mWidth + x] = color; } }