155a384c62528636190cfe0762228d4c2795c6883Romain Guy/*
255a384c62528636190cfe0762228d4c2795c6883Romain Guy * Copyright (C) 2009 The Android Open Source Project
355a384c62528636190cfe0762228d4c2795c6883Romain Guy *
455a384c62528636190cfe0762228d4c2795c6883Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
555a384c62528636190cfe0762228d4c2795c6883Romain Guy * you may not use this file except in compliance with the License.
655a384c62528636190cfe0762228d4c2795c6883Romain Guy * You may obtain a copy of the License at
755a384c62528636190cfe0762228d4c2795c6883Romain Guy *
855a384c62528636190cfe0762228d4c2795c6883Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
955a384c62528636190cfe0762228d4c2795c6883Romain Guy *
1055a384c62528636190cfe0762228d4c2795c6883Romain Guy * Unless required by applicable law or agreed to in writing, software
1155a384c62528636190cfe0762228d4c2795c6883Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
1255a384c62528636190cfe0762228d4c2795c6883Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1355a384c62528636190cfe0762228d4c2795c6883Romain Guy * See the License for the specific language governing permissions and
1455a384c62528636190cfe0762228d4c2795c6883Romain Guy * limitations under the License.
1555a384c62528636190cfe0762228d4c2795c6883Romain Guy */
1655a384c62528636190cfe0762228d4c2795c6883Romain Guy
1755a384c62528636190cfe0762228d4c2795c6883Romain Guypackage com.android.wallpaper.grass;
1855a384c62528636190cfe0762228d4c2795c6883Romain Guy
1955a384c62528636190cfe0762228d4c2795c6883Romain Guyimport android.renderscript.Sampler;
2055a384c62528636190cfe0762228d4c2795c6883Romain Guyimport static android.renderscript.ProgramStore.DepthFunc.*;
2155a384c62528636190cfe0762228d4c2795c6883Romain Guyimport static android.renderscript.ProgramStore.BlendSrcFunc;
2255a384c62528636190cfe0762228d4c2795c6883Romain Guyimport static android.renderscript.ProgramStore.BlendDstFunc;
2376faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchoukimport android.renderscript.*;
2455a384c62528636190cfe0762228d4c2795c6883Romain Guyimport static android.renderscript.Element.*;
2555a384c62528636190cfe0762228d4c2795c6883Romain Guyimport static android.util.MathUtils.*;
2676faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchoukimport android.renderscript.Mesh.Primitive;
2755a384c62528636190cfe0762228d4c2795c6883Romain Guyimport static android.renderscript.Sampler.Value.*;
28a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.content.Context;
29a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.content.IntentFilter;
30a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.content.Intent;
31a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.content.BroadcastReceiver;
32a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.location.LocationManager;
33a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.location.LocationListener;
34a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.location.Location;
35a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.os.Bundle;
36a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport android.text.format.Time;
3755a384c62528636190cfe0762228d4c2795c6883Romain Guyimport com.android.wallpaper.R;
3844da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guyimport com.android.wallpaper.RenderScriptScene;
3955a384c62528636190cfe0762228d4c2795c6883Romain Guy
4055a384c62528636190cfe0762228d4c2795c6883Romain Guyimport java.util.TimeZone;
41a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guyimport java.util.Calendar;
4255a384c62528636190cfe0762228d4c2795c6883Romain Guy
4344da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guyclass GrassRS extends RenderScriptScene {
4441f1b533b84918dfce66c167ef879add467fefddRomain Guy    @SuppressWarnings({"UnusedDeclaration"})
45ab3bef5aa54658edf1bcda773f986d856d86ca43Romain Guy    private static final String LOG_TAG = "Grass";
4641f1b533b84918dfce66c167ef879add467fefddRomain Guy    private static final boolean DEBUG = false;
4739761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams
48fee41f5a5d20c8520cf0fd22f6604f200c1600acRomain Guy    private static final int LOCATION_UPDATE_MIN_TIME = DEBUG ? 5 * 60 * 1000 : 60 * 60 * 1000; // 1 hour
49fee41f5a5d20c8520cf0fd22f6604f200c1600acRomain Guy    private static final int LOCATION_UPDATE_MIN_DISTANCE = DEBUG ? 10 : 150 * 1000; // 150 km
50a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private static final float TESSELATION = 0.5f;
5155a384c62528636190cfe0762228d4c2795c6883Romain Guy    private static final int TEXTURES_COUNT = 5;
5255a384c62528636190cfe0762228d4c2795c6883Romain Guy    private static final int BLADES_COUNT = 200;
532ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams
548aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams    private ScriptField_Blade mBlades;
558aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams    private ScriptField_Vertex mVertexBuffer;
5676faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk    private ProgramVertexFixedFunction.Constants mPvOrthoAlloc;
5755a384c62528636190cfe0762228d4c2795c6883Romain Guy
588aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams    //private Allocation mBladesBuffer;
597a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams    private Allocation mBladesIndicies;
60359f0324a761abae0977a35c0e072e409aecd544Alex Sakhartchouk    private Mesh mBladesMesh;
61b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy
625f5044f59065ac339b175bb8a47ea6be861f925cStephen Hines    private ScriptC_grass mScript;
632ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams
647a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams    private int mVerticies;
657a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams    private int mIndicies;
667a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams    private int[] mBladeSizes;
6755a384c62528636190cfe0762228d4c2795c6883Romain Guy
68a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private final Context mContext;
69a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private final LocationManager mLocationManager;
70a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
71a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private LocationUpdater mLocationUpdater;
72a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private GrassRS.TimezoneTracker mTimezoneTracker;
73a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
74a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    GrassRS(Context context, int width, int height) {
7544da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy        super(width, height);
76a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
77a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        mContext = context;
78a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        mLocationManager = (LocationManager)
79a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy                context.getSystemService(Context.LOCATION_SERVICE);
80a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    }
81a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
82a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    @Override
83a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    public void start() {
84a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        super.start();
85a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
86a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        if (mTimezoneTracker == null) {
87a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            mTimezoneTracker = new TimezoneTracker();
88a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            IntentFilter filter = new IntentFilter();
89ab3bef5aa54658edf1bcda773f986d856d86ca43Romain Guy            filter.addAction(Intent.ACTION_DATE_CHANGED);
90a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            filter.addAction(Intent.ACTION_TIME_CHANGED);
91a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
9239761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams
93a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            mContext.registerReceiver(mTimezoneTracker, filter);
94a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
95a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
96a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        if (mLocationUpdater == null) {
97a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            mLocationUpdater = new LocationUpdater();
986bde8205bb9ae4afb3bb012f3bfb92019d6b1460Conley Owens            try {
996bde8205bb9ae4afb3bb012f3bfb92019d6b1460Conley Owens              mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
1006bde8205bb9ae4afb3bb012f3bfb92019d6b1460Conley Owens                      LOCATION_UPDATE_MIN_TIME, LOCATION_UPDATE_MIN_DISTANCE, mLocationUpdater);
1016bde8205bb9ae4afb3bb012f3bfb92019d6b1460Conley Owens            } catch (java.lang.IllegalArgumentException e) {
1026bde8205bb9ae4afb3bb012f3bfb92019d6b1460Conley Owens              if (!e.getMessage().equals("provider=network")) {
1036bde8205bb9ae4afb3bb012f3bfb92019d6b1460Conley Owens                throw e;
1046bde8205bb9ae4afb3bb012f3bfb92019d6b1460Conley Owens              }
1056bde8205bb9ae4afb3bb012f3bfb92019d6b1460Conley Owens            }
106a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
107a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
108a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        updateLocation();
109a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    }
110a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
111a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    @Override
112a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    public void stop() {
113a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        super.stop();
114a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
115a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        if (mTimezoneTracker != null) {
116a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            mContext.unregisterReceiver(mTimezoneTracker);
117a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            mTimezoneTracker = null;
118a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
11939761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams
120a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        if (mLocationUpdater != null) {
121a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            mLocationManager.removeUpdates(mLocationUpdater);
122a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            mLocationUpdater = null;
123a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
1249e6f2347087ab40539b4c4b76f4b050f02184436Romain Guy    }
1259e6f2347087ab40539b4c4b76f4b050f02184436Romain Guy
12644da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy    @Override
12744da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy    public void resize(int width, int height) {
12844da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy        super.resize(width, height);
129575d514273135bb13ff662037b4ed4eb7c8aa985Jason Sams
1308aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gWidth(width);
1318aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gHeight(height);
132144361958bf67ff199ee65433af1a390dbd80fefJason Sams        mScript.invoke_updateBlades();
13376faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        Matrix4f proj = new Matrix4f();
13476faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        proj.loadOrthoWindow(width, height);
13576faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        mPvOrthoAlloc.setProjection(proj);
1369e6f2347087ab40539b4c4b76f4b050f02184436Romain Guy    }
13744da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy
13844da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy    @Override
13944da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy    protected ScriptC createScript() {
14076469b31f1bda22057330a0146d9296df92b9094Jason Sams        mScript = new ScriptC_grass(mRS, mResources, R.raw.grass);
1418aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams
1428aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        final boolean isPreview = isPreview();
14355a384c62528636190cfe0762228d4c2795c6883Romain Guy        createProgramVertex();
14455a384c62528636190cfe0762228d4c2795c6883Romain Guy        createProgramFragmentStore();
14539761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams        loadTextures();
14655a384c62528636190cfe0762228d4c2795c6883Romain Guy        createProgramFragment();
147b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy        createBlades();
1488aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams
1498aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gBladesCount(BLADES_COUNT);
1508aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gIndexCount(mIndicies);
1518aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gWidth(mWidth);
1528aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gHeight(mHeight);
1538aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gXOffset(isPreview ? 0.5f : 0.f);
1548aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gIsPreview(isPreview ? 1 : 0);
1558aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gBladesMesh(mBladesMesh);
1568aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams
1578aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.setTimeZone(TimeZone.getDefault().getID());
1588aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.bind_Blades(mBlades);
1598aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.bind_Verticies(mVertexBuffer);
1608aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams
1618aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        // set these to reasonable defaults.
1628aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gDawn(6.f / 24.f);
1638aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gDusk(18.f / 24.f);
1648aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gMorning(8.f / 24.f); // 2 hours for sunrise
1658aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gAfternoon(16.f / 24.f); // 2 hours for sunset
1668aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams
1678aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        return mScript;
168b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy    }
169b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy
17044da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy    @Override
17144da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy    public void setOffset(float xOffset, float yOffset, int xPixels, int yPixels) {
1728aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gXOffset(xOffset);
173b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy    }
174b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy
175b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy    private void createBlades() {
1767a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams        mVerticies = 0;
1777a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams        mIndicies = 0;
17855a384c62528636190cfe0762228d4c2795c6883Romain Guy
1798aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mBlades = new ScriptField_Blade(mRS, BLADES_COUNT);
180f0bb95619b01499e991bee297745cad31c20b28eRomain Guy
1817a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams        mBladeSizes = new int[BLADES_COUNT];
1822ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        for (int i = 0; i < BLADES_COUNT; i++) {
1838aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams            ScriptField_Blade.Item item = new ScriptField_Blade.Item();
1848aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams            createBlade(item);
1858aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams            mBlades.set(item, i, false);
1868aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams
1878aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams            mIndicies += item.size * 2 * 3;
1888aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams            mVerticies += item.size + 2;
1898aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams            mBladeSizes[i] = item.size;
19055a384c62528636190cfe0762228d4c2795c6883Romain Guy        }
1918aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mBlades.copyAll();
192b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy
1937a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams        createMesh();
194b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy    }
195b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy
1967a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams    private void createMesh() {
1978aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mVertexBuffer = new ScriptField_Vertex(mRS, mVerticies * 2);
1988aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams
199359f0324a761abae0977a35c0e072e409aecd544Alex Sakhartchouk        final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS);
200359f0324a761abae0977a35c0e072e409aecd544Alex Sakhartchouk        meshBuilder.addVertexAllocation(mVertexBuffer.getAllocation());
201359f0324a761abae0977a35c0e072e409aecd544Alex Sakhartchouk
202359f0324a761abae0977a35c0e072e409aecd544Alex Sakhartchouk        mBladesIndicies = Allocation.createSized(mRS, Element.U16(mRS), mIndicies);
20376faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        meshBuilder.addIndexSetAllocation(mBladesIndicies, Primitive.TRIANGLE);
204b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy
205359f0324a761abae0977a35c0e072e409aecd544Alex Sakhartchouk        mBladesMesh = meshBuilder.create();
206b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy
2077a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams        short[] idx = new short[mIndicies];
2087a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams        int idxIdx = 0;
2097a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams        int vtxIdx = 0;
2107a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams        for (int i = 0; i < mBladeSizes.length; i++) {
2117a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams            for (int ct = 0; ct < mBladeSizes[i]; ct ++) {
2127a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams                idx[idxIdx + 0] = (short)(vtxIdx + 0);
2137a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams                idx[idxIdx + 1] = (short)(vtxIdx + 1);
2147a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams                idx[idxIdx + 2] = (short)(vtxIdx + 2);
2157a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams                idx[idxIdx + 3] = (short)(vtxIdx + 1);
2167a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams                idx[idxIdx + 4] = (short)(vtxIdx + 3);
2177a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams                idx[idxIdx + 5] = (short)(vtxIdx + 2);
2187a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams                idxIdx += 6;
2197a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams                vtxIdx += 2;
2207a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams            }
2217a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams            vtxIdx += 2;
222b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy        }
2237a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams
22476469b31f1bda22057330a0146d9296df92b9094Jason Sams        mBladesIndicies.copyFrom(idx);
22555a384c62528636190cfe0762228d4c2795c6883Romain Guy    }
22655a384c62528636190cfe0762228d4c2795c6883Romain Guy
2278aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams    private void createBlade(ScriptField_Blade.Item blades) {
228b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy        final float size = random(4.0f) + 4.0f;
22944da17844aa73a047a1f1ff67b4794ea330be3b5Romain Guy        final int xpos = random(-mWidth, mWidth);
230b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy
23155a384c62528636190cfe0762228d4c2795c6883Romain Guy        //noinspection PointlessArithmeticExpression
2322ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.angle = 0.0f;
2332ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.size = (int)(size / TESSELATION);
2342ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.xPos = xpos;
2352ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.yPos = mHeight;
2362ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.offset = random(0.2f) - 0.1f;
2372ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.scale = 4.0f / (size / TESSELATION) + (random(0.6f) + 0.2f) * TESSELATION;
2382ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.lengthX = (random(4.5f) + 3.0f) * TESSELATION * size;
2392ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.lengthY = (random(5.5f) + 2.0f) * TESSELATION * size;
2402ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.hardness = (random(1.0f) + 0.2f) * TESSELATION;
2412ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.h = random(0.02f) + 0.2f;
2422ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.s = random(0.22f) + 0.78f;
2432ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.b = random(0.65f) + 0.35f;
2442ffa1cb7ec3fbfea042e45c2804d5dd4dd812b94Jason Sams        blades.turbulencex = xpos * 0.006f;
24555a384c62528636190cfe0762228d4c2795c6883Romain Guy    }
24655a384c62528636190cfe0762228d4c2795c6883Romain Guy
24755a384c62528636190cfe0762228d4c2795c6883Romain Guy    private void loadTextures() {
2488aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gTNight(loadTexture(R.drawable.night));
2498aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gTSunrise(loadTexture(R.drawable.sunrise));
2508aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gTSky(loadTexture(R.drawable.sky));
2518aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gTSunset(loadTexture(R.drawable.sunset));
252b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        mScript.set_gTAa(generateTextureAlpha());
25355a384c62528636190cfe0762228d4c2795c6883Romain Guy    }
25455a384c62528636190cfe0762228d4c2795c6883Romain Guy
255b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams    private Allocation generateTextureAlpha() {
256575d514273135bb13ff662037b4ed4eb7c8aa985Jason Sams        final Type.Builder builder = new Type.Builder(mRS, A_8(mRS));
257b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        builder.setX(4);
258b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        builder.setY(1);
25976469b31f1bda22057330a0146d9296df92b9094Jason Sams        builder.setMipmaps(true);
260575d514273135bb13ff662037b4ed4eb7c8aa985Jason Sams
261ff72c0eec3b4b0400fc903bcc5ae78fa495a1678Jason Sams        final Allocation allocation = Allocation.createTyped(mRS, builder.create(),
262ff72c0eec3b4b0400fc903bcc5ae78fa495a1678Jason Sams                                                             Allocation.USAGE_GRAPHICS_TEXTURE);
263b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        byte[] mip0 = new byte[] {0, -1, -1, 0};
264b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        byte[] mip1 = new byte[] {64, 64};
265b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        byte[] mip2 = new byte[] {0};
2669c28ff884296f3c14e1bb1c2799c460f016e3f42Jason Sams
2679c28ff884296f3c14e1bb1c2799c460f016e3f42Jason Sams        AllocationAdapter a = AllocationAdapter.create2D(mRS, allocation);
2689c28ff884296f3c14e1bb1c2799c460f016e3f42Jason Sams        a.setLOD(0);
269b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        a.copyFrom(mip0);
2709c28ff884296f3c14e1bb1c2799c460f016e3f42Jason Sams        a.setLOD(1);
271b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        a.copyFrom(mip1);
2729c28ff884296f3c14e1bb1c2799c460f016e3f42Jason Sams        a.setLOD(2);
273b699d1f04a3452dd88ca68044ce93cc765369af4Jason Sams        a.copyFrom(mip2);
2747a990688bb00e14ab9d3395539cd1971f09e93e5Jason Sams
27555a384c62528636190cfe0762228d4c2795c6883Romain Guy        return allocation;
27655a384c62528636190cfe0762228d4c2795c6883Romain Guy    }
27755a384c62528636190cfe0762228d4c2795c6883Romain Guy
2788aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams    private Allocation loadTexture(int id) {
279bbcb547467bd09da372a15ac235e239c6557289bJason Sams        return Allocation.createFromBitmapResource(mRS, mResources, id);
28055a384c62528636190cfe0762228d4c2795c6883Romain Guy    }
28155a384c62528636190cfe0762228d4c2795c6883Romain Guy
28255a384c62528636190cfe0762228d4c2795c6883Romain Guy    private void createProgramFragment() {
283b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy        Sampler.Builder samplerBuilder = new Sampler.Builder(mRS);
28476faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        samplerBuilder.setMinification(LINEAR_MIP_LINEAR);
28576faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        samplerBuilder.setMagnification(LINEAR);
286b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy        samplerBuilder.setWrapS(WRAP);
287b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy        samplerBuilder.setWrapT(WRAP);
28839761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams        Sampler sl = samplerBuilder.create();
28939761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams
29076faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        samplerBuilder.setMinification(NEAREST);
29176faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        samplerBuilder.setMagnification(NEAREST);
29239761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams        Sampler sn = samplerBuilder.create();
29339761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams
29476faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
29576faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
29676faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk                           ProgramFragmentFixedFunction.Builder.Format.ALPHA, 0);
2975dde25d38dd72a709c7e7e6c9dd7975d39bd8b0aJason Sams        builder.setVaryingColor(true);
2988aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        ProgramFragment pf = builder.create();
2998aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gPFGrass(pf);
3008aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        pf.bindSampler(sl, 0);
30139761a986ce070f7761c6fcd2113b6e4cd18bb31Jason Sams
30276faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        builder = new ProgramFragmentFixedFunction.Builder(mRS);
30376faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
30476faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk                           ProgramFragmentFixedFunction.Builder.Format.RGB, 0);
3058aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        pf = builder.create();
3068aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gPFBackground(pf);
3078aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        pf.bindSampler(sn, 0);
30855a384c62528636190cfe0762228d4c2795c6883Romain Guy    }
30955a384c62528636190cfe0762228d4c2795c6883Romain Guy
31055a384c62528636190cfe0762228d4c2795c6883Romain Guy    private void createProgramFragmentStore() {
31176faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        ProgramStore.Builder builder = new ProgramStore.Builder(mRS);
312b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy        builder.setDepthFunc(ALWAYS);
313b7d225205d18b1f97a305ea07ef1de9ff8d86906Romain Guy        builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
31476faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        builder.setDitherEnabled(false);
31576faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        builder.setDepthMaskEnabled(false);
3168aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gPSBackground(builder.create());
31755a384c62528636190cfe0762228d4c2795c6883Romain Guy    }
31855a384c62528636190cfe0762228d4c2795c6883Romain Guy
31955a384c62528636190cfe0762228d4c2795c6883Romain Guy    private void createProgramVertex() {
32076faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        mPvOrthoAlloc = new ProgramVertexFixedFunction.Constants(mRS);
32176faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        Matrix4f proj = new Matrix4f();
32276faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        proj.loadOrthoWindow(mWidth, mHeight);
32376faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        mPvOrthoAlloc.setProjection(proj);
32455a384c62528636190cfe0762228d4c2795c6883Romain Guy
32576faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
3268aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        ProgramVertex pv = pvb.create();
32776faca88c5c6c0e75cf05dc139f33c07df96366fAlex Sakhartchouk        ((ProgramVertexFixedFunction)pv).bindConstants(mPvOrthoAlloc);
3288aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gPVBackground(pv);
32955a384c62528636190cfe0762228d4c2795c6883Romain Guy    }
330a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
331a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private void updateLocation() {
332a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        updateLocation(mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER));
333a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    }
334a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
335a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private void updateLocation(Location location) {
3368aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        float dawn = 0.3f;
3378aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        float dusk = 0.75f;
3388aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams
339a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        if (location != null) {
340a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            final String timeZone = Time.getCurrentTimezone();
341a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            final SunCalculator calculator = new SunCalculator(location, timeZone);
342a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            final Calendar now = Calendar.getInstance();
343a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
344a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            final double sunrise = calculator.computeSunriseTime(SunCalculator.ZENITH_CIVIL, now);
3458aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams            dawn = SunCalculator.timeToDayFraction(sunrise);
346a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
347a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            final double sunset = calculator.computeSunsetTime(SunCalculator.ZENITH_CIVIL, now);
3488aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams            dusk = SunCalculator.timeToDayFraction(sunset);
349a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
350a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
3518aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gDawn(dawn);
3528aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gDusk(dusk);
3538aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gMorning(dawn + 1.0f / 12.0f); // 2 hours for sunrise
3548aeb9839d8b2ed85ab5a580d1b10554866add28aJason Sams        mScript.set_gAfternoon(dusk - 1.0f / 12.0f); // 2 hours for sunset
355a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    }
356a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
357a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private class LocationUpdater implements LocationListener {
358a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        public void onLocationChanged(Location location) {
359a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            updateLocation(location);
360a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
361a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
362a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        public void onStatusChanged(String provider, int status, Bundle extras) {
363a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
364a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
365a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        public void onProviderEnabled(String provider) {
366a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
367a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
368a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        public void onProviderDisabled(String provider) {
369a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
370a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    }
371a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy
372a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    private class TimezoneTracker extends BroadcastReceiver {
373a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        public void onReceive(Context context, Intent intent) {
374a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            getScript().setTimeZone(Time.getCurrentTimezone());
375a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy            updateLocation();
376a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy        }
377a56ce01d5f2e831ad4a5ada54a3c10f8075e4921Romain Guy    }
37855a384c62528636190cfe0762228d4c2795c6883Romain Guy}
379