1/*
2 * Copyright (C) 2009 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.galaxy;
18
19import android.renderscript.*;
20import android.renderscript.Mesh.Primitive;
21import static android.renderscript.ProgramStore.DepthFunc.*;
22import static android.renderscript.ProgramStore.BlendDstFunc;
23import static android.renderscript.ProgramStore.BlendSrcFunc;
24import static android.renderscript.Element.*;
25import android.graphics.Bitmap;
26import android.graphics.BitmapFactory;
27
28import java.util.TimeZone;
29
30import com.android.wallpaper.R;
31import com.android.wallpaper.RenderScriptScene;
32
33class GalaxyRS extends RenderScriptScene {
34    private static final int PARTICLES_COUNT = 12000;
35    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
36    private ProgramVertexFixedFunction.Constants mPvOrthoAlloc;
37    private ProgramVertexFixedFunction.Constants mPvProjectionAlloc;
38    private ScriptField_VpConsts mPvStarAlloc;
39    private Mesh mParticlesMesh;
40    private ScriptC_galaxy mScript;
41
42    GalaxyRS(int width, int height) {
43        super(width, height);
44
45        mOptionsARGB.inScaled = false;
46        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
47    }
48
49    @Override
50    protected ScriptC createScript() {
51        mScript = new ScriptC_galaxy(mRS, mResources, R.raw.galaxy);
52        mScript.set_gIsPreview(isPreview() ? 1 : 0);
53        if (isPreview()) {
54            mScript.set_gXOffset(0.5f);
55        }
56
57
58        createParticlesMesh();
59        createProgramVertex();
60        createProgramRaster();
61        createProgramFragmentStore();
62        createProgramFragment();
63        loadTextures();
64
65        mScript.setTimeZone(TimeZone.getDefault().getID());
66        return mScript;
67    }
68
69    private void createParticlesMesh() {
70        ScriptField_Particle p = new ScriptField_Particle(mRS, PARTICLES_COUNT);
71
72        final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS);
73        meshBuilder.addVertexAllocation(p.getAllocation());
74        final int vertexSlot = meshBuilder.getCurrentVertexTypeIndex();
75        meshBuilder.addIndexSetType(Primitive.POINT);
76        mParticlesMesh = meshBuilder.create();
77
78        mScript.set_gParticlesMesh(mParticlesMesh);
79        mScript.bind_Particles(p);
80    }
81
82    private Matrix4f getProjectionNormalized(int w, int h) {
83        // range -1,1 in the narrow axis at z = 0.
84        Matrix4f m1 = new Matrix4f();
85        Matrix4f m2 = new Matrix4f();
86
87        if(w > h) {
88            float aspect = ((float)w) / h;
89            m1.loadFrustum(-aspect,aspect,  -1,1,  1,100);
90        } else {
91            float aspect = ((float)h) / w;
92            m1.loadFrustum(-1,1, -aspect,aspect, 1,100);
93        }
94
95        m2.loadRotate(180, 0, 1, 0);
96        m1.loadMultiply(m1, m2);
97
98        m2.loadScale(-2, 2, 1);
99        m1.loadMultiply(m1, m2);
100
101        m2.loadTranslate(0, 0, 2);
102        m1.loadMultiply(m1, m2);
103        return m1;
104    }
105
106    private void updateProjectionMatrices() {
107        Matrix4f proj = new Matrix4f();
108        proj.loadOrthoWindow(mWidth, mHeight);
109        mPvOrthoAlloc.setProjection(proj);
110
111        Matrix4f projNorm = getProjectionNormalized(mWidth, mHeight);
112        ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item();
113        i.Proj = projNorm;
114        i.MVP = projNorm;
115        mPvStarAlloc.set(i, 0, true);
116        mPvProjectionAlloc.setProjection(projNorm);
117    }
118
119    @Override
120    public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
121        mScript.set_gXOffset(xOffset);
122    }
123
124    @Override
125    public void resize(int width, int height) {
126        super.resize(width, height);
127
128        updateProjectionMatrices();
129    }
130
131    private void loadTextures() {
132        mScript.set_gTSpace(loadTexture(R.drawable.space));
133        mScript.set_gTLight1(loadTexture(R.drawable.light1));
134        mScript.set_gTFlares(loadTextureARGB(R.drawable.flares));
135    }
136
137    private Allocation loadTexture(int id) {
138        final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources, id);
139        return allocation;
140    }
141
142    // TODO: Fix Allocation.createFromBitmapResource() to do this when RGBA_8888 is specified
143    private Allocation loadTextureARGB(int id) {
144        Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
145        final Allocation allocation = Allocation.createFromBitmap(mRS, b);
146        return allocation;
147    }
148
149    private void createProgramFragment() {
150        ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
151        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
152                           ProgramFragmentFixedFunction.Builder.Format.RGB, 0);
153        ProgramFragment pfb = builder.create();
154        pfb.bindSampler(Sampler.WRAP_NEAREST(mRS), 0);
155        mScript.set_gPFBackground(pfb);
156
157        builder = new ProgramFragmentFixedFunction.Builder(mRS);
158        builder.setPointSpriteTexCoordinateReplacement(true);
159        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE,
160                           ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
161        builder.setVaryingColor(true);
162        ProgramFragment pfs = builder.create();
163        pfs.bindSampler(Sampler.WRAP_LINEAR(mRS), 0);
164        mScript.set_gPFStars(pfs);
165    }
166
167    private void createProgramFragmentStore() {
168        ProgramStore.Builder builder = new ProgramStore.Builder(mRS);
169        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO);
170        mRS.bindProgramStore(builder.create());
171
172        builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE);
173        mScript.set_gPSLights(builder.create());
174    }
175
176    private void createProgramVertex() {
177        mPvOrthoAlloc = new ProgramVertexFixedFunction.Constants(mRS);
178
179        ProgramVertexFixedFunction.Builder builder = new ProgramVertexFixedFunction.Builder(mRS);
180        ProgramVertex pvbo = builder.create();
181        ((ProgramVertexFixedFunction)pvbo).bindConstants(mPvOrthoAlloc);
182        mRS.bindProgramVertex(pvbo);
183
184        mPvStarAlloc = new ScriptField_VpConsts(mRS, 1);
185        mScript.bind_vpConstants(mPvStarAlloc);
186        mPvProjectionAlloc = new ProgramVertexFixedFunction.Constants(mRS);
187        updateProjectionMatrices();
188
189        builder = new ProgramVertexFixedFunction.Builder(mRS);
190        ProgramVertex pvbp = builder.create();
191        ((ProgramVertexFixedFunction)pvbp).bindConstants(mPvProjectionAlloc);
192        mScript.set_gPVBkProj(pvbp);
193
194        ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS);
195        String t =  "varying vec4 varColor;\n" +
196                    "varying vec2 varTex0;\n" +
197                    "void main() {\n" +
198                    "  float dist = ATTRIB_position.y;\n" +
199                    "  float angle = ATTRIB_position.x;\n" +
200                    "  float x = dist * sin(angle);\n" +
201                    "  float y = dist * cos(angle) * 0.892;\n" +
202                    "  float p = dist * 5.5;\n" +
203                    "  float s = cos(p);\n" +
204                    "  float t = sin(p);\n" +
205                    "  vec4 pos;\n" +
206                    "  pos.x = t * x + s * y;\n" +
207                    "  pos.y = s * x - t * y;\n" +
208                    "  pos.z = ATTRIB_position.z;\n" +
209                    "  pos.w = 1.0;\n" +
210                    "  gl_Position = UNI_MVP * pos;\n" +
211                    "  gl_PointSize = ATTRIB_color.a * 10.0;\n" +
212                    "  varColor.rgb = ATTRIB_color.rgb;\n" +
213                    "  varColor.a = 1.0;\n" +
214                    "}\n";
215        sb.setShader(t);
216        sb.addInput(mParticlesMesh.getVertexAllocation(0).getType().getElement());
217        sb.addConstant(mPvStarAlloc.getType());
218        ProgramVertex pvs = sb.create();
219        pvs.bindConstants(mPvStarAlloc.getAllocation(), 0);
220        mScript.set_gPVStars(pvs);
221    }
222
223    private void createProgramRaster() {
224        ProgramRaster.Builder b = new ProgramRaster.Builder(mRS);
225        b.setPointSpriteEnabled(true);
226        ProgramRaster pr = b.create();
227        mRS.bindProgramRaster(pr);
228    }
229
230}
231