package org.open2jam.render; import java.awt.Rectangle; import java.io.IOException; import java.net.URL; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import org.open2jam.parsers.Event; import org.open2jam.render.entities.*; import org.open2jam.util.Logger; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; public class SkinParser extends DefaultHandler { private enum Keyword { Resources, skin, spriteset, styles, style, sprite, frame, layer, entity } private ArrayDeque<Keyword> call_stack; private ArrayDeque<Map<String,String>> atts_stack; private ArrayList<Sprite> frame_buffer; private HashMap<String, SpriteList> sprite_buffer; private ArrayList<String> style_list; private HashMap<String, ArrayList<String>> styles_map; private HashMap<String, Skin> result; private int layer = -1; private String skin_name; private double baseW = 800; private double baseH = 600; private final double targetW; private final double targetH; public SkinParser(double width, double height) { this.targetW = width; this.targetH = height; call_stack = new ArrayDeque<Keyword>(); atts_stack = new ArrayDeque<Map<String,String>>(); frame_buffer = new ArrayList<Sprite>(); sprite_buffer = new HashMap<String, SpriteList>(); style_list = new ArrayList<String>(); styles_map = new HashMap<String, ArrayList<String>>(); result = new HashMap<String, Skin>(); } @Override public void startElement(String uri, String localName, String qName, Attributes atts) { HashMap<String,String> atts_map = new HashMap<String,String>(atts.getLength()); for(int i=0;i<atts.getLength();i++) atts_map.put(atts.getQName(i), atts.getValue(i)); Keyword k = getKeyword(qName); call_stack.push(k); atts_stack.push(atts_map); switch(k) { case skin:{ this.skin_name = atts_map.get("name"); result.put(skin_name, new Skin()); if(atts_map.containsKey("width"))this.baseW = Double.parseDouble(atts_map.get("width")); if(atts_map.containsKey("height"))this.baseH = Double.parseDouble(atts_map.get("height")); result.get(skin_name).judgment_line = Integer.parseInt(atts_map.get("judgment_line")); result.get(skin_name).screen_scale_x = (float) (this.targetW/this.baseW); result.get(skin_name).screen_scale_y = (float) (this.targetH/this.baseH); ResourceFactory.get().getGameWindow().initScales(this.baseW, this.baseH); }break; case layer:{ this.layer++; result.get(skin_name).max_layer = this.layer; }break; case style:{ style_list.add(atts_map.get("id")); }break; case styles:{ ArrayList<String> al = new ArrayList<String>(); al.addAll(style_list); styles_map.put(atts_map.get("id"), al); style_list.clear(); }break; } } @Override public void endElement(String uri,String localName,String qName) { Keyword k = call_stack.pop(); Map<String,String> atts = atts_stack.pop(); switch(k) { case frame:{ int x = Integer.parseInt(atts.get("x")); int y = Integer.parseInt(atts.get("y")); int w = Integer.parseInt(atts.get("w")); int h = Integer.parseInt(atts.get("h")); float sx = 1, sy = 1; if(atts.containsKey("scale_x"))sx = Float.parseFloat(atts.get("scale_x")); if(atts.containsKey("scale_y"))sy = Float.parseFloat(atts.get("scale_y")); if(atts.containsKey("scale"))sy = sx = Float.parseFloat(atts.get("scale")); Rectangle slice = new Rectangle(x,y,w,h); String FILE_PATH_PREFIX = "/resources/"; URL url = SkinParser.class.getResource(FILE_PATH_PREFIX +atts.get("file")); if(url == null)throw new RuntimeException("Cannot find resource: "+ FILE_PATH_PREFIX +atts.get("file")); Sprite s; try { s = ResourceFactory.get().getSprite(url, slice); } catch(IOException e) { Logger.global.log(Level.WARNING, "Sprite resource load error !! {0}", e); break; } s.setScale(sx, sy); frame_buffer.add(s); }break; case sprite:{ double framespeed = 0; if(atts.containsKey("framespeed"))framespeed = Double.parseDouble(atts.get("framespeed")); framespeed /= 1000; // spritelist need framespeed in milliseconds String id; if(atts.containsKey("id"))id = atts.get("id"); else { Logger.global.log(Level.SEVERE,"bad resource file ! sprite must have an ID ! ATTS: {0}",atts); break; } SpriteList sl = new SpriteList(framespeed); sl.addAll(frame_buffer); // TODO: change to blendmode for theme customizability. Boolean alpha = false; if(atts.containsKey("alpha")) alpha = Boolean.parseBoolean(atts.get("alpha")); for (Sprite s : sl) s.setBlendAlpha(alpha); sprite_buffer.put(id, sl); frame_buffer.clear(); }break; case entity:{ Entity e; String id = null; if(atts.containsKey("id"))id = atts.get("id"); String sprites[]; if(atts.containsKey("sprite"))sprites = atts.get("sprite").split(","); else { Logger.global.log(Level.SEVERE, "bad resource file ! entity [{0}] must have an sprite !", id); break; } if(sprites[0].trim().equals("")){ Logger.global.log(Level.SEVERE, "bad resource file ! entity [{0}] must have an sprite !", id); break; } if(id != null && (e = promoteEntity(id, atts)) != null){ // ok } else if(atts.get("sprite").split(",").length > 1){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new Entity(sprite_buffer.get(s),0,0)); } e = new CompositeEntity(list); } else{ String sprite = atts.get("sprite").trim(); SpriteList sl = sprite_buffer.get(sprite); if(sl.size() > 1){ e = new AnimatedEntity(sl, 0, 0); } else e = new Entity(sl, 0, 0); } e.setLayer(this.layer); double x = e.getX(), y = e.getY(); if(atts.containsKey("x"))x = Integer.parseInt(atts.get("x")); if(atts.containsKey("y"))y = Integer.parseInt(atts.get("y")); e.setPos(x, y); if(id != null){ if(!result.get(skin_name).getEntityMap().containsKey(id))result.get(skin_name).getEntityMap().put(id, e); else{ Entity prime = result.get(skin_name).getEntityMap().get(id); if(prime instanceof CompositeEntity){ ((CompositeEntity)prime).getEntityList().add(e); }else{ CompositeEntity ce = new CompositeEntity(prime, e); result.get(skin_name).getEntityMap().put(id, ce); } } } else result.get(skin_name).getEntityList().add(e); }break; } } private Entity promoteEntity(String id, Map<String,String> atts) { Entity e = null; if(id.startsWith("NOTE_")){ SpriteList sprite = null, head = null, body = null, tail = null; sprite = sprite_buffer.get(atts.get("sprite")); if(atts.containsKey("head")) head = sprite_buffer.get(atts.get("head")); else head = sprite; if(atts.containsKey("body")) body = sprite_buffer.get(atts.get("body")); else body = sprite; if(atts.containsKey("tail")) tail = sprite_buffer.get(atts.get("tail")); else tail = sprite; int x = 0; if(atts.containsKey("x"))x = Integer.parseInt(atts.get("x")); e = new LongNoteEntity(head, body, tail, sprite, Event.Channel.valueOf(id), x, 0); e.setLayer(layer); result.get(skin_name).getEntityMap().put("LONG_"+id, e); e = new NoteEntity(sprite, Event.Channel.valueOf(id), x, 0); } else if(id.equals("MEASURE_MARK")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); e = new MeasureEntity(s, 0, 0); } else if(id.equals("JUDGMENT_LINE")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); e = new AnimatedEntity(s, 0, 0); } else if(id.startsWith("EFFECT_JUDGMENT_")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); e = new JudgmentEntity(s,0, 0); } else if(id.equals("EFFECT_LONGFLARE")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); e = new AnimatedEntity(s,0,0); } else if(id.equals("EFFECT_CLICK")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); e = new AnimatedEntity(s,0, 0, false); } else if(id.startsWith("PRESSED_NOTE_")){ SpriteList sl = sprite_buffer.get(atts.get("sprite")); e = new AnimatedEntity(sl, 0, 0); } else if(id.equals("FPS_COUNTER")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("COUNTER_JUDGMENT_PERFECT")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("COUNTER_JUDGMENT_COOL")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("COUNTER_JUDGMENT_GOOD")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("COUNTER_JUDGMENT_BAD")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("COUNTER_JUDGMENT_MISS")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("MAXCOMBO_COUNTER")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("SCORE_COUNTER")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("JAM_COUNTER")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } Entity title = null; if(atts.containsKey("title")) title = new AnimatedEntity(sprite_buffer.get(atts.get("title")),0,0); e = new ComboCounterEntity(list, title, 0, 0); } else if(id.equals("COMBO_COUNTER")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } Entity title = null; if(atts.containsKey("title")) title = new AnimatedEntity(sprite_buffer.get(atts.get("title")),0,0); e = new ComboCounterEntity(list, title, 0, 0); } else if(id.equals("MINUTE_COUNTER")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.equals("SECOND_COUNTER")){ ArrayList<Entity> list = new ArrayList<Entity>(); for(String s : atts.get("sprite").split(",")){ s = s.trim(); list.add( new AnimatedEntity(sprite_buffer.get(s),0,0)); } e = new NumberEntity(list, 0, 0); } else if(id.startsWith("PILL_")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); e = new AnimatedEntity(s, 0, 0); } else if(id.equals("LIFE_BAR")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); if(atts.containsKey("fill_direction")) e = new BarEntity(s, 0, 0, getFill(atts.get("fill_direction"))); else e = new BarEntity(s, 0, 0); } else if(id.equals("JAM_BAR")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); if(atts.containsKey("fill_direction")) e = new BarEntity(s, 0, 0, getFill(atts.get("fill_direction"))); else e = new BarEntity(s, 0, 0); } else if(id.equals("TIME_BAR")){ SpriteList s = sprite_buffer.get(atts.get("sprite")); if(atts.containsKey("fill_direction")) e = new BarEntity(s, 0, 0, getFill(atts.get("fill_direction"))); else e = new BarEntity(s, 0, 0); } else if(id.equals("BGA")){ Sprite s = sprite_buffer.get(atts.get("sprite")).get(0); int x = 0, y = 0; if(atts.containsKey("x"))x = Integer.parseInt(atts.get("x")); if(atts.containsKey("y"))y = Integer.parseInt(atts.get("y")); e = new BgaEntity(s, x, y); }else{ Logger.global.log(Level.WARNING, "unpromoted entity [{0}]", id); } return e; } public Skin getResult(String skin) { if(result.containsKey(skin)) return result.get(skin); else return null; } private BarEntity.FillDirection getFill(String fill) { BarEntity.FillDirection direction = BarEntity.FillDirection.LEFT_TO_RIGHT; fill = fill.toLowerCase().trim(); if (fill.equals("left_to_right")) direction = BarEntity.FillDirection.LEFT_TO_RIGHT; else if (fill.equals("right_to_left")) direction = BarEntity.FillDirection.RIGHT_TO_LEFT; else if (fill.equals("up_to_down")) direction = BarEntity.FillDirection.UP_TO_DOWN; else if (fill.equals("down_to_up")) direction = BarEntity.FillDirection.DOWN_TO_UP; else Logger.global.log(Level.WARNING, "The fill_direction [{0}] is unknown !", fill); return direction; } private Keyword getKeyword(String s) { try{ return Keyword.valueOf(s); }catch(IllegalArgumentException e){ Logger.global.log(Level.WARNING, "Unknown keyword [{0}] in resources.xml.", s); } return null; } public HashMap<String, ArrayList<String>> getStyles() { return styles_map; } }