1 package com.tapina.robe.swi.os;
2
3 import com.tapina.robe.runtime.ByteArrayUtils;
4 import com.tapina.robe.runtime.DataBlock;
5 import com.tapina.robe.swi.SWIError;
6
7 import java.io.File;
8 import java.io.FileInputStream;
9 import java.io.IOException;
10 import java.util.HashMap;
11 import java.util.LinkedList;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.logging.Logger;
15
16 /***
17 * Created by IntelliJ IDEA.
18 * User: gareth
19 * Date: Sep 8, 2003
20 * Time: 9:18:36 AM
21 */
22 public final class SpriteArea extends DataBlock {
23 private static final int SIZE_OFFSET = 0;
24 private static final int SPRITE_COUNT_OFFSET = 4;
25 private static final int SPRITE_OFFSET = 8;
26 private static final int FREE_SPACE_OFFSET = 12;
27
28 private final Logger log = Logger.getLogger(getClass().getName());
29 private final List spriteList = new LinkedList();
30 private final Map spriteMap = new HashMap(30);
31 private byte[] data;
32 int size;
33
34 public SpriteArea(int address) {
35 super(address);
36 size = 16;
37 data = new byte[16];
38 ByteArrayUtils.putInt(data, SPRITE_OFFSET, 16);
39 ByteArrayUtils.putInt(data, FREE_SPACE_OFFSET, 16);
40 }
41
42 public SpriteArea(DataBlock dataBlock) {
43 super(dataBlock.getAddress());
44
45 log.warning("Creating SpriteArea from existing DataBlock, existing data will be ignored");
46 size = dataBlock.getSize();
47 data = new byte[size];
48 System.arraycopy(dataBlock.getBytes(), 0, data, 0, size);
49 }
50
51 public byte[] getBytes() {
52 return data;
53 }
54
55 public final void addSprite(Sprite sprite) {
56 spriteList.add(sprite);
57 spriteMap.put(sprite.getName().toLowerCase(), sprite);
58 ByteArrayUtils.putInt(data, SPRITE_COUNT_OFFSET, spriteList.size());
59 final int freeSpace = ByteArrayUtils.getInt(data, FREE_SPACE_OFFSET);
60 if (this.data.length < freeSpace + sprite.data.length) {
61 log.warning("Extending sprite area automatically, this doesn't normally happen");
62 setSize(size + sprite.data.length);
63 }
64 System.arraycopy(sprite.data, 0, this.data, freeSpace, sprite.data.length);
65 ByteArrayUtils.putInt(data, FREE_SPACE_OFFSET, freeSpace + sprite.data.length);
66 }
67
68 public final int getSize() {
69 return size;
70 }
71
72 public void setSize(int newSize) {
73 byte[] newBytes = new byte[newSize];
74 System.arraycopy(data, 0, newBytes, 0, newSize < size ? newSize : size);
75 this.size = newSize;
76 this.data = newBytes;
77 ByteArrayUtils.putInt(data, SIZE_OFFSET, size);
78 }
79
80 public final Sprite getSprite(String name) {
81 return (Sprite) spriteMap.get(name.toLowerCase());
82 }
83
84 public final void merge(File spriteFile) {
85 if (!spriteList.isEmpty()) {
86 log.warning("Merge of sprite files into sprite areas not supported - replacing");
87 }
88 load(spriteFile);
89 }
90
91 public final void load(File spriteFile) {
92 final int size = (int) spriteFile.length();
93 byte[] data = new byte[16];
94 ByteArrayUtils.putInt(data, 0, size);
95 FileInputStream in = null;
96 try {
97 in = new FileInputStream(spriteFile);
98 in.read(data, 4, 12);
99 int offset = ByteArrayUtils.getInt(data, SPRITE_OFFSET) - 16;
100 in.skip(offset);
101 for (int spriteCount = ByteArrayUtils.getInt(data, 4); spriteCount > 0; spriteCount--) {
102 in.read(data, 0, 4);
103 final int spriteSize = ByteArrayUtils.getInt(data, 0);
104 final byte[] spriteData = new byte[spriteSize];
105 in.read(spriteData, 4, spriteSize - 4);
106 addSprite(new Sprite(spriteData));
107 }
108 } catch (IOException e) {
109 throw new SWIError(0, e);
110 } finally {
111 if (in != null) {
112 try {
113 in.close();
114 } catch (IOException e) {
115 throw new SWIError(0, e);
116 }
117 }
118 }
119 }
120
121 }