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 
17 package com.android.wallpaper.holospiral;
18 
19 import com.android.wallpaper.holospiral.ScriptC_holo_spiral;
20 import com.android.wallpaper.holospiral.ScriptField_VertexColor_s;
21 import com.android.wallpaper.holospiral.ScriptField_VertexShaderConstants_s;
22 
23 import android.content.res.Resources;
24 import android.graphics.Bitmap;
25 import android.graphics.BitmapFactory;
26 import android.graphics.Color;
27 import android.os.Bundle;
28 import android.renderscript.Allocation;
29 import android.renderscript.Element;
30 import android.renderscript.Float3;
31 import android.renderscript.Float4;
32 import android.renderscript.Mesh;
33 import android.renderscript.Mesh.Primitive;
34 import android.renderscript.Program;
35 import android.renderscript.ProgramFragment;
36 import android.renderscript.ProgramStore;
37 import android.renderscript.ProgramVertex;
38 import android.renderscript.RenderScriptGL;
39 import android.renderscript.Sampler;
40 
41 public 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 
HoloSpiralRS(RenderScriptGL renderer, Resources resources)68     public HoloSpiralRS(RenderScriptGL renderer, Resources resources) {
69         init(renderer, resources);
70     }
71 
init(RenderScriptGL renderer, Resources resources)72     public void init(RenderScriptGL renderer, Resources resources) {
73         mRS = renderer;
74         mResources = resources;
75         createScript();
76     }
77 
setOffset(float xOffset, float yOffset, int xPixels, int yPixels)78     public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
79         mScript.set_gXOffset(xOffset);
80     }
81 
onCommand(String action, int x, int y, int z, Bundle extras, boolean resultRequested)82     public Bundle onCommand(String action, int x, int y, int z, Bundle extras,
83             boolean resultRequested) {
84         return null;
85     }
86 
start()87     public void start() {
88         mRS.bindRootScript(mScript);
89     }
90 
stop()91     public void stop() {
92         mRS.bindRootScript(null);
93     }
94 
resize(int width, int height)95     public void resize(int width, int height) {
96         mScript.invoke_resize(width, height);
97     }
98 
createScript()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 
createVertexPrograms()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 
createFragmentPrograms()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 
createStorePrograms()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 
createPointGeometry()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 
createTextures()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                                            Allocation.MipmapControl.MIPMAP_NONE,
186                                            Allocation.USAGE_GRAPHICS_TEXTURE);
187         mScript.set_gPointTexture(pointTexture);
188     }
189 
createBackgroundMesh()190     private void createBackgroundMesh() {
191         ScriptField_VertexColor_s fullQuad = new ScriptField_VertexColor_s(mRS, 4);
192 
193         Float3 topLeft = new Float3(-1.0f, 1.0f, 0.0f);
194         Float3 bottomLeft = new Float3(-1.0f, -1.0f, 0.0f);
195         Float3 topRight = new Float3(1.0f, 1.0f, 0.0f);
196         Float3 bottomRight = new Float3(1.0f, -1.0f, 0.0f);
197 
198         fullQuad.set_position(0, topLeft, false);
199         fullQuad.set_color(0, convertColor(BG_COLOR_BLUE), false);
200 
201         fullQuad.set_position(1, bottomLeft, false);
202         fullQuad.set_color(1, convertColor(BG_COLOR_BLACK), false);
203 
204         fullQuad.set_position(2, topRight, false);
205         fullQuad.set_color(2, convertColor(BG_COLOR_BLUE), false);
206 
207         fullQuad.set_position(3, bottomRight, false);
208         fullQuad.set_color(3, convertColor(BG_COLOR_BLACK), false);
209 
210         fullQuad.copyAll();
211 
212         Mesh.AllocationBuilder backgroundBuilder = new Mesh.AllocationBuilder(mRS);
213         backgroundBuilder.addIndexSetType(Primitive.TRIANGLE_STRIP);
214         backgroundBuilder.addVertexAllocation(fullQuad.getAllocation());
215         mScript.set_gBackgroundMesh(backgroundBuilder.create());
216     }
217 
generateSpiral(ScriptField_VertexColor_s points, float depth, float radius, float separationDegrees, int primaryColor, int secondaryColor)218     private void generateSpiral(ScriptField_VertexColor_s points, float depth, float radius,
219             float separationDegrees, int primaryColor, int secondaryColor) {
220 
221         float separationRads = (separationDegrees / 360.0f) * 2 * (float) Math.PI;
222         int size = points.getAllocation().getType().getX();
223 
224         float halfDepth = depth / 2.0f;
225         float radians = 0.0f;
226 
227         Float4 primary = convertColor(primaryColor);
228         Float4 secondary = convertColor(secondaryColor);
229 
230         for (int i = 0; i < size; i++) {
231             float percentage = (float) i / (float) size;
232             Float3 position = new Float3(radius * (float) Math.cos(radians),
233                     radius * (float) Math.sin(radians), (percentage * depth) - halfDepth);
234 
235             float r = (float) Math.sin(radians / 2.0f);
236 
237             Float4 color = new Float4();
238             color.x = primary.x + ((secondary.x - primary.x) * r);
239             color.y = primary.y + ((secondary.y - primary.y) * r);
240             color.z = primary.z + ((secondary.z - primary.z) * r);
241             color.w = primary.w + ((secondary.w - primary.w) * r);
242 
243             points.set_position(i, position, false);
244             points.set_color(i, color, false);
245 
246             radians += separationRads;
247             int multiplier = (int) (radians / (2.0f * (float) Math.PI));
248             radians -= multiplier * 2.0f * (float) Math.PI;
249         }
250 
251         points.copyAll();
252     }
253 
convertColor(int color)254     private static Float4 convertColor(int color) {
255         float red = Color.red(color) / 255.0f;
256         float green = Color.green(color) / 255.0f;
257         float blue = Color.blue(color) / 255.0f;
258         float alpha = Color.alpha(color) / 255.0f;
259         return new Float4(red, green, blue, alpha);
260     }
261 }
262