PageRenderTime 79ms CodeModel.GetById 61ms app.highlight 15ms RepoModel.GetById 0ms app.codeStats 0ms

/newcode/src/com/prupe/mcpatcher/mal/tile/TileLoader.java

https://bitbucket.org/prupe/mcpatcher
Java | 334 lines | 296 code | 36 blank | 2 comment | 63 complexity | ba78a5fc71f6c79440b54b2eae7999d2 MD5 | raw file
  1package com.prupe.mcpatcher.mal.tile;
  2
  3import com.prupe.mcpatcher.Config;
  4import com.prupe.mcpatcher.MCLogger;
  5import com.prupe.mcpatcher.MCPatcherUtils;
  6import com.prupe.mcpatcher.mal.resource.BlendMethod;
  7import com.prupe.mcpatcher.mal.resource.TexturePackAPI;
  8import com.prupe.mcpatcher.mal.resource.TexturePackChangeHandler;
  9import net.minecraft.src.*;
 10
 11import java.awt.*;
 12import java.awt.image.BufferedImage;
 13import java.io.File;
 14import java.util.*;
 15import java.util.List;
 16
 17public class TileLoader {
 18    private static final MCLogger logger = MCLogger.getLogger("Tilesheet");
 19
 20    private static final List<TileLoader> loaders = new ArrayList<TileLoader>();
 21
 22    private static final boolean debugTextures = Config.getBoolean(MCPatcherUtils.CONNECTED_TEXTURES, "debugTextures", false);
 23    private static final Map<String, String> specialTextures = new HashMap<String, String>();
 24
 25    private static final TexturePackChangeHandler changeHandler;
 26    private static boolean changeHandlerCalled;
 27    private static boolean useFullPath;
 28
 29    private static final long MAX_TILESHEET_SIZE;
 30
 31    protected final String mapName;
 32    protected final MCLogger subLogger;
 33
 34    private TextureAtlas baseTextureMap;
 35    private final Map<String, TextureAtlasSprite> baseTexturesByName = new HashMap<String, TextureAtlasSprite>();
 36    private final Set<ResourceLocation> tilesToRegister = new HashSet<ResourceLocation>();
 37    private final Map<ResourceLocation, BufferedImage> tileImages = new HashMap<ResourceLocation, BufferedImage>();
 38    private final Map<String, Icon> iconMap = new HashMap<String, Icon>();
 39
 40    static {
 41        long maxSize = 4096L;
 42        try {
 43            maxSize = Minecraft.getMaxTextureSize();
 44        } catch (NoSuchMethodError e) {
 45        } catch (Throwable e) {
 46            e.printStackTrace();
 47        }
 48        MAX_TILESHEET_SIZE = (maxSize * maxSize * 4) * 7 / 8;
 49        logger.config("max texture size is %dx%d (%.1fMB)", maxSize, maxSize, MAX_TILESHEET_SIZE / 1048576.0f);
 50
 51        changeHandler = new TexturePackChangeHandler("Tilesheet API", 2) {
 52            @Override
 53            public void initialize() {
 54            }
 55
 56            @Override
 57            public void beforeChange() {
 58                changeHandlerCalled = true;
 59                loaders.clear();
 60                specialTextures.clear();
 61                try {
 62                    FaceInfo.clear();
 63                } catch (NoClassDefFoundError e) {
 64                    // nothing
 65                } catch (Throwable e) {
 66                    e.printStackTrace();
 67                }
 68            }
 69
 70            @Override
 71            public void afterChange() {
 72                for (TileLoader loader : loaders) {
 73                    if (!loader.tilesToRegister.isEmpty()) {
 74                        loader.subLogger.warning("could not load all %s tiles (%d remaining)", loader.mapName, loader.tilesToRegister.size());
 75                        loader.tilesToRegister.clear();
 76                    }
 77                }
 78                changeHandlerCalled = false;
 79            }
 80
 81            @Override
 82            public void afterChange2() {
 83                for (TileLoader loader : loaders) {
 84                    loader.finish();
 85                }
 86            }
 87        };
 88        TexturePackChangeHandler.register(changeHandler);
 89    }
 90
 91    public static void registerIcons(TextureAtlas textureMap, String mapName, Map<String, TextureAtlasSprite> map) {
 92        mapName = mapName.replaceFirst("/$", "");
 93        logger.fine("before registerIcons(%s) %d icons", mapName, map.size());
 94        if (!changeHandlerCalled) {
 95            logger.severe("beforeChange was not called, invoking directly");
 96            changeHandler.beforeChange();
 97        }
 98        for (TileLoader loader : loaders) {
 99            if (loader.isForThisMap(mapName)) {
100                if (loader.baseTextureMap == null) {
101                    loader.baseTextureMap = textureMap;
102                    loader.baseTexturesByName.putAll(map);
103                }
104                if (!loader.tilesToRegister.isEmpty()) {
105                    loader.subLogger.fine("adding icons to %s (%d remaining)", mapName, loader.tilesToRegister.size(), mapName);
106                    while (!loader.tilesToRegister.isEmpty() && loader.registerOneIcon(textureMap, mapName, map)) {
107                        // nothing
108                    }
109                    loader.subLogger.fine("done adding icons to %s (%d remaining)", mapName, loader.tilesToRegister.size(), mapName);
110                }
111            }
112        }
113        logger.fine("after registerIcons(%s) %d icons", mapName, map.size());
114    }
115
116    public static String getOverridePath(String prefix, String basePath, String name, String ext) {
117        String path;
118        if (name.endsWith(".png")) {
119            path = name.replaceFirst("^/", "").replaceFirst("\\.[^.]+$", "") + ext;
120            useFullPath = true;
121        } else {
122            path = basePath;
123            if (!basePath.endsWith("/")) {
124                path += "/";
125            }
126            path += name;
127            path += ext;
128            useFullPath = false;
129        }
130        path = prefix + path;
131        logger.finer("getOverridePath(%s, %s, %s, %s) -> %s", prefix, basePath, name, ext, path);
132        return path;
133    }
134
135    public static String getOverrideBasename(Object o, String path) {
136        if (useFullPath) {
137            useFullPath = false;
138            return "/" + path;
139        } else {
140            File file = new File(path);
141            return file.getName().substring(0, file.getName().lastIndexOf('.'));
142        }
143    }
144
145    public static boolean isSpecialTexture(TextureAtlas map, String texture, String special) {
146        return special.equals(texture) || special.equals(specialTextures.get(texture));
147    }
148
149    public static BufferedImage generateDebugTexture(String text, int width, int height, boolean alternate) {
150        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
151        Graphics graphics = image.getGraphics();
152        graphics.setColor(alternate ? new Color(0, 255, 255, 128) : Color.WHITE);
153        graphics.fillRect(0, 0, width, height);
154        graphics.setColor(alternate ? Color.RED : Color.BLACK);
155        int ypos = 10;
156        if (alternate) {
157            ypos += height / 2;
158        }
159        int charsPerRow = width / 8;
160        if (charsPerRow <= 0) {
161            return image;
162        }
163        while (text.length() % charsPerRow != 0) {
164            text += " ";
165        }
166        while (ypos < height && !text.equals("")) {
167            graphics.drawString(text.substring(0, charsPerRow), 1, ypos);
168            ypos += graphics.getFont().getSize();
169            text = text.substring(charsPerRow);
170        }
171        return image;
172    }
173
174    static void init() {
175    }
176
177    public static ResourceLocation getBlocksAtlas() {
178        return TextureAtlas.blocksAtlas;
179    }
180
181    public static ResourceLocation getItemsAtlas() {
182        return TextureAtlas.itemsAtlas;
183    }
184
185    public TileLoader(String mapName, MCLogger logger) {
186        this.mapName = mapName;
187        subLogger = logger;
188        loaders.add(this);
189    }
190
191    private static long getTextureSize(TextureAtlasSprite texture) {
192        return texture == null ? 0 : 4 * IconAPI.getIconWidth(texture) * IconAPI.getIconHeight(texture);
193    }
194
195    private static long getTextureSize(Collection<TextureAtlasSprite> textures) {
196        long size = 0;
197        for (TextureAtlasSprite texture : textures) {
198            size += getTextureSize(texture);
199        }
200        return size;
201    }
202
203    public static ResourceLocation getDefaultAddress(ResourceLocation propertiesAddress) {
204        return TexturePackAPI.transformResourceLocation(propertiesAddress, ".properties", ".png");
205    }
206
207    public static ResourceLocation parseTileAddress(ResourceLocation propertiesAddress, String value) {
208        return parseTileAddress(propertiesAddress, value, BlendMethod.ALPHA.getBlankResource());
209    }
210
211    public static ResourceLocation parseTileAddress(ResourceLocation propertiesAddress, String value, ResourceLocation blankResource) {
212        if (value == null) {
213            return null;
214        }
215        if (value.equals("blank")) {
216            return blankResource;
217        }
218        if (value.equals("null") || value.equals("none") || value.equals("default") || value.equals("")) {
219            return null;
220        }
221        if (!value.endsWith(".png")) {
222            value += ".png";
223        }
224        return TexturePackAPI.parseResourceLocation(propertiesAddress, value);
225    }
226
227    public boolean preloadTile(ResourceLocation resource, boolean alternate, String special) {
228        if (tileImages.containsKey(resource)) {
229            return true;
230        }
231        BufferedImage image = null;
232        if (!debugTextures) {
233            image = TexturePackAPI.getImage(resource);
234            if (image == null) {
235                subLogger.warning("missing %s", resource);
236            }
237        }
238        if (image == null) {
239            image = generateDebugTexture(resource.getPath(), 64, 64, alternate);
240        }
241        tilesToRegister.add(resource);
242        tileImages.put(resource, image);
243        if (special != null) {
244            specialTextures.put(resource.toString(), special);
245        }
246        return true;
247    }
248
249    public boolean preloadTile(ResourceLocation resource, boolean alternate) {
250        return preloadTile(resource, alternate, null);
251    }
252
253    protected boolean isForThisMap(String mapName) {
254        return mapName.equals("textures") || mapName.startsWith(this.mapName);
255    }
256
257    private boolean registerDefaultIcon(String name) {
258        if (name.startsWith(mapName) && name.endsWith(".png") && baseTextureMap != null) {
259            String defaultName = name.substring(mapName.length()).replaceFirst("\\.png$", "");
260            TextureAtlasSprite texture = baseTexturesByName.get(defaultName);
261            if (texture != null) {
262                subLogger.finer("%s -> existing icon %s", name, defaultName);
263                iconMap.put(name, texture);
264                return true;
265            }
266        }
267        return false;
268    }
269
270    private boolean registerOneIcon(TextureAtlas textureMap, String mapName, Map<String, TextureAtlasSprite> map) {
271        ResourceLocation resource = tilesToRegister.iterator().next();
272        String name = resource.toString();
273        if (registerDefaultIcon(name)) {
274            tilesToRegister.remove(resource);
275            return true;
276        }
277        BufferedImage image = tileImages.get(resource);
278        if (image == null) {
279            subLogger.error("tile for %s unexpectedly missing", resource);
280            tilesToRegister.remove(resource);
281            return true;
282        }
283        int width = image.getWidth();
284        int height = image.getHeight();
285        long currentSize = getTextureSize(map.values());
286        long newSize = 4 * width * width;
287        if (newSize + currentSize > MAX_TILESHEET_SIZE) {
288            float sizeMB = (float) currentSize / 1048576.0f;
289            if (currentSize <= 0) {
290                subLogger.error("%s too big for any tilesheet (%.1fMB), dropping", name, sizeMB);
291                tilesToRegister.remove(resource);
292                return true;
293            } else {
294                subLogger.warning("%s nearly full (%.1fMB), will start a new tilesheet", mapName, sizeMB);
295                return false;
296            }
297        }
298        Icon icon;
299        if (mapName.equals("textures")) { // 1.8
300            icon = map.get(name);
301            if (icon == null) {
302                icon = TextureAtlasSprite.createSprite(resource);
303            }
304        } else {
305            icon = textureMap.registerIcon(name);
306        }
307        map.put(name, (TextureAtlasSprite) icon);
308        iconMap.put(name, icon);
309        String extra = (width == height ? "" : ", " + (height / width) + " frames");
310        subLogger.finer("%s -> %s icon %dx%d%s", name, mapName, width, width, extra);
311        tilesToRegister.remove(resource);
312        return true;
313    }
314
315    public void finish() {
316        tilesToRegister.clear();
317        tileImages.clear();
318    }
319
320    public Icon getIcon(String name) {
321        if (MCPatcherUtils.isNullOrEmpty(name)) {
322            return null;
323        }
324        Icon icon = iconMap.get(name);
325        if (icon == null) {
326            icon = baseTexturesByName.get(name);
327        }
328        return icon;
329    }
330
331    public Icon getIcon(ResourceLocation resource) {
332        return resource == null ? null : getIcon(resource.toString());
333    }
334}