summaryrefslogtreecommitdiffstats
path: root/src/com/android/wallpaper/holospiral/HoloSpiralRS.java
blob: f2b846caf22cc14e171231c32fc933e8b78c97c4 (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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wallpaper.holospiral;

import com.android.wallpaper.holospiral.ScriptC_holo_spiral;
import com.android.wallpaper.holospiral.ScriptField_VertexColor_s;
import com.android.wallpaper.holospiral.ScriptField_VertexShaderConstants_s;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.Float3;
import android.renderscript.Float4;
import android.renderscript.Mesh;
import android.renderscript.Primitive;
import android.renderscript.ProgramFragment;
import android.renderscript.ProgramStore;
import android.renderscript.ProgramVertex;
import android.renderscript.RenderScriptGL;
import android.renderscript.Sampler;

public class HoloSpiralRS {
    private static final String LOG_TAG = "HoloSpiralRS";
    private static final float MAX_POINT_SIZE = 75.0f;
    private static final float NEAR_PLANE = 1.0f;
    private static final float FAR_PLANE = 55.0f;

    private static final int NUM_INNER_POINTS = 100;
    private static final float INNER_SPIRAL_DEPTH = 50.0f;
    private static final float INNER_RADIUS = 5.0f;
    private static final float INNER_SEPARATION_DEG = 23.0f;

    private static final int NUM_OUTER_POINTS = 50;
    private static final float OUTER_SPIRAL_DEPTH = 30.0f;
    private static final float OUTER_RADIUS = 10.0f;
    private static final float OUTER_SEPARATION_DEG = 23.0f;

    /* Colors */
    private static final int POINTS_COLOR_BLUE = Color.argb(179, 0, 0, 255);
    private static final int POINTS_COLOR_GREEN = Color.argb(179, 0, 255, 255);
    private static final int POINTS_COLOR_AQUA = Color.argb(179, 38, 120, 148);
    private static final int BG_COLOR_BLACK = Color.argb(255, 8, 19, 46);
    private static final int BG_COLOR_BLUE = Color.argb(255, 26, 56, 99);

    private ScriptC_holo_spiral mScript;
    private RenderScriptGL mRS = null;
    private Resources mResources = null;

    public HoloSpiralRS(RenderScriptGL renderer, Resources resources) {
        init(renderer, resources);
    }

    public void init(RenderScriptGL renderer, Resources resources) {
        mRS = renderer;
        mResources = resources;
        createScript();
    }

    public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
        mScript.set_gXOffset(xOffset);
    }

    public Bundle onCommand(String action, int x, int y, int z, Bundle extras,
            boolean resultRequested) {
        return null;
    }

    public void start() {
        mRS.bindRootScript(mScript);
    }

    public void stop() {
        mRS.bindRootScript(null);
    }

    public void resize(int width, int height) {
        mScript.invoke_resize(width, height);
    }

    private void createScript() {
        mScript = new ScriptC_holo_spiral(mRS, mResources, R.raw.holo_spiral);
        mScript.set_gNearPlane(NEAR_PLANE);
        mScript.set_gFarPlane(FAR_PLANE);

        createVertexPrograms();
        createFragmentPrograms();
        createStorePrograms();

        createPointGeometry();
        createBackgroundMesh();
        createTextures();
    }

    private void createVertexPrograms() {
        ScriptField_VertexShaderConstants_s vertexShaderConstants =
                new ScriptField_VertexShaderConstants_s(mRS, 1);
        mScript.bind_gVSConstants(vertexShaderConstants);
        vertexShaderConstants.set_maxPointSize(0, MAX_POINT_SIZE, false);
        vertexShaderConstants.copyAll();

        ProgramVertex.ShaderBuilder backgroundBuilder = new ProgramVertex.ShaderBuilder(mRS);
        backgroundBuilder.setShader(mResources, R.raw.vertex_background);
        backgroundBuilder.addInput(ScriptField_VertexColor_s.createElement(mRS));
        ProgramVertex programVertexBackground = backgroundBuilder.create();
        mScript.set_gPVBackground(programVertexBackground);

        ProgramVertex.ShaderBuilder geometryBuilder = new ProgramVertex.ShaderBuilder(mRS);
        geometryBuilder.setShader(mResources, R.raw.vertex_geometry);
        geometryBuilder.addConstant(vertexShaderConstants.getAllocation().getType());
        geometryBuilder.addInput(ScriptField_VertexColor_s.createElement(mRS));
        ProgramVertex programVertexGeometry = geometryBuilder.create();
        programVertexGeometry.bindConstants(vertexShaderConstants.getAllocation(), 0);
        mScript.set_gPVGeometry(programVertexGeometry);
    }

    private void createFragmentPrograms() {
        ProgramFragment.ShaderBuilder backgroundBuilder = new ProgramFragment.ShaderBuilder(mRS);
        backgroundBuilder.setShader(mResources, R.raw.fragment_background);
        ProgramFragment programFragmentBackground = backgroundBuilder.create();
        mScript.set_gPFBackground(programFragmentBackground);

        ProgramFragment.ShaderBuilder geometryBuilder = new ProgramFragment.ShaderBuilder(mRS);
        geometryBuilder.setShader(mResources, R.raw.fragment_geometry);
        geometryBuilder.setTextureCount(1);
        ProgramFragment programFragmentGeometry = geometryBuilder.create();
        programFragmentGeometry.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
        mScript.set_gPFGeometry(programFragmentGeometry);
    }

    private void createStorePrograms() {
        ProgramStore.Builder builder = new ProgramStore.Builder(mRS);
        builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
                ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
        mScript.set_gPSGeometry(builder.create());
        builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ZERO);
        builder.setDitherEnable(true);
        mScript.set_gPSBackground(builder.create());
    }

    private void createPointGeometry() {
        ScriptField_VertexColor_s innerPoints =
                new ScriptField_VertexColor_s(mRS, NUM_INNER_POINTS);
        generateSpiral(innerPoints, INNER_SPIRAL_DEPTH, INNER_RADIUS, INNER_SEPARATION_DEG,
                POINTS_COLOR_BLUE, POINTS_COLOR_GREEN);

        Mesh.AllocationBuilder innerPointBuilder = new Mesh.AllocationBuilder(mRS);
        innerPointBuilder.addIndexType(Primitive.POINT);
        innerPointBuilder.addVertexAllocation(innerPoints.getAllocation());
        mScript.set_gInnerGeometry(innerPointBuilder.create());

        ScriptField_VertexColor_s outerPoints =
                new ScriptField_VertexColor_s(mRS, NUM_OUTER_POINTS);
        generateSpiral(outerPoints, OUTER_SPIRAL_DEPTH, OUTER_RADIUS, OUTER_SEPARATION_DEG,
                POINTS_COLOR_AQUA, POINTS_COLOR_AQUA);

        Mesh.AllocationBuilder outerPointBuilder = new Mesh.AllocationBuilder(mRS);
        outerPointBuilder.addIndexType(Primitive.POINT);
        outerPointBuilder.addVertexAllocation(outerPoints.getAllocation());
        mScript.set_gOuterGeometry(outerPointBuilder.create());
    }

    private void createTextures() {
        Bitmap bmp = BitmapFactory.decodeResource(
                mResources, R.drawable.points_red_green, null);
        Allocation pointTexture = Allocation.createFromBitmap(
                mRS, bmp, Element.RGB_565(mRS), false);
        pointTexture.uploadToTexture(0);
        mScript.set_gPointTexture(pointTexture);
    }

    private void createBackgroundMesh() {
        ScriptField_VertexColor_s fullQuad = new ScriptField_VertexColor_s(mRS, 4);

        Float3 topLeft = new Float3(-1.0f, 1.0f, 0.0f);
        Float3 bottomLeft = new Float3(-1.0f, -1.0f, 0.0f);
        Float3 topRight = new Float3(1.0f, 1.0f, 0.0f);
        Float3 bottomRight = new Float3(1.0f, -1.0f, 0.0f);

        fullQuad.set_position(0, topLeft, false);
        fullQuad.set_color(0, convertColor(BG_COLOR_BLUE), false);

        fullQuad.set_position(1, bottomLeft, false);
        fullQuad.set_color(1, convertColor(BG_COLOR_BLACK), false);

        fullQuad.set_position(2, topRight, false);
        fullQuad.set_color(2, convertColor(BG_COLOR_BLUE), false);

        fullQuad.set_position(3, bottomRight, false);
        fullQuad.set_color(3, convertColor(BG_COLOR_BLACK), false);

        fullQuad.copyAll();

        Mesh.AllocationBuilder backgroundBuilder = new Mesh.AllocationBuilder(mRS);
        backgroundBuilder.addIndexType(Primitive.TRIANGLE_STRIP);
        backgroundBuilder.addVertexAllocation(fullQuad.getAllocation());
        mScript.set_gBackgroundMesh(backgroundBuilder.create());
    }

    private void generateSpiral(ScriptField_VertexColor_s points, float depth, float radius,
            float separationDegrees, int primaryColor, int secondaryColor) {

        float separationRads = (separationDegrees / 360.0f) * 2 * (float) Math.PI;
        int size = points.getAllocation().getType().getX();

        float halfDepth = depth / 2.0f;
        float radians = 0.0f;

        Float4 primary = convertColor(primaryColor);
        Float4 secondary = convertColor(secondaryColor);

        for (int i = 0; i < size; i++) {
            float percentage = (float) i / (float) size;
            Float3 position = new Float3(radius * (float) Math.cos(radians),
                    radius * (float) Math.sin(radians), (percentage * depth) - halfDepth);

            float r = (float) Math.sin(radians / 2.0f);

            Float4 color = new Float4();
            color.x = primary.x + ((secondary.x - primary.x) * r);
            color.y = primary.y + ((secondary.y - primary.y) * r);
            color.z = primary.z + ((secondary.z - primary.z) * r);
            color.w = primary.w + ((secondary.w - primary.w) * r);

            points.set_position(i, position, false);
            points.set_color(i, color, false);

            radians += separationRads;
            int multiplier = (int) (radians / (2.0f * (float) Math.PI));
            radians -= multiplier * 2.0f * (float) Math.PI;
        }

        points.copyAll();
    }

    private static Float4 convertColor(int color) {
        float red = Color.red(color) / 255.0f;
        float green = Color.green(color) / 255.0f;
        float blue = Color.blue(color) / 255.0f;
        float alpha = Color.alpha(color) / 255.0f;
        return new Float4(red, green, blue, alpha);
    }
}