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 17 package com.android.wallpaper.galaxy; 18 19 import android.renderscript.ScriptC; 20 import android.renderscript.ProgramFragment; 21 import android.renderscript.ProgramStore; 22 import android.renderscript.ProgramVertex; 23 import android.renderscript.ProgramRaster; 24 import android.renderscript.Allocation; 25 import android.renderscript.Sampler; 26 import android.renderscript.Element; 27 import android.renderscript.SimpleMesh; 28 import android.renderscript.Primitive; 29 import android.renderscript.Type; 30 import static android.renderscript.Sampler.Value.LINEAR; 31 import static android.renderscript.Sampler.Value.NEAREST; 32 import static android.renderscript.Sampler.Value.WRAP; 33 import static android.renderscript.ProgramStore.DepthFunc.*; 34 import static android.renderscript.ProgramStore.BlendDstFunc; 35 import static android.renderscript.ProgramStore.BlendSrcFunc; 36 import static android.renderscript.Element.*; 37 import android.graphics.Bitmap; 38 import android.graphics.BitmapFactory; 39 40 import java.util.TimeZone; 41 42 import com.android.wallpaper.R; 43 import com.android.wallpaper.RenderScriptScene; 44 45 class GalaxyRS extends RenderScriptScene { 46 private static final int GALAXY_RADIUS = 300; 47 private static final int PARTICLES_COUNT = 12000; 48 49 private static final int RSID_STATE = 0; 50 private static final int RSID_PARTICLES_BUFFER = 1; 51 52 private static final int TEXTURES_COUNT = 3; 53 private static final int RSID_TEXTURE_SPACE = 0; 54 private static final int RSID_TEXTURE_LIGHT1 = 1; 55 private static final int RSID_TEXTURE_FLARES = 2; 56 57 private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); 58 59 @SuppressWarnings({"FieldCanBeLocal"}) 60 private ProgramFragment mPfBackground; 61 @SuppressWarnings({"FieldCanBeLocal"}) 62 private ProgramFragment mPfStars; 63 @SuppressWarnings({"FieldCanBeLocal"}) 64 private ProgramStore mPfsBackground; 65 @SuppressWarnings({"FieldCanBeLocal"}) 66 private ProgramStore mPfsLights; 67 @SuppressWarnings({"FieldCanBeLocal"}) 68 private ProgramVertex mPvBkOrtho; 69 @SuppressWarnings({"FieldCanBeLocal"}) 70 private ProgramVertex mPvBkProj; 71 @SuppressWarnings({"FieldCanBeLocal"}) 72 private ProgramVertex mPvStars; 73 @SuppressWarnings({"FieldCanBeLocal"}) 74 private Sampler mSampler; 75 @SuppressWarnings({"FieldCanBeLocal"}) 76 private Sampler mStarSampler; 77 @SuppressWarnings({"FieldCanBeLocal"}) 78 private ProgramVertex.MatrixAllocation mPvOrthoAlloc; 79 @SuppressWarnings({"FieldCanBeLocal"}) 80 private ProgramVertex.MatrixAllocation mPvProjectionAlloc; 81 @SuppressWarnings({"FieldCanBeLocal"}) 82 private Allocation[] mTextures; 83 84 private GalaxyState mGalaxyState; 85 private Type mStateType; 86 private Allocation mState; 87 private Allocation mParticlesBuffer; 88 @SuppressWarnings({"FieldCanBeLocal"}) 89 private SimpleMesh mParticlesMesh; 90 private ScriptC.Invokable mInitParticles; 91 92 GalaxyRS(int width, int height) { 93 super(width, height); 94 95 mOptionsARGB.inScaled = false; 96 mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; 97 } 98 99 @Override 100 protected ScriptC createScript() { 101 createScriptStructures(); 102 createProgramVertex(); 103 createProgramRaster(); 104 createProgramFragmentStore(); 105 createProgramFragment(); 106 loadTextures(); 107 108 ScriptC.Builder sb = new ScriptC.Builder(mRS); 109 sb.setType(mStateType, "State", RSID_STATE); 110 sb.setType(mParticlesMesh.getVertexType(0), "Particles", RSID_PARTICLES_BUFFER); 111 mInitParticles = sb.addInvokable("initParticles"); 112 sb.setScript(mResources, R.raw.galaxy); 113 sb.setRoot(true); 114 115 ScriptC script = sb.create(); 116 script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); 117 script.setTimeZone(TimeZone.getDefault().getID()); 118 119 script.bindAllocation(mState, RSID_STATE); 120 script.bindAllocation(mParticlesBuffer, RSID_PARTICLES_BUFFER); 121 mInitParticles.execute(); 122 123 return script; 124 } 125 126 private void createScriptStructures() { 127 createState(); 128 createParticlesMesh(); 129 } 130 131 private void createParticlesMesh() { 132 final Builder elementBuilder = new Builder(mRS); 133 elementBuilder.add(Element.createAttrib(mRS, Element.DataType.UNSIGNED_8, 134 Element.DataKind.USER, 4), "color"); 135 elementBuilder.add(Element.createAttrib(mRS, Element.DataType.FLOAT_32, 136 Element.DataKind.USER, 3), "position"); 137 final Element vertexElement = elementBuilder.create(); 138 139 final SimpleMesh.Builder meshBuilder = new SimpleMesh.Builder(mRS); 140 final int vertexSlot = meshBuilder.addVertexType(vertexElement, PARTICLES_COUNT); 141 meshBuilder.setPrimitive(Primitive.POINT); 142 mParticlesMesh = meshBuilder.create(); 143 mParticlesMesh.setName("ParticlesMesh"); 144 145 mParticlesBuffer = mParticlesMesh.createVertexAllocation(vertexSlot); 146 mParticlesBuffer.setName("ParticlesBuffer"); 147 mParticlesMesh.bindVertexAllocation(mParticlesBuffer, 0); 148 } 149 150 @Override 151 public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) { 152 mGalaxyState.xOffset = xOffset; 153 mState.data(mGalaxyState); 154 } 155 156 @Override 157 public void resize(int width, int height) { 158 super.resize(width, height); 159 160 mGalaxyState.width = width; 161 mGalaxyState.height = height; 162 mGalaxyState.scale = width > height ? 1 : 0; 163 mState.data(mGalaxyState); 164 165 mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight); 166 mPvProjectionAlloc.setupProjectionNormalized(mWidth, mHeight); 167 168 mInitParticles.execute(); 169 } 170 171 static class GalaxyState { 172 public int width; 173 public int height; 174 public int particlesCount; 175 public int galaxyRadius; 176 public float xOffset; 177 public int isPreview; 178 public int scale; 179 } 180 181 private void createState() { 182 boolean isPreview = isPreview(); 183 184 mGalaxyState = new GalaxyState(); 185 mGalaxyState.width = mWidth; 186 mGalaxyState.height = mHeight; 187 mGalaxyState.scale = mWidth > mHeight ? 1 : 0; 188 mGalaxyState.particlesCount = PARTICLES_COUNT; 189 mGalaxyState.galaxyRadius = GALAXY_RADIUS; 190 mGalaxyState.isPreview = isPreview ? 1 : 0; 191 if (isPreview) { 192 mGalaxyState.xOffset = 0.5f; 193 } 194 195 mStateType = Type.createFromClass(mRS, GalaxyState.class, 1, "GalaxyState"); 196 mState = Allocation.createTyped(mRS, mStateType); 197 mState.data(mGalaxyState); 198 } 199 200 private void loadTextures() { 201 mTextures = new Allocation[TEXTURES_COUNT]; 202 203 final Allocation[] textures = mTextures; 204 textures[RSID_TEXTURE_SPACE] = loadTexture(R.drawable.space, "TSpace"); 205 textures[RSID_TEXTURE_LIGHT1] = loadTexture(R.drawable.light1, "TLight1"); 206 textures[RSID_TEXTURE_FLARES] = loadTextureARGB(R.drawable.flares, "TFlares"); 207 208 final int count = textures.length; 209 for (int i = 0; i < count; i++) { 210 textures[i].uploadToTexture(0); 211 } 212 } 213 214 private Allocation loadTexture(int id, String name) { 215 final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources, 216 id, RGB_565(mRS), false); 217 allocation.setName(name); 218 return allocation; 219 } 220 221 // TODO: Fix Allocation.createFromBitmapResource() to do this when RGBA_8888 is specified 222 private Allocation loadTextureARGB(int id, String name) { 223 Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB); 224 final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888(mRS), false); 225 allocation.setName(name); 226 return allocation; 227 } 228 229 private void createProgramFragment() { 230 Sampler.Builder samplerBuilder = new Sampler.Builder(mRS); 231 samplerBuilder.setMin(NEAREST); 232 samplerBuilder.setMag(NEAREST); 233 samplerBuilder.setWrapS(WRAP); 234 samplerBuilder.setWrapT(WRAP); 235 mSampler = samplerBuilder.create(); 236 237 ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS); 238 builder.setTexture(ProgramFragment.Builder.EnvMode.REPLACE, 239 ProgramFragment.Builder.Format.RGB, 0); 240 mPfBackground = builder.create(); 241 mPfBackground.setName("PFBackground"); 242 mPfBackground.bindSampler(mSampler, 0); 243 244 samplerBuilder = new Sampler.Builder(mRS); 245 samplerBuilder.setMin(LINEAR); 246 samplerBuilder.setMag(LINEAR); 247 samplerBuilder.setWrapS(WRAP); 248 samplerBuilder.setWrapT(WRAP); 249 mStarSampler = samplerBuilder.create(); 250 251 builder = new ProgramFragment.Builder(mRS); 252 builder.setPointSpriteTexCoordinateReplacement(true); 253 builder.setTexture(ProgramFragment.Builder.EnvMode.MODULATE, 254 ProgramFragment.Builder.Format.RGBA, 0); 255 mPfStars = builder.create(); 256 mPfStars.setName("PFStars"); 257 mPfBackground.bindSampler(mStarSampler, 0); 258 } 259 260 private void createProgramFragmentStore() { 261 ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null); 262 builder.setDepthFunc(ALWAYS); 263 builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); 264 builder.setDitherEnable(false); 265 builder.setDepthMask(false); 266 mPfsBackground = builder.create(); 267 mPfsBackground.setName("PFSBackground"); 268 269 builder = new ProgramStore.Builder(mRS, null, null); 270 builder.setDepthFunc(ALWAYS); 271 builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE); 272 builder.setDitherEnable(false); 273 mPfsLights = builder.create(); 274 mPfsLights.setName("PFSLights"); 275 } 276 277 private void createProgramVertex() { 278 mPvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS); 279 mPvOrthoAlloc.setupOrthoWindow(mWidth, mHeight); 280 281 ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null); 282 mPvBkOrtho = builder.create(); 283 mPvBkOrtho.bindAllocation(mPvOrthoAlloc); 284 mPvBkOrtho.setName("PVBkOrtho"); 285 286 mPvProjectionAlloc = new ProgramVertex.MatrixAllocation(mRS); 287 mPvProjectionAlloc.setupProjectionNormalized(mWidth, mHeight); 288 289 builder = new ProgramVertex.Builder(mRS, null, null); 290 mPvBkProj = builder.create(); 291 mPvBkProj.bindAllocation(mPvProjectionAlloc); 292 mPvBkProj.setName("PVBkProj"); 293 294 ProgramVertex.ShaderBuilder sb = new ProgramVertex.ShaderBuilder(mRS); 295 String t = "void main() {\n" + 296 " float dist = ATTRIB_position.y;\n" + 297 " float angle = ATTRIB_position.x;\n" + 298 " float x = dist * sin(angle);\n" + 299 " float y = dist * cos(angle) * 0.892;\n" + 300 " float p = dist * 5.5;\n" + 301 " float s = cos(p);\n" + 302 " float t = sin(p);\n" + 303 " vec4 pos;\n" + 304 " pos.x = t * x + s * y;\n" + 305 " pos.y = s * x - t * y;\n" + 306 " pos.z = ATTRIB_position.z;\n" + 307 " pos.w = 1.0;\n" + 308 " gl_Position = UNI_MVP * pos;\n" + 309 " gl_PointSize = ATTRIB_color.a * 10.0;\n" + 310 " varColor.rgb = ATTRIB_color.rgb;\n" + 311 " varColor.a = 1.0;\n" + 312 "}\n"; 313 sb.setShader(t); 314 sb.addInput(mParticlesMesh.getVertexType(0).getElement()); 315 mPvStars = sb.create(); 316 mPvStars.bindAllocation(mPvProjectionAlloc); 317 mPvStars.setName("PVStars"); 318 } 319 320 private void createProgramRaster() { 321 ProgramRaster.Builder b = new ProgramRaster.Builder(mRS, null, null); 322 b.setPointSmoothEnable(true); 323 b.setPointSpriteEnable(true); 324 mRS.contextBindProgramRaster(b.create()); 325 } 326 327 } 328