package com.kreative.paint.material;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import javax.imageio.ImageIO;
import com.kreative.paint.material.sprite.ArrayOrdering;
import com.kreative.paint.material.sprite.ColorTransform;
import com.kreative.paint.material.sprite.SPNXParser;
import com.kreative.paint.material.sprite.SpriteIntent;
import com.kreative.paint.material.sprite.SpriteSheet;
import com.kreative.paint.material.sprite.SpriteSheetReader;
import com.kreative.paint.material.sprite.SpriteSheetSlice;
import com.kreative.paint.material.sprite.SpriteTreeNode;
public class SpriteLoader {
private final MaterialLoader loader;
private final MaterialList<SpriteSheet> brushes;
private final MaterialList<SpriteSheet> calligraphyBrushes;
private final MaterialList<SpriteSheet> charcoalBrushes;
private final MaterialList<SpriteSheet> sprinkles;
private final MaterialList<SpriteSheet> rubberStamps;
public SpriteLoader(MaterialLoader loader) {
this.loader = loader;
this.brushes = new MaterialList<SpriteSheet>();
this.calligraphyBrushes = new MaterialList<SpriteSheet>();
this.charcoalBrushes = new MaterialList<SpriteSheet>();
this.sprinkles = new MaterialList<SpriteSheet>();
this.rubberStamps = new MaterialList<SpriteSheet>();
}
public MaterialList<SpriteSheet> getBrushes() {
if (isEmpty()) loadResources();
if (brushes.isEmpty()) createBrushes();
return brushes;
}
public MaterialList<SpriteSheet> getCalligraphyBrushes() {
if (isEmpty()) loadResources();
if (calligraphyBrushes.isEmpty()) createCalligraphyBrushes();
return calligraphyBrushes;
}
public MaterialList<SpriteSheet> getCharcoalBrushes() {
if (isEmpty()) loadResources();
if (charcoalBrushes.isEmpty()) createCharcoalBrushes();
return charcoalBrushes;
}
public MaterialList<SpriteSheet> getSprinkles() {
if (isEmpty()) loadResources();
if (sprinkles.isEmpty()) createSprinkles();
return sprinkles;
}
public MaterialList<SpriteSheet> getRubberStamps() {
if (isEmpty()) loadResources();
if (rubberStamps.isEmpty()) createRubberStamps();
return rubberStamps;
}
private boolean isEmpty() {
return brushes.isEmpty()
&& calligraphyBrushes.isEmpty()
&& charcoalBrushes.isEmpty()
&& sprinkles.isEmpty()
&& rubberStamps.isEmpty();
}
private void loadResources() {
for (MaterialResource r : loader.listResources()) {
if (r.isFormat("png", false)) {
MaterialList<SpriteSheet> dc = getDefaultCategory(r);
if (dc == null) continue;
SpriteSheetReader.Options o = getDefaultOptions(dc);
try {
InputStream in = r.getInputStream();
BufferedImage image = ImageIO.read(in);
in.close();
in = r.getInputStream();
SpriteSheet ss = SpriteSheetReader.readSpriteSheet(r.getResourceName(), in, image, o);
in.close();
MaterialList<SpriteSheet> category = getCategory(ss, dc);
String name = (ss.name != null) ? ss.name : r.getResourceName();
category.add(name, ss);
} catch (IOException e) {
System.err.println("Warning: Ignoring invalid image: " + r.getResourceName());
e.printStackTrace();
}
} else if (r.isFormat("spnd", true)) {
MaterialList<SpriteSheet> dc = getDefaultCategory(r);
SpriteSheetReader.Options o = getDefaultOptions(dc);
Map<String,MaterialResource> pngs = new TreeMap<String,MaterialResource>();
Map<String,MaterialResource> spnxs = new TreeMap<String,MaterialResource>();
for (MaterialResource child : r.listChildren()) {
String name = child.getResourceName().replaceFirst("\\.[a-zA-Z0-9]+$", "").trim();
if (child.isFormat("png", false)) pngs.put(name, child);
if (child.isFormat("spnx", false)) spnxs.put(name, child);
}
for (Map.Entry<String,MaterialResource> e : pngs.entrySet()) {
MaterialResource png = e.getValue();
MaterialResource spnx = spnxs.get(e.getKey());
try {
InputStream in = png.getInputStream();
BufferedImage image = ImageIO.read(in);
in.close();
SpriteSheet ss;
if (spnx == null) {
ss = SpriteSheetReader.createSpriteSheet(e.getKey(), image, o);
} else {
in = spnx.getInputStream();
ss = SPNXParser.parse(e.getKey(), in, image);
in.close();
}
MaterialList<SpriteSheet> category = getCategory(ss, dc);
if (category == null) continue;
String name = (ss.name != null) ? ss.name : e.getKey();
category.add(name, ss);
} catch (IOException ex) {
System.err.println("Warning: Ignoring invalid sprite sheet: " + e.getKey());
ex.printStackTrace();
}
}
}
}
}
private MaterialList<SpriteSheet> getDefaultCategory(MaterialResource r) {
String branchName = r.getBranchName().toLowerCase();
if (branchName.contains("stamps")) return rubberStamps;
if (branchName.contains("sprinkles")) return sprinkles;
if (branchName.contains("charcoal")) return charcoalBrushes;
if (branchName.contains("calligraphy")) return calligraphyBrushes;
if (branchName.contains("brushes")) return brushes;
return null;
}
private SpriteSheetReader.Options getDefaultOptions(MaterialList<SpriteSheet> dc) {
SpriteSheetReader.Options o = new SpriteSheetReader.Options();
if (dc == brushes) o.setDefaultPresentation(12, -1, ArrayOrdering.LTR_TTB);
if (dc == calligraphyBrushes) o.setDefaultStructureSingleParent(false);
if (dc == charcoalBrushes) o.setDefaultStructureSingleParent(true);
if (dc == sprinkles) o.setDefaultStructureSingleParent(false);
if (dc != rubberStamps) o.setDefaultColorTransform(ColorTransform.ALL);
return o;
}
private MaterialList<SpriteSheet> getCategory(SpriteSheet ss, MaterialList<SpriteSheet> dc) {
switch (ss.intent) {
case SpriteIntent.STATIC_BRUSH: return brushes;
case SpriteIntent.ACCELERATED_BRUSH: return calligraphyBrushes;
case SpriteIntent.SPRAYED_BRUSH: return charcoalBrushes;
case SpriteIntent.STAMPED_BRUSH: return sprinkles;
case SpriteIntent.RUBBER_STAMPS: return rubberStamps;
case SpriteIntent.ANIMATED_STAMPS: return rubberStamps;
default: return dc;
}
}
private void createBrushes() {
System.err.println("Notice: No brushes found. Generating generic brushes.");
BufferedImage bi = new BufferedImage(128, 16, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setColor(Color.black);
for (
int rx = 0, sx = 64, x = 6, w = 4;
rx < 64 && sx < 128 && x >= 0 && w <= 16;
rx += 16, sx += 16, x -= 2, w += 4
) {
g.fillOval(rx + x, x, w, w);
g.fillRect(sx + x, x, w, w);
}
g.dispose();
SpriteSheet ss = new SpriteSheet(bi, "Simple", 0, 2, 4, ArrayOrdering.TTB_LTR);
ss.slices.add(new SpriteSheetSlice(0, 0, 16, 16, 8, 8, 16, 16, 8, 1, ArrayOrdering.LTR_TTB, ColorTransform.ALL));
ss.root.children.add(new SpriteTreeNode.Leaf("", 0, 0, 8));
brushes.add("Simple", ss);
}
private void createCalligraphyBrushes() {
System.err.println("Notice: No calligraphy brushes found. Generating generic calligraphy brushes.");
BufferedImage bi = new BufferedImage(256, 32, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setColor(Color.black);
for (int x = 8, d = 16; x < 256 && d > 0; x += 16, d--) {
g.fillOval(x - d / 2, 8 - d / 2, d, d);
g.fillRect(x - d / 2, 24 - d / 2, d, d);
}
g.dispose();
SpriteSheet ss = new SpriteSheet(bi, "Simple", 0, 2, 1, ArrayOrdering.LTR_TTB);
ss.slices.add(new SpriteSheetSlice(0, 0, 16, 16, 8, 8, 16, 16, 16, 2, ArrayOrdering.LTR_TTB, ColorTransform.ALL));
SpriteTreeNode.Branch stb;
stb = new SpriteTreeNode.Branch("Round", 0, 0);
stb.children.add(new SpriteTreeNode.Leaf("", 0, 0, 16));
ss.root.children.add(stb);
stb = new SpriteTreeNode.Branch("Square", 16, 0);
stb.children.add(new SpriteTreeNode.Leaf("", 16, 0, 16));
ss.root.children.add(stb);
calligraphyBrushes.add("Simple", ss);
}
private void createCharcoalBrushes() {
System.err.println("Notice: No charcoal brushes found. Generating generic charcoal brushes.");
BufferedImage bi = new BufferedImage(128, 16, BufferedImage.TYPE_INT_ARGB);
int[] rgb = new int[256];
Random r = new Random();
for (int i = 0, x = 0; i < 8 && x < 128; i++, x += 16) {
for (int j = 0; j < 256; j++) {
rgb[j] = r.nextBoolean() ? 0xFF000000 : 0;
}
bi.setRGB(x, 0, 16, 16, rgb, 0, 16);
}
SpriteSheet ss = new SpriteSheet(bi, "Simple", 0, 1, 1, ArrayOrdering.LTR_TTB);
ss.slices.add(new SpriteSheetSlice(0, 0, 16, 16, 8, 8, 16, 16, 8, 1, ArrayOrdering.LTR_TTB, ColorTransform.ALL));
SpriteTreeNode.Branch stb = new SpriteTreeNode.Branch("Square", 0, 0);
stb.children.add(new SpriteTreeNode.Leaf("", 0, 0, 8));
ss.root.children.add(stb);
charcoalBrushes.add("Simple", ss);
}
private void createSprinkles() {
System.err.println("Notice: No sprinkles found. Generating generic sprinkles.");
int k = 0xFF000000;
int[] rgb = new int[] {
0,0,0,0,0,k,k,k,k,k,k,0,0,0,0,0,
0,0,0,k,k,k,0,0,0,0,k,k,k,0,0,0,
0,0,k,k,0,0,0,0,0,0,0,0,k,k,0,0,
0,k,k,0,0,0,0,0,0,0,0,0,0,k,k,0,
0,k,0,0,0,k,0,0,0,0,k,0,0,0,k,0,
k,k,0,0,0,k,0,0,0,0,k,0,0,0,k,k,
k,0,0,0,0,0,0,0,0,0,0,0,0,0,0,k,
k,0,0,k,0,0,0,0,0,0,0,0,k,0,0,k,
k,0,k,k,0,0,0,0,0,0,0,0,k,k,0,k,
k,0,0,0,k,k,0,0,0,0,k,k,0,0,0,k,
k,k,0,0,k,0,k,k,k,k,0,k,0,0,k,k,
0,k,0,0,0,k,0,0,0,0,k,0,0,0,k,0,
0,k,k,0,0,0,k,k,k,k,0,0,0,k,k,0,
0,0,k,k,0,0,0,0,0,0,0,0,k,k,0,0,
0,0,0,k,k,k,0,0,0,0,k,k,k,0,0,0,
0,0,0,0,0,k,k,k,k,k,k,0,0,0,0,0
};
BufferedImage bi = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
bi.setRGB(0, 0, 16, 16, rgb, 0, 16);
SpriteSheet ss = new SpriteSheet(bi, "Smiley", 0, 1, 1, ArrayOrdering.LTR_TTB);
ss.slices.add(new SpriteSheetSlice(0, 0, 16, 16, 8, 8, 16, 16, 1, 1, ArrayOrdering.LTR_TTB, ColorTransform.ALL));
SpriteTreeNode.Branch stb = new SpriteTreeNode.Branch("Smiley", 0, 0);
stb.children.add(new SpriteTreeNode.Leaf("", 0, 0, 1));
ss.root.children.add(stb);
sprinkles.add("Smiley", ss);
}
private void createRubberStamps() {
System.err.println("Notice: No rubber stamps found. Generating generic rubber stamps.");
BufferedImage bi = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bi.createGraphics();
g.setColor(Color.black);
g.fillOval(0, 0, 32, 32);
g.setColor(Color.yellow);
g.fillOval(1, 1, 30, 30);
Shape s = g.getClip();
g.setClip(new Rectangle(0, 16, 32, 32));
g.setColor(Color.black);
g.fillOval(8, 8, 16, 16);
g.setColor(Color.yellow);
g.fillOval(9, 9, 14, 14);
g.setClip(s);
g.setColor(Color.black);
g.fillRect(10, 10, 2, 2);
g.fillRect(20, 10, 2, 2);
g.dispose();
SpriteSheet ss = new SpriteSheet(bi, "Smiley", 0, 1, 1, ArrayOrdering.LTR_TTB);
ss.slices.add(new SpriteSheetSlice(0, 0, 32, 32, 16, 16, 32, 32, 1, 1, ArrayOrdering.LTR_TTB, ColorTransform.NONE));
ss.root.children.add(new SpriteTreeNode.Leaf("", 0, 0, 1));
rubberStamps.add("Smiley", ss);
}
}