1/*
2 * Copyright (C) 2010 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.replica.replicaisland;
18
19import java.io.IOException;
20import java.io.InputStream;
21import android.content.res.AssetManager;
22
23/**
24 * TiledWorld manages a 2D map of tile indexes that define a "world" of tiles.  These may be
25 * foreground or background layers in a scrolling game, or a layer of collision tiles, or some other
26 * type of tile map entirely.  The TiledWorld maps xy positions to tile indices and also handles
27 * deserialization of tilemap files.
28 */
29public class TiledWorld extends AllocationGuard {
30    private int[][] mTilesArray;
31    private int mRowCount;
32    private int mColCount;
33    private byte[] mWorkspaceBytes;
34
35    public TiledWorld(int cols, int rows) {
36        super();
37        mTilesArray = new int[cols][rows];
38        mRowCount = rows;
39        mColCount = cols;
40
41        for (int x = 0; x < cols; x++) {
42            for (int y = 0; y < rows; y++) {
43                mTilesArray[x][y] = -1;
44            }
45        }
46
47        mWorkspaceBytes = new byte[4];
48
49        calculateSkips();
50    }
51
52    public TiledWorld(InputStream stream) {
53        super();
54        mWorkspaceBytes = new byte[4];
55        parseInput(stream);
56        calculateSkips();
57    }
58
59    public int getTile(int x, int y) {
60        int result = -1;
61        if (x >= 0 && x < mColCount && y >= 0 && y < mRowCount) {
62            result = mTilesArray[x][y];
63        }
64        return result;
65    }
66
67    // Builds a tiled world from a simple map file input source.  The map file format is as follows:
68    // First byte: signature.  Must always be decimal 42.
69    // Second byte: width of the world in tiles.
70    // Third byte: height of the world in tiles.
71    // Subsequent bytes: actual tile data in column-major order.
72    // TODO: add a checksum in here somewhere.
73    protected boolean parseInput(InputStream stream) {
74        boolean success = false;
75        AssetManager.AssetInputStream byteStream = (AssetManager.AssetInputStream) stream;
76        int signature;
77        try {
78            signature = (byte)byteStream.read();
79            if (signature == 42) {
80                byteStream.read(mWorkspaceBytes, 0, 4);
81                final int width = Utils.byteArrayToInt(mWorkspaceBytes);
82                byteStream.read(mWorkspaceBytes, 0, 4);
83                final int height = Utils.byteArrayToInt(mWorkspaceBytes);
84
85                final int totalTiles = width * height;
86                final int bytesRemaining = byteStream.available();
87                assert bytesRemaining >= totalTiles;
88                if (bytesRemaining >= totalTiles) {
89                    mTilesArray = new int[width][height];
90                    mRowCount = height;
91                    mColCount = width;
92                    for (int y = 0; y < height; y++) {
93                        for (int x = 0; x < width; x++) {
94                            mTilesArray[x][y] = (byte)byteStream.read();
95                        }
96                    }
97                    success = true;
98                }
99            }
100
101        } catch (IOException e) {
102            //TODO: figure out the best way to deal with this.  Assert?
103        }
104
105        return success;
106    }
107
108    protected void calculateSkips() {
109        int emptyTileCount = 0;
110        for (int y = mRowCount - 1; y >= 0; y--) {
111            for (int x = mColCount - 1; x >= 0; x--) {
112                if (mTilesArray[x][y] < 0) {
113                    emptyTileCount++;
114                    mTilesArray[x][y] = -emptyTileCount;
115                } else {
116                    emptyTileCount = 0;
117                }
118            }
119        }
120    }
121
122    public final int getWidth() {
123        return mColCount;
124    }
125
126    public final int getHeight() {
127        return mRowCount;
128    }
129
130    public final int[][] getTiles() {
131        return mTilesArray;
132    }
133
134}
135