summaryrefslogtreecommitdiffstats
path: root/src/com/tavianator/dimension/android/RaytracedView.java
blob: 4a8879369f86416b8fa4ed013b3a87bc34aed4ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*************************************************************************
 * Copyright (C) 2010-2011 Tavian Barnes <tavianator@tavianator.com>	 *
 *									 *
 * 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 <http://www.gnu.org/licenses/>. *
 *************************************************************************/

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 <tavianator@tavianator.com>
 * @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;
	}
}