1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.wallpaper.holospiral;
18
19import com.android.wallpaper.holospiral.ScriptC_holo_spiral;
20import com.android.wallpaper.holospiral.ScriptField_VertexColor_s;
21import com.android.wallpaper.holospiral.ScriptField_VertexShaderConstants_s;
22
23import android.content.res.Resources;
24import android.graphics.Bitmap;
25import android.graphics.BitmapFactory;
26import android.graphics.Color;
27import android.os.Bundle;
28import android.renderscript.Allocation;
29import android.renderscript.Element;
30import android.renderscript.Float3;
31import android.renderscript.Float4;
32import android.renderscript.Mesh;
33import android.renderscript.Mesh.Primitive;
34import android.renderscript.Program;
35import android.renderscript.ProgramFragment;
36import android.renderscript.ProgramStore;
37import android.renderscript.ProgramVertex;
38import android.renderscript.RenderScriptGL;
39import android.renderscript.Sampler;
40
41public class HoloSpiralRS {
42    private static final String LOG_TAG = "HoloSpiralRS";
43    private static final float MAX_POINT_SIZE = 75.0f;
44    private static final float NEAR_PLANE = 1.0f;
45    private static final float FAR_PLANE = 55.0f;
46
47    private static final int NUM_INNER_POINTS = 100;
48    private static final float INNER_SPIRAL_DEPTH = 50.0f;
49    private static final float INNER_RADIUS = 5.0f;
50    private static final float INNER_SEPARATION_DEG = 23.0f;
51
52    private static final int NUM_OUTER_POINTS = 50;
53    private static final float OUTER_SPIRAL_DEPTH = 30.0f;
54    private static final float OUTER_RADIUS = 10.0f;
55    private static final float OUTER_SEPARATION_DEG = 23.0f;
56
57    /* Colors */
58    private static final int POINTS_COLOR_BLUE = Color.argb(179, 0, 0, 255);
59    private static final int POINTS_COLOR_GREEN = Color.argb(210, 166, 51, 255);
60    private static final int POINTS_COLOR_AQUA = Color.argb(220, 38, 120, 148);
61    private static final int BG_COLOR_BLACK = Color.argb(255, 26, 26, 83);
62    private static final int BG_COLOR_BLUE = Color.argb(255, 8, 0, 26);
63
64    private ScriptC_holo_spiral mScript;
65    private RenderScriptGL mRS = null;
66    private Resources mResources = null;
67
68    public HoloSpiralRS(RenderScriptGL renderer, Resources resources) {
69        init(renderer, resources);
70    }
71
72    public void init(RenderScriptGL renderer, Resources resources) {
73        mRS = renderer;
74        mResources = resources;
75        createScript();
76    }
77
78    public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
79        mScript.set_gXOffset(xOffset);
80    }
81
82    public Bundle onCommand(String action, int x, int y, int z, Bundle extras,
83            boolean resultRequested) {
84        return null;
85    }
86
87    public void start() {
88        mRS.bindRootScript(mScript);
89    }
90
91    public void stop() {
92        mRS.bindRootScript(null);
93    }
94
95    public void resize(int width, int height) {
96        mScript.invoke_resize(width, height);
97    }
98
99    private void createScript() {
100        mScript = new ScriptC_holo_spiral(mRS, mResources, R.raw.holo_spiral);
101        mScript.set_gNearPlane(NEAR_PLANE);
102        mScript.set_gFarPlane(FAR_PLANE);
103
104        createVertexPrograms();
105        createFragmentPrograms();
106        createStorePrograms();
107
108        createPointGeometry();
109        createBackgroundMesh();
110        createTextures();
111    }
112
113    private void createVertexPrograms() {
114        ScriptField_VertexShaderConstants_s vertexShaderConstants =
115                new ScriptField_VertexShaderConstants_s(mRS, 1);
116        mScript.bind_gVSConstants(vertexShaderConstants);
117        vertexShaderConstants.set_maxPointSize(0, MAX_POINT_SIZE, false);
118        vertexShaderConstants.copyAll();
119
120        ProgramVertex.Builder backgroundBuilder = new ProgramVertex.Builder(mRS);
121        backgroundBuilder.setShader(mResources, R.raw.vertex_background);
122        backgroundBuilder.addInput(ScriptField_VertexColor_s.createElement(mRS));
123        ProgramVertex programVertexBackground = backgroundBuilder.create();
124        mScript.set_gPVBackground(programVertexBackground);
125
126        ProgramVertex.Builder geometryBuilder = new ProgramVertex.Builder(mRS);
127        geometryBuilder.setShader(mResources, R.raw.vertex_geometry);
128        geometryBuilder.addConstant(vertexShaderConstants.getAllocation().getType());
129        geometryBuilder.addInput(ScriptField_VertexColor_s.createElement(mRS));
130        ProgramVertex programVertexGeometry = geometryBuilder.create();
131        programVertexGeometry.bindConstants(vertexShaderConstants.getAllocation(), 0);
132        mScript.set_gPVGeometry(programVertexGeometry);
133    }
134
135    private void createFragmentPrograms() {
136        ProgramFragment.Builder backgroundBuilder = new ProgramFragment.Builder(mRS);
137        backgroundBuilder.setShader(mResources, R.raw.fragment_background);
138        ProgramFragment programFragmentBackground = backgroundBuilder.create();
139        mScript.set_gPFBackground(programFragmentBackground);
140
141        ProgramFragment.Builder geometryBuilder = new ProgramFragment.Builder(mRS);
142        geometryBuilder.setShader(mResources, R.raw.fragment_geometry);
143        geometryBuilder.addTexture(Program.TextureType.TEXTURE_2D);
144        ProgramFragment programFragmentGeometry = geometryBuilder.create();
145        programFragmentGeometry.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
146        mScript.set_gPFGeometry(programFragmentGeometry);
147    }
148
149    private void createStorePrograms() {
150        ProgramStore.Builder builder = new ProgramStore.Builder(mRS);
151        builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
152                ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
153        mScript.set_gPSGeometry(builder.create());
154        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ZERO);
155        builder.setDitherEnabled(true);
156        mScript.set_gPSBackground(builder.create());
157    }
158
159    private void createPointGeometry() {
160        ScriptField_VertexColor_s innerPoints =
161                new ScriptField_VertexColor_s(mRS, NUM_INNER_POINTS);
162        generateSpiral(innerPoints, INNER_SPIRAL_DEPTH, INNER_RADIUS, INNER_SEPARATION_DEG,
163                POINTS_COLOR_BLUE, POINTS_COLOR_GREEN);
164
165        Mesh.AllocationBuilder innerPointBuilder = new Mesh.AllocationBuilder(mRS);
166        innerPointBuilder.addIndexSetType(Primitive.POINT);
167        innerPointBuilder.addVertexAllocation(innerPoints.getAllocation());
168        mScript.set_gInnerGeometry(innerPointBuilder.create());
169
170        ScriptField_VertexColor_s outerPoints =
171                new ScriptField_VertexColor_s(mRS, NUM_OUTER_POINTS);
172        generateSpiral(outerPoints, OUTER_SPIRAL_DEPTH, OUTER_RADIUS, OUTER_SEPARATION_DEG,
173                POINTS_COLOR_AQUA, POINTS_COLOR_AQUA);
174
175        Mesh.AllocationBuilder outerPointBuilder = new Mesh.AllocationBuilder(mRS);
176        outerPointBuilder.addIndexSetType(Primitive.POINT);
177        outerPointBuilder.addVertexAllocation(outerPoints.getAllocation());
178        mScript.set_gOuterGeometry(outerPointBuilder.create());
179    }
180
181    private void createTextures() {
182        Bitmap bmp = BitmapFactory.decodeResource(
183                mResources, R.drawable.points_red_green, null);
184        Allocation pointTexture = Allocation.createFromBitmap(mRS, bmp);
185        mScript.set_gPointTexture(pointTexture);
186    }
187
188    private void createBackgroundMesh() {
189        ScriptField_VertexColor_s fullQuad = new ScriptField_VertexColor_s(mRS, 4);
190
191        Float3 topLeft = new Float3(-1.0f, 1.0f, 0.0f);
192        Float3 bottomLeft = new Float3(-1.0f, -1.0f, 0.0f);
193        Float3 topRight = new Float3(1.0f, 1.0f, 0.0f);
194        Float3 bottomRight = new Float3(1.0f, -1.0f, 0.0f);
195
196        fullQuad.set_position(0, topLeft, false);
197        fullQuad.set_color(0, convertColor(BG_COLOR_BLUE), false);
198
199        fullQuad.set_position(1, bottomLeft, false);
200        fullQuad.set_color(1, convertColor(BG_COLOR_BLACK), false);
201
202        fullQuad.set_position(2, topRight, false);
203        fullQuad.set_color(2, convertColor(BG_COLOR_BLUE), false);
204
205        fullQuad.set_position(3, bottomRight, false);
206        fullQuad.set_color(3, convertColor(BG_COLOR_BLACK), false);
207
208        fullQuad.copyAll();
209
210        Mesh.AllocationBuilder backgroundBuilder = new Mesh.AllocationBuilder(mRS);
211        backgroundBuilder.addIndexSetType(Primitive.TRIANGLE_STRIP);
212        backgroundBuilder.addVertexAllocation(fullQuad.getAllocation());
213        mScript.set_gBackgroundMesh(backgroundBuilder.create());
214    }
215
216    private void generateSpiral(ScriptField_VertexColor_s points, float depth, float radius,
217            float separationDegrees, int primaryColor, int secondaryColor) {
218
219        float separationRads = (separationDegrees / 360.0f) * 2 * (float) Math.PI;
220        int size = points.getAllocation().getType().getX();
221
222        float halfDepth = depth / 2.0f;
223        float radians = 0.0f;
224
225        Float4 primary = convertColor(primaryColor);
226        Float4 secondary = convertColor(secondaryColor);
227
228        for (int i = 0; i < size; i++) {
229            float percentage = (float) i / (float) size;
230            Float3 position = new Float3(radius * (float) Math.cos(radians),
231                    radius * (float) Math.sin(radians), (percentage * depth) - halfDepth);
232
233            float r = (float) Math.sin(radians / 2.0f);
234
235            Float4 color = new Float4();
236            color.x = primary.x + ((secondary.x - primary.x) * r);
237            color.y = primary.y + ((secondary.y - primary.y) * r);
238            color.z = primary.z + ((secondary.z - primary.z) * r);
239            color.w = primary.w + ((secondary.w - primary.w) * r);
240
241            points.set_position(i, position, false);
242            points.set_color(i, color, false);
243
244            radians += separationRads;
245            int multiplier = (int) (radians / (2.0f * (float) Math.PI));
246            radians -= multiplier * 2.0f * (float) Math.PI;
247        }
248
249        points.copyAll();
250    }
251
252    private static Float4 convertColor(int color) {
253        float red = Color.red(color) / 255.0f;
254        float green = Color.green(color) / 255.0f;
255        float blue = Color.blue(color) / 255.0f;
256        float alpha = Color.alpha(color) / 255.0f;
257        return new Float4(red, green, blue, alpha);
258    }
259}
260