/** * eAdventure (formerly <e-Adventure> and <e-Game>) is a research project of the * <e-UCM> research group. * * Copyright 2005-2010 <e-UCM> research group. * * You can access a list of all the contributors to eAdventure at: * http://e-adventure.e-ucm.es/contributors * * <e-UCM> is a research group of the Department of Software Engineering * and Artificial Intelligence at the Complutense University of Madrid * (School of Computer Science). * * C Profesor Jose Garcia Santesmases sn, * 28040 Madrid (Madrid), Spain. * * For more info please visit: <http://e-adventure.e-ucm.es> or * <http://www.e-ucm.es> * * **************************************************************************** * * This file is part of eAdventure, version 2.0 * * eAdventure is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * eAdventure is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with eAdventure. If not, see <http://www.gnu.org/licenses/>. */ package ead.importer.subimporters.chapter.scene; import com.google.inject.Inject; import ead.importer.EAdElementImporter; import ead.importer.annotation.ImportAnnotator; import ead.importer.interfaces.EAdElementFactory; import ead.importer.interfaces.ResourceImporter; import es.eucm.ead.model.assets.drawable.basics.Image; import es.eucm.ead.model.assets.multimedia.EAdSound; import es.eucm.ead.model.assets.multimedia.Sound; import es.eucm.ead.model.elements.conditions.ANDCond; import es.eucm.ead.model.elements.conditions.EmptyCond; import es.eucm.ead.model.elements.conditions.NOTCond; import es.eucm.ead.model.elements.effects.TriggerMacroEf; import es.eucm.ead.model.elements.effects.variables.ChangeFieldEf; import es.eucm.ead.model.elements.events.SceneElementEv; import es.eucm.ead.model.elements.events.enums.SceneElementEvType; import es.eucm.ead.model.elements.extra.EAdList; import es.eucm.ead.model.elements.predef.effects.MakeActiveElementEf; import es.eucm.ead.model.elements.predef.effects.MoveActiveElementToMouseEf; import es.eucm.ead.model.elements.predef.events.ScrollWithSceneElementEv; import es.eucm.ead.model.elements.scenes.*; import es.eucm.ead.model.elements.trajectories.NodeTrajectory; import es.eucm.ead.model.elements.trajectories.SimpleTrajectory; import es.eucm.ead.model.params.guievents.MouseGEv; import es.eucm.ead.model.params.text.EAdString; import es.eucm.ead.model.params.util.Position; import es.eucm.ead.model.params.util.Position.Corner; import es.eucm.ead.tools.StringHandler; import es.eucm.eadventure.common.data.chapter.Chapter; import es.eucm.eadventure.common.data.chapter.ElementReference; import es.eucm.eadventure.common.data.chapter.Exit; import es.eucm.eadventure.common.data.chapter.Trajectory; import es.eucm.eadventure.common.data.chapter.conditions.Conditions; import es.eucm.eadventure.common.data.chapter.elements.ActiveArea; import es.eucm.eadventure.common.data.chapter.elements.Barrier; import es.eucm.eadventure.common.data.chapter.elements.Player; import es.eucm.eadventure.common.data.chapter.resources.Resources; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Scenes importer * */ public class SceneImporter implements EAdElementImporter<es.eucm.eadventure.common.data.chapter.scenes.Scene, Scene> { static private Logger logger = LoggerFactory.getLogger(SceneImporter.class); /** * String handler */ private StringHandler stringHandler; /** * References importer */ private EAdElementImporter<ElementReference, SceneElement> referencesImporter; /** * Resources importer */ private ResourceImporter resourceImporter; /** * Exits importer */ private EAdElementImporter<Exit, SceneElement> exitsImporter; /** * Trajectory importer */ private EAdElementImporter<Trajectory, NodeTrajectory> trajectoryImporter; /** * Barrier importer */ private EAdElementImporter<Barrier, SceneElement> barrierImporter; private EAdElementFactory factory; protected ImportAnnotator annotator; private EAdElementImporter<Conditions, Condition> conditionsImporter; @Inject public SceneImporter( StringHandler stringHandler, EAdElementImporter<Conditions, Condition> conditionsImporter, ResourceImporter resourceImporter, EAdElementImporter<ElementReference, SceneElement> referencesImporter, EAdElementFactory factory, EAdElementImporter<Exit, SceneElement> exitsImporter, EAdElementImporter<Trajectory, NodeTrajectory> trajectoryImporter, EAdElementImporter<Barrier, SceneElement> barrierImporter, ImportAnnotator annotator) { this.stringHandler = stringHandler; this.resourceImporter = resourceImporter; this.exitsImporter = exitsImporter; this.referencesImporter = referencesImporter; this.trajectoryImporter = trajectoryImporter; this.barrierImporter = barrierImporter; this.factory = factory; this.annotator = annotator; this.conditionsImporter = conditionsImporter; } @Override public Scene init(es.eucm.eadventure.common.data.chapter.scenes.Scene oldScene) { Scene scene = new Scene(); return scene; } @Override public Scene convert(es.eucm.eadventure.common.data.chapter.scenes.Scene oldScene, Object object) { Chapter chapter = factory.getCurrentChapterModel(); Scene scene = (Scene) object; //chapter.getScenes().add(scene); importDocumentation(scene, oldScene); importResources(scene, oldScene, chapter); importSceneElements(scene, oldScene, chapter); return scene; } private void importSceneElements(Scene scene, es.eucm.eadventure.common.data.chapter.scenes.Scene oldScene, Chapter chapter) { int substract = importActiveAreas(1, scene, oldScene.getActiveAreas()); importExits(substract, scene, oldScene.getExits()); importReferences(scene, oldScene.getItemReferences(), chapter); importReferences(scene, oldScene.getAtrezzoReferences(), chapter); importReferences(scene, oldScene.getCharacterReferences(), chapter); SceneElement playerReference = addPlayer(scene, oldScene, chapter); importTrajectory(scene, oldScene.getTrajectory(), oldScene .getBarriers(), playerReference); } private SceneElement addPlayer(Scene scene, es.eucm.eadventure.common.data.chapter.scenes.Scene oldScene, Chapter chapter) { if (factory.isFirstPerson()) { return null; } else { SceneElementDef player = (SceneElementDef) factory .getElementById(Player.IDENTIFIER); SceneElement playerReference = new SceneElement(player); Position p = new Position(Position.Corner.BOTTOM_CENTER, oldScene .getPositionX(), oldScene.getPositionY()); playerReference.setPosition(p); playerReference.setScale(oldScene.getPlayerScale()); // Make it active element of the scene MakeActiveElementEf effect = new MakeActiveElementEf( playerReference); SceneElementEv event = new SceneElementEv(); event.addEffect(SceneElementEvType.INIT, effect); playerReference.addEvent(event); int playerZ = oldScene.isAllowPlayerLayer() ? Math.max(0, oldScene .getPlayerLayer()) : 1; playerReference.setVarInitialValue(SceneElement.VAR_Z, playerZ); scene.getSceneElements().add(playerReference); scene.getBackground().addBehavior(MouseGEv.MOUSE_LEFT_PRESSED, new MoveActiveElementToMouseEf()); // Add move camera with character Dimension d = resourceImporter.getDimensionsForOldImage(oldScene .getResources().get(0).getAssetPath( es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_BACKGROUND)); scene.setBounds(d.width, 600); ScrollWithSceneElementEv scroll = new ScrollWithSceneElementEv( scene, playerReference); scene.addEvent(scroll); return playerReference; } } private void importTrajectory(Scene scene, Trajectory trajectory, List<Barrier> barriers, SceneElement playerReference) { if (trajectory == null) { scene.setTrajectoryDefinition(new SimpleTrajectory(true)); } else { NodeTrajectory nodeDef = trajectoryImporter.init(trajectory); nodeDef = trajectoryImporter.convert(trajectory, nodeDef); scene.setTrajectoryDefinition(nodeDef); for (Barrier b : barriers) { SceneElement barrier = barrierImporter.init(b); barrier = barrierImporter.convert(b, barrier); nodeDef.addBarrier(barrier); scene.getSceneElements().add(barrier); } playerReference.setPosition(new Position(Corner.BOTTOM_CENTER, nodeDef.getInitial().getX(), nodeDef.getInitial().getY())); playerReference.setScale(nodeDef.getInitial().getScale()); } } private int importActiveAreas(int substract, Scene scene, List<ActiveArea> list) { int i = 0; for (ActiveArea a : list) { SceneElement activeArea = (SceneElement) factory.getElementById(a .getId()); activeArea.setPosition(new Position(Position.Corner.TOP_LEFT, a .getX(), a.getY())); activeArea.setVarInitialValue(SceneElement.VAR_Z, Integer.MAX_VALUE - substract - i); i++; if (activeArea != null) scene.getSceneElements().add(activeArea); } return substract - i; } private int importExits(int substract, Scene scene, List<Exit> list) { int i = 0; for (Exit e : list) { SceneElement se = exitsImporter.init(e); se.setVarInitialValue(SceneElement.VAR_Z, Integer.MAX_VALUE - substract - i); se = exitsImporter.convert(e, se); i++; if (se != null) { scene.getSceneElements().add(se); } } return substract - i; } private void importReferences(Scene scene, List<ElementReference> references, Chapter chapter) { for (ElementReference oldRef : references) { SceneElement newRef = referencesImporter.init(oldRef); newRef = referencesImporter.convert(oldRef, newRef); newRef.setVarInitialValue(SceneElement.VAR_Z, oldRef.getLayer()); scene.getSceneElements().add(newRef); } } private void importResources(Scene scene, es.eucm.eadventure.common.data.chapter.scenes.Scene oldScene, Chapter chapter) { Map<String, String> resourcesStrings = new LinkedHashMap<String, String>(); resourcesStrings.put(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_BACKGROUND, SceneElementDef.appearance); Map<String, Object> resourcesClasses = new LinkedHashMap<String, Object>(); resourcesClasses.put(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_BACKGROUND, Image.class); resourceImporter.importResources(scene.getBackground().getDefinition(), oldScene.getResources(), resourcesStrings, resourcesClasses); // Music variables List<String> musics = new ArrayList<String>(); List<Condition> conditions = new ArrayList<Condition>(); Condition lastCondition = null; boolean end = false; for (Resources r : oldScene.getResources()) { Condition c = conditionsImporter.init(r.getConditions()); c = conditionsImporter.convert(r.getConditions(), c); // This condition is to detect if the resources blocks has an empty // condition. If so, subsequent resources blocks are unreachable if (c.equals(EmptyCond.TRUE)) { end = true; } if (lastCondition != null) { c = new ANDCond(new NOTCond(lastCondition), c); lastCondition = c; } conditions.add(c); String foregroundPath = r .getAssetPath(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_FOREGROUND); if (foregroundPath != null) { Image image = (Image) resourceImporter.getAssetDescritptor( foregroundPath, Image.class); String path = image.getUri(); if (path.endsWith(".jpg") || path.endsWith(".JPG")) { image = new Image(path.substring(0, path.length() - 3) + "png"); } String backgroundPath = r .getAssetPath(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_BACKGROUND); applyForegroundMask(image.getUri(), foregroundPath, backgroundPath); SceneElement foreground = new SceneElement(image); foreground.setVarInitialValue(SceneElement.VAR_Z, Integer.MAX_VALUE); foreground.setEnable(false); ChangeFieldEf changeVisibility = new ChangeFieldEf(foreground .getField(SceneElement.VAR_VISIBLE), c); SceneElementEv event = new SceneElementEv( SceneElementEvType.ALWAYS, changeVisibility); foreground.addEvent(event); scene.getSceneElements().add(foreground); } musics.add(r.getAssetPath(es.eucm.eadventure.common.data.chapter.scenes.Scene.RESOURCE_TYPE_MUSIC)); if (end) { break; } } importSceneMusic(musics, resourceImporter, scene, conditions); } public static void importSceneMusic(List<String> musicPaths, ResourceImporter resourceImporter, Scene scene, List<Condition> conditions) { TriggerMacroEf triggerMacro = new TriggerMacroEf(); int i = 0; for (String musicPath : musicPaths) { Condition condition = conditions.get(i); EAdSound sound = null; if (musicPath != null) { sound = (EAdSound) resourceImporter.getAssetDescritptor( musicPath, Sound.class); } //PlayMusicEf playMusic = new PlayMusicEf(null, true, 1.0f); triggerMacro.putEffects(condition, new EAdList<Effect>()); i++; } SceneElementEv event = new SceneElementEv(); event.addEffect(SceneElementEvType.ADDED, triggerMacro); scene.addEvent(event); } private void applyForegroundMask(String finalPath, String foregroundPath, String backgroundPath) { BufferedImage foreground = resourceImporter.getOldImage(foregroundPath); BufferedImage background = resourceImporter.getOldImage(backgroundPath); int width = foreground.getWidth(); int height = foreground.getHeight(); int[] backgroundPixels = background.getRGB(0, 0, width, height, null, 0, width); int[] maskPixels = foreground.getRGB(0, 0, width, height, null, 0, width); int[] resultPixels = new int[maskPixels.length]; for (int i = 0; i < backgroundPixels.length; i++) { int color = backgroundPixels[i]; int mask = maskPixels[i]; if (mask != 0xffffffff) { resultPixels[i] = color; } else { resultPixels[i] = 0x00000000; } } BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); result.getRaster().setDataElements(0, 0, width, height, resultPixels); String newUri = resourceImporter.getString(foregroundPath); try { ImageIO.write(result, "png", new File(resourceImporter .getNewProjecFolder(), newUri.substring(1))); } catch (IOException e) { logger.error("Error creating foreground image {}", e); } foreground.flush(); background.flush(); result.flush(); } private void importDocumentation(Scene scene, es.eucm.eadventure.common.data.chapter.scenes.Scene oldScene) { EAdString doc = stringHandler.generateNewString(); stringHandler.setString(doc, oldScene.getDocumentation()); scene.getDefinition().setDoc(doc); EAdString name = stringHandler.generateNewString(); stringHandler.setString(name, oldScene.getName()); scene.getDefinition().setName(name); } }