13c1e67e433728684b5f228c5d4f3e5b1457bb271sm/*
23c1e67e433728684b5f228c5d4f3e5b1457bb271sm * Copyright (C) 2010 The Android Open Source Project
33c1e67e433728684b5f228c5d4f3e5b1457bb271sm *
43c1e67e433728684b5f228c5d4f3e5b1457bb271sm * Licensed under the Apache License, Version 2.0 (the "License");
53c1e67e433728684b5f228c5d4f3e5b1457bb271sm * you may not use this file except in compliance with the License.
63c1e67e433728684b5f228c5d4f3e5b1457bb271sm * You may obtain a copy of the License at
73c1e67e433728684b5f228c5d4f3e5b1457bb271sm *
83c1e67e433728684b5f228c5d4f3e5b1457bb271sm *      http://www.apache.org/licenses/LICENSE-2.0
93c1e67e433728684b5f228c5d4f3e5b1457bb271sm *
103c1e67e433728684b5f228c5d4f3e5b1457bb271sm * Unless required by applicable law or agreed to in writing, software
113c1e67e433728684b5f228c5d4f3e5b1457bb271sm * distributed under the License is distributed on an "AS IS" BASIS,
123c1e67e433728684b5f228c5d4f3e5b1457bb271sm * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133c1e67e433728684b5f228c5d4f3e5b1457bb271sm * See the License for the specific language governing permissions and
143c1e67e433728684b5f228c5d4f3e5b1457bb271sm * limitations under the License.
153c1e67e433728684b5f228c5d4f3e5b1457bb271sm */
163c1e67e433728684b5f228c5d4f3e5b1457bb271sm
17cfd74d65d832137e20e193c960802afba73b5d38smpackage com.replica.replicaisland;
18cfd74d65d832137e20e193c960802afba73b5d38sm
19cfd74d65d832137e20e193c960802afba73b5d38smimport javax.microedition.khronos.opengles.GL10;
20cfd74d65d832137e20e193c960802afba73b5d38sm
21cfd74d65d832137e20e193c960802afba73b5d38smpublic class TiledVertexGrid extends BaseObject {
22cfd74d65d832137e20e193c960802afba73b5d38sm	private static final float GL_MAGIC_OFFSET = 0.375f;
23cfd74d65d832137e20e193c960802afba73b5d38sm    private Grid mTileMap;
24cfd74d65d832137e20e193c960802afba73b5d38sm    private TiledWorld mWorld;
25cfd74d65d832137e20e193c960802afba73b5d38sm    private int mTileWidth;
26cfd74d65d832137e20e193c960802afba73b5d38sm    private int mTileHeight;
27cfd74d65d832137e20e193c960802afba73b5d38sm
28cfd74d65d832137e20e193c960802afba73b5d38sm    private int mWidth;
29cfd74d65d832137e20e193c960802afba73b5d38sm    private int mHeight;
30cfd74d65d832137e20e193c960802afba73b5d38sm    private Texture mTexture;
31cfd74d65d832137e20e193c960802afba73b5d38sm
32cfd74d65d832137e20e193c960802afba73b5d38sm    private float mWorldPixelWidth;
33cfd74d65d832137e20e193c960802afba73b5d38sm    private float mWorldPixelHeight;
34cfd74d65d832137e20e193c960802afba73b5d38sm
35cfd74d65d832137e20e193c960802afba73b5d38sm    private int mTilesPerRow;
36cfd74d65d832137e20e193c960802afba73b5d38sm    private int mTilesPerColumn;
37cfd74d65d832137e20e193c960802afba73b5d38sm
389d4cc2572d37983607df38b0f4216ed76ac51814sm    private Boolean mGenerated;
399d4cc2572d37983607df38b0f4216ed76ac51814sm
40cfd74d65d832137e20e193c960802afba73b5d38sm    public TiledVertexGrid(Texture texture, int width, int height, int tileWidth, int tileHeight) {
41cfd74d65d832137e20e193c960802afba73b5d38sm        super();
42cfd74d65d832137e20e193c960802afba73b5d38sm        mTileWidth = tileWidth;
43cfd74d65d832137e20e193c960802afba73b5d38sm        mTileHeight = tileHeight;
44cfd74d65d832137e20e193c960802afba73b5d38sm        mWidth = width;
45cfd74d65d832137e20e193c960802afba73b5d38sm        mHeight = height;
46cfd74d65d832137e20e193c960802afba73b5d38sm        mTexture = texture;
479d4cc2572d37983607df38b0f4216ed76ac51814sm        mGenerated = false;
48cfd74d65d832137e20e193c960802afba73b5d38sm    }
49cfd74d65d832137e20e193c960802afba73b5d38sm
50cfd74d65d832137e20e193c960802afba73b5d38sm    @Override
51cfd74d65d832137e20e193c960802afba73b5d38sm    public void reset() {
52cfd74d65d832137e20e193c960802afba73b5d38sm    }
53cfd74d65d832137e20e193c960802afba73b5d38sm
54cfd74d65d832137e20e193c960802afba73b5d38sm    public void setWorld(TiledWorld world) {
55cfd74d65d832137e20e193c960802afba73b5d38sm        mWorld = world;
56cfd74d65d832137e20e193c960802afba73b5d38sm
57cfd74d65d832137e20e193c960802afba73b5d38sm    }
58cfd74d65d832137e20e193c960802afba73b5d38sm
59cfd74d65d832137e20e193c960802afba73b5d38sm    private Grid generateGrid(int width, int height, int startTileX, int startTileY) {
60cfd74d65d832137e20e193c960802afba73b5d38sm        final int tileWidth = mTileWidth;
61cfd74d65d832137e20e193c960802afba73b5d38sm        final int tileHeight = mTileHeight;
62cfd74d65d832137e20e193c960802afba73b5d38sm        final int tilesAcross = width / tileWidth;
63cfd74d65d832137e20e193c960802afba73b5d38sm        final int tilesDown = height / tileHeight;
64cfd74d65d832137e20e193c960802afba73b5d38sm        final Texture texture = mTexture;
65cfd74d65d832137e20e193c960802afba73b5d38sm        final float texelWidth = 1.0f / texture.width;
66cfd74d65d832137e20e193c960802afba73b5d38sm        final float texelHeight = 1.0f / texture.height;
67cfd74d65d832137e20e193c960802afba73b5d38sm        final int textureTilesAcross = texture.width / tileWidth;
68cfd74d65d832137e20e193c960802afba73b5d38sm        final int textureTilesDown = texture.height / tileHeight;
69cfd74d65d832137e20e193c960802afba73b5d38sm        final int tilesPerWorldColumn = mWorld.getHeight();
70cfd74d65d832137e20e193c960802afba73b5d38sm        final int totalTextureTiles = textureTilesAcross * textureTilesDown;
71cfd74d65d832137e20e193c960802afba73b5d38sm        // Check to see if this entire grid is empty tiles.  If so, we don't need to do anything.
72cfd74d65d832137e20e193c960802afba73b5d38sm        boolean entirelyEmpty = true;
73cfd74d65d832137e20e193c960802afba73b5d38sm        for (int tileY = 0; tileY < tilesDown && entirelyEmpty; tileY++) {
74cfd74d65d832137e20e193c960802afba73b5d38sm            for (int tileX = 0; tileX < tilesAcross && entirelyEmpty; tileX++) {
75cfd74d65d832137e20e193c960802afba73b5d38sm                int tileIndex = mWorld.getTile(startTileX + tileX,
76cfd74d65d832137e20e193c960802afba73b5d38sm                        (tilesPerWorldColumn - 1 - (startTileY + tileY)));
77cfd74d65d832137e20e193c960802afba73b5d38sm                if (tileIndex >= 0) {
78cfd74d65d832137e20e193c960802afba73b5d38sm                    entirelyEmpty = false;
79cfd74d65d832137e20e193c960802afba73b5d38sm                    break;
80cfd74d65d832137e20e193c960802afba73b5d38sm                }
81cfd74d65d832137e20e193c960802afba73b5d38sm            }
82cfd74d65d832137e20e193c960802afba73b5d38sm        }
83cfd74d65d832137e20e193c960802afba73b5d38sm
84cfd74d65d832137e20e193c960802afba73b5d38sm        Grid grid = null;
85cfd74d65d832137e20e193c960802afba73b5d38sm        if (!entirelyEmpty) {
86cfd74d65d832137e20e193c960802afba73b5d38sm            grid = new Grid(tilesAcross, tilesDown, false);
87cfd74d65d832137e20e193c960802afba73b5d38sm            for (int tileY = 0; tileY < tilesDown; tileY++) {
88cfd74d65d832137e20e193c960802afba73b5d38sm                for (int tileX = 0; tileX < tilesAcross; tileX++) {
89cfd74d65d832137e20e193c960802afba73b5d38sm                    final float offsetX = tileX * tileWidth;
90cfd74d65d832137e20e193c960802afba73b5d38sm                    final float offsetY = tileY * tileHeight;
91cfd74d65d832137e20e193c960802afba73b5d38sm                    int tileIndex = mWorld.getTile(startTileX + tileX,
92cfd74d65d832137e20e193c960802afba73b5d38sm                            (tilesPerWorldColumn - 1 - (startTileY + tileY)));
93cfd74d65d832137e20e193c960802afba73b5d38sm                    if (tileIndex < 0) {
94cfd74d65d832137e20e193c960802afba73b5d38sm                        tileIndex = totalTextureTiles - 1; // Assume that the last tile is empty.
95cfd74d65d832137e20e193c960802afba73b5d38sm                    }
96cfd74d65d832137e20e193c960802afba73b5d38sm                    int textureOffsetX = (tileIndex % textureTilesAcross) * tileWidth;
97cfd74d65d832137e20e193c960802afba73b5d38sm                    int textureOffsetY = (tileIndex / textureTilesAcross) * tileHeight;
98cfd74d65d832137e20e193c960802afba73b5d38sm                    if (textureOffsetX < 0 ||
99cfd74d65d832137e20e193c960802afba73b5d38sm                            textureOffsetX > texture.width - tileWidth ||
100cfd74d65d832137e20e193c960802afba73b5d38sm                            textureOffsetY < 0 ||
101cfd74d65d832137e20e193c960802afba73b5d38sm                            textureOffsetY > texture.height - tileHeight) {
102cfd74d65d832137e20e193c960802afba73b5d38sm                        textureOffsetX = 0;
103cfd74d65d832137e20e193c960802afba73b5d38sm                        textureOffsetY = 0;
104cfd74d65d832137e20e193c960802afba73b5d38sm                    }
105cfd74d65d832137e20e193c960802afba73b5d38sm                    final float u = (textureOffsetX + GL_MAGIC_OFFSET) * texelWidth;
106cfd74d65d832137e20e193c960802afba73b5d38sm                    final float v = (textureOffsetY + GL_MAGIC_OFFSET) * texelHeight;
107cfd74d65d832137e20e193c960802afba73b5d38sm                    final float u2 = ((textureOffsetX + tileWidth - GL_MAGIC_OFFSET) * texelWidth);
108cfd74d65d832137e20e193c960802afba73b5d38sm                    final float v2 = ((textureOffsetY + tileHeight - GL_MAGIC_OFFSET) * texelHeight);
109cfd74d65d832137e20e193c960802afba73b5d38sm
110cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[] p0 = { offsetX, offsetY, 0.0f };
111cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[] p1 = { offsetX + tileWidth, offsetY, 0.0f };
112cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[] p2 = { offsetX, offsetY + tileHeight, 0.0f };
113cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[] p3 = { offsetX + tileWidth, offsetY + tileHeight, 0.0f };
114cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[] uv0 = { u, v2 };
115cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[] uv1 = { u2, v2 };
116cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[] uv2 = { u, v };
117cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[] uv3 = { u2, v };
118cfd74d65d832137e20e193c960802afba73b5d38sm
119cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[][] positions = { p0, p1, p2, p3 };
120cfd74d65d832137e20e193c960802afba73b5d38sm                    final float[][] uvs = { uv0, uv1, uv2, uv3 };
121cfd74d65d832137e20e193c960802afba73b5d38sm
122cfd74d65d832137e20e193c960802afba73b5d38sm                    grid.set(tileX, tileY, positions, uvs);
123cfd74d65d832137e20e193c960802afba73b5d38sm
124cfd74d65d832137e20e193c960802afba73b5d38sm                }
125cfd74d65d832137e20e193c960802afba73b5d38sm            }
126cfd74d65d832137e20e193c960802afba73b5d38sm        }
127cfd74d65d832137e20e193c960802afba73b5d38sm        return grid;
128cfd74d65d832137e20e193c960802afba73b5d38sm    }
129cfd74d65d832137e20e193c960802afba73b5d38sm
130cfd74d65d832137e20e193c960802afba73b5d38sm    public void draw(float x, float y, float scrollOriginX, float scrollOriginY) {
131cfd74d65d832137e20e193c960802afba73b5d38sm        TiledWorld world = mWorld;
132cfd74d65d832137e20e193c960802afba73b5d38sm        GL10 gl = OpenGLSystem.getGL();
1339d4cc2572d37983607df38b0f4216ed76ac51814sm        if (!mGenerated && world != null && gl != null && mTexture != null) {
134cfd74d65d832137e20e193c960802afba73b5d38sm            final int tilesAcross = mWorld.getWidth();
135cfd74d65d832137e20e193c960802afba73b5d38sm            final int tilesDown = mWorld.getHeight();
136cfd74d65d832137e20e193c960802afba73b5d38sm
137cfd74d65d832137e20e193c960802afba73b5d38sm            mWorldPixelWidth = mWorld.getWidth() * mTileWidth;
138cfd74d65d832137e20e193c960802afba73b5d38sm            mWorldPixelHeight = mWorld.getHeight() * mTileHeight;
139cfd74d65d832137e20e193c960802afba73b5d38sm            mTilesPerRow = tilesAcross;
140cfd74d65d832137e20e193c960802afba73b5d38sm            mTilesPerColumn = tilesDown;
141cfd74d65d832137e20e193c960802afba73b5d38sm
142cfd74d65d832137e20e193c960802afba73b5d38sm
143cfd74d65d832137e20e193c960802afba73b5d38sm            BufferLibrary bufferLibrary = sSystemRegistry.bufferLibrary;
144cfd74d65d832137e20e193c960802afba73b5d38sm
145cfd74d65d832137e20e193c960802afba73b5d38sm            Grid grid = generateGrid((int)mWorldPixelWidth, (int)mWorldPixelHeight, 0, 0);
146cfd74d65d832137e20e193c960802afba73b5d38sm            mTileMap = grid;
1479d4cc2572d37983607df38b0f4216ed76ac51814sm            mGenerated = true;
148cfd74d65d832137e20e193c960802afba73b5d38sm            if (grid != null) {
149cfd74d65d832137e20e193c960802afba73b5d38sm                bufferLibrary.add(grid);
150cfd74d65d832137e20e193c960802afba73b5d38sm                if (sSystemRegistry.contextParameters.supportsVBOs) {
151cfd74d65d832137e20e193c960802afba73b5d38sm                	grid.generateHardwareBuffers(gl);
152cfd74d65d832137e20e193c960802afba73b5d38sm                }
153cfd74d65d832137e20e193c960802afba73b5d38sm            }
1549d4cc2572d37983607df38b0f4216ed76ac51814sm
155cfd74d65d832137e20e193c960802afba73b5d38sm        }
156cfd74d65d832137e20e193c960802afba73b5d38sm
157cfd74d65d832137e20e193c960802afba73b5d38sm        final Grid tileMap = mTileMap;
158cfd74d65d832137e20e193c960802afba73b5d38sm        if (tileMap != null) {
159cfd74d65d832137e20e193c960802afba73b5d38sm            final Texture texture = mTexture;
160cfd74d65d832137e20e193c960802afba73b5d38sm            if (gl != null && texture != null) {
161cfd74d65d832137e20e193c960802afba73b5d38sm
162cfd74d65d832137e20e193c960802afba73b5d38sm                int originX = (int) (x - scrollOriginX);
163cfd74d65d832137e20e193c960802afba73b5d38sm                int originY = (int) (y - scrollOriginY);
164cfd74d65d832137e20e193c960802afba73b5d38sm
165cfd74d65d832137e20e193c960802afba73b5d38sm
166cfd74d65d832137e20e193c960802afba73b5d38sm                final float worldPixelWidth = mWorldPixelWidth;
167cfd74d65d832137e20e193c960802afba73b5d38sm
168cfd74d65d832137e20e193c960802afba73b5d38sm                final float percentageScrollRight =
169cfd74d65d832137e20e193c960802afba73b5d38sm                    scrollOriginX != 0.0f ? scrollOriginX / worldPixelWidth : 0.0f;
170cfd74d65d832137e20e193c960802afba73b5d38sm                final float tileSpaceX = percentageScrollRight * mTilesPerRow;
171cfd74d65d832137e20e193c960802afba73b5d38sm                final int leftTile = (int)tileSpaceX;
172cfd74d65d832137e20e193c960802afba73b5d38sm
173cfd74d65d832137e20e193c960802afba73b5d38sm                // calculate the top tile index
174cfd74d65d832137e20e193c960802afba73b5d38sm                final float worldPixelHeight = mWorldPixelHeight;
175cfd74d65d832137e20e193c960802afba73b5d38sm
176cfd74d65d832137e20e193c960802afba73b5d38sm                final float percentageScrollUp =
177cfd74d65d832137e20e193c960802afba73b5d38sm                    scrollOriginY != 0.0f ? scrollOriginY / worldPixelHeight : 0.0f;
178cfd74d65d832137e20e193c960802afba73b5d38sm                final float tileSpaceY = percentageScrollUp * mTilesPerColumn;
179cfd74d65d832137e20e193c960802afba73b5d38sm                final int bottomTile = (int)tileSpaceY;
180cfd74d65d832137e20e193c960802afba73b5d38sm
181cfd74d65d832137e20e193c960802afba73b5d38sm                // calculate any sub-tile slop that our scroll position may require.
182cfd74d65d832137e20e193c960802afba73b5d38sm                final int horizontalSlop = ((tileSpaceX - leftTile) * mTileWidth) > 0 ? 1 : 0;
183cfd74d65d832137e20e193c960802afba73b5d38sm                final int verticalSlop = ((tileSpaceY - bottomTile) * mTileHeight) > 0 ? 1 : 0;
184cfd74d65d832137e20e193c960802afba73b5d38sm
185cfd74d65d832137e20e193c960802afba73b5d38sm
186cfd74d65d832137e20e193c960802afba73b5d38sm                OpenGLSystem.bindTexture(GL10.GL_TEXTURE_2D, texture.name);
187cfd74d65d832137e20e193c960802afba73b5d38sm                tileMap.beginDrawingStrips(gl, true);
188cfd74d65d832137e20e193c960802afba73b5d38sm
189cfd74d65d832137e20e193c960802afba73b5d38sm                final int horzTileCount = (int)Math.ceil((float)mWidth / mTileWidth);
190cfd74d65d832137e20e193c960802afba73b5d38sm                final int vertTileCount = (int)Math.ceil((float)mHeight / mTileHeight);
191cfd74d65d832137e20e193c960802afba73b5d38sm                // draw vertex strips
192cfd74d65d832137e20e193c960802afba73b5d38sm                final int startX = leftTile;
193cfd74d65d832137e20e193c960802afba73b5d38sm                final int startY = bottomTile;
194cfd74d65d832137e20e193c960802afba73b5d38sm                final int endX = startX + horizontalSlop + horzTileCount;
195cfd74d65d832137e20e193c960802afba73b5d38sm                final int endY = startY + verticalSlop +  vertTileCount;
196cfd74d65d832137e20e193c960802afba73b5d38sm
197cfd74d65d832137e20e193c960802afba73b5d38sm                gl.glPushMatrix();
198cfd74d65d832137e20e193c960802afba73b5d38sm                gl.glLoadIdentity();
199cfd74d65d832137e20e193c960802afba73b5d38sm                gl.glTranslatef(
200cfd74d65d832137e20e193c960802afba73b5d38sm                        originX,
201cfd74d65d832137e20e193c960802afba73b5d38sm                        originY,
202cfd74d65d832137e20e193c960802afba73b5d38sm                        0.0f);
203cfd74d65d832137e20e193c960802afba73b5d38sm
204cfd74d65d832137e20e193c960802afba73b5d38sm
205cfd74d65d832137e20e193c960802afba73b5d38sm                final int indexesPerTile = 6;
206cfd74d65d832137e20e193c960802afba73b5d38sm                final int indexesPerRow = mTilesPerRow * indexesPerTile;
207cfd74d65d832137e20e193c960802afba73b5d38sm                final int startOffset = (startX * indexesPerTile);
208cfd74d65d832137e20e193c960802afba73b5d38sm                final int count = (endX - startX) * indexesPerTile;
209cfd74d65d832137e20e193c960802afba73b5d38sm                for (int tileY = startY; tileY < endY && tileY < mTilesPerColumn; tileY++) {
210cfd74d65d832137e20e193c960802afba73b5d38sm                	final int row = tileY * indexesPerRow;
211cfd74d65d832137e20e193c960802afba73b5d38sm                	tileMap.drawStrip(gl, true, row + startOffset, count);
212cfd74d65d832137e20e193c960802afba73b5d38sm                }
213cfd74d65d832137e20e193c960802afba73b5d38sm
214cfd74d65d832137e20e193c960802afba73b5d38sm                gl.glPopMatrix();
215cfd74d65d832137e20e193c960802afba73b5d38sm
216cfd74d65d832137e20e193c960802afba73b5d38sm                Grid.endDrawing(gl);
217cfd74d65d832137e20e193c960802afba73b5d38sm
218cfd74d65d832137e20e193c960802afba73b5d38sm            }
219cfd74d65d832137e20e193c960802afba73b5d38sm        }
220cfd74d65d832137e20e193c960802afba73b5d38sm    }
221cfd74d65d832137e20e193c960802afba73b5d38sm
222cfd74d65d832137e20e193c960802afba73b5d38sm}
223