/** * 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 es.eucm.ead.importer; import com.google.inject.Inject; import com.google.inject.Singleton; import es.eucm.ead.importer.resources.ResourcesConverter; import es.eucm.ead.importer.subconverters.conditions.ConditionsConverter; import es.eucm.ead.model.assets.drawable.EAdDrawable; import es.eucm.ead.model.assets.drawable.compounds.StateDrawable; import es.eucm.ead.model.assets.drawable.filters.FilteredDrawable; import es.eucm.ead.model.assets.drawable.filters.MatrixFilter; import es.eucm.ead.model.elements.BasicElement; import es.eucm.ead.model.elements.conditions.Condition; import es.eucm.ead.model.elements.conditions.EmptyCond; import es.eucm.ead.model.elements.effects.TriggerMacroEf; import es.eucm.ead.model.elements.effects.variables.ChangeFieldEf; import es.eucm.ead.model.elements.events.WatchFieldEv; import es.eucm.ead.model.elements.huds.MouseHud; import es.eucm.ead.model.elements.operations.ElementField; import es.eucm.ead.model.elements.operations.ValueOp; import es.eucm.ead.model.elements.predef.effects.ChangeAppearanceEf; import es.eucm.ead.model.elements.scenes.SceneElement; import es.eucm.ead.model.interfaces.features.Evented; import es.eucm.ead.model.interfaces.features.WithBehavior; import es.eucm.ead.model.params.fills.ColorFill; import es.eucm.ead.model.params.fills.Paint; import es.eucm.ead.model.params.guievents.MouseGEv; import es.eucm.ead.model.params.paint.EAdPaint; import es.eucm.ead.model.params.util.Matrix; import es.eucm.eadventure.common.data.chapter.conditions.Conditions; 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.List; @Singleton public class UtilsConverter { static private Logger logger = LoggerFactory .getLogger(UtilsConverter.class); private ConditionsConverter conditionsConverter; private BasicElement cursor; private ResourcesConverter resourcesConverter; @Inject public UtilsConverter(ConditionsConverter conditionsConverter, ModelQuerier modelQuerier, ResourcesConverter resourcesConverter) { this.conditionsConverter = conditionsConverter; this.resourcesConverter = resourcesConverter; modelQuerier.setUtilsConverter(this); cursor = new BasicElement(MouseHud.CURSOR_ID); } /** * Add conditions for the resources changes * * @param resources the list of resources * @param e the element affected * @param stateVar the variable controlling the state for the element */ public void addResourcesConditions(List<Resources> resources, BasicElement e, String stateVar) { if (resources.size() > 1) { WatchFieldEv watchField = new WatchFieldEv(); ElementField stateField = new ElementField(e, stateVar); // An effect that changes the state attending to the conditions TriggerMacroEf triggerMacro = new TriggerMacroEf(); int i = 0; for (Resources r : resources) { Condition cond = conditionsConverter.convert(r.getConditions()); for (ElementField f : conditionsConverter .getFieldsLastCondition()) { watchField.watchField(f); } ChangeFieldEf changeState = new ChangeFieldEf(stateField, new ValueOp(this.getResourceBundleId(i))); triggerMacro.putEffect(cond, changeState); i++; } watchField.addEffect(triggerMacro); ((Evented) e).addEvent(watchField); } } public String getResourceBundleId(int index) { return "bundle" + index; } /** * Watches the var in the definition * * @param sceneElement * @param varState */ public void addWatchDefinitionField(SceneElement sceneElement, String varState) { WatchFieldEv watchField = new WatchFieldEv(); watchField.watchField(new ElementField(sceneElement.getDefinition(), varState)); watchField.addEffect(new ChangeFieldEf(new ElementField(sceneElement, varState), new ElementField(sceneElement.getDefinition(), varState))); watchField.setId(sceneElement.getId() + "$watchbundle"); sceneElement.addEvent(watchField); } /** * Simplifies a state drawables to its minimum * * @param drawable * @return */ public EAdDrawable simplifyStateDrawable(StateDrawable drawable) { if (drawable.getDrawables().isEmpty()) { return null; } else if (drawable.getDrawablesCollection().size() == 1) { return drawable.getDrawable(drawable.getStates().iterator().next()); } return drawable; } /** * Add a event to watch a condition, and set the field to the value of the * condition * * @param field * @param c */ public void addWatchCondition(SceneElement sceneElement, ElementField field, Conditions c) { Condition cond = conditionsConverter.convert(c); // If condition is true, the scene element is always visible, so no need // for watch event if (!cond.equals(EmptyCond.TRUE)) { WatchFieldEv watchField = new WatchFieldEv(); for (ElementField f : conditionsConverter.getFieldsLastCondition()) { watchField.watchField(f); } watchField.addEffect(new ChangeFieldEf(field, cond)); sceneElement.addEvent(watchField); } } /** * Add mouse enter and mouse exit behavior to change the cursor when is over * the given element * * @param e the element * @param bundleId cursor bundle id */ public void addCursorChange(WithBehavior e, String bundleId) { e.addBehavior(MouseGEv.MOUSE_ENTERED, new ChangeAppearanceEf(cursor, MouseHud.EXIT_CURSOR)); e.addBehavior(MouseGEv.MOUSE_EXITED, new ChangeAppearanceEf(cursor, MouseHud.DEFAULT_CURSOR)); } /** * Returns a string transforming the given old color * * @param oldColor * @return */ public String getColor(String oldColor) { if (oldColor != null) { String color = oldColor; if (oldColor.startsWith("#")) { color = color.substring(1); } while (color.length() < 6) { color = "0" + color; } return "0x" + color + "FF"; } else { return "0x00000000"; } } /** * Get the proper paint for two colors in the old format * * @param fillColor * @param borderColor * @return */ public EAdPaint getPaint(String fillColor, String borderColor) { return new Paint(new ColorFill(getColor(fillColor)), new ColorFill( getColor(borderColor))); } public EAdDrawable getBackground(String path) { return getBackground(path, false); } public EAdDrawable getBackground(String path, boolean adjust) { EAdDrawable drawable = resourcesConverter.getImage(path); Dimension d = resourcesConverter.getSize(path); // If dimension is greater than 600, we have to scale if (d.getHeight() > 600) { Matrix m = new Matrix(); float scaleY = 600.0f / (float) d.getHeight(); float scaleX = adjust ? 800.0f / (float) d.getWidth() : scaleY; float diff = 800.0f - scaleX * 800.0f; if (diff > 0) { m.translate(diff / 2.0f, 0.0f, true); } m.scale(scaleX, scaleY, true); MatrixFilter filter = new MatrixFilter(m, 0.0f, 0.0f); drawable = new FilteredDrawable(drawable, filter); } return drawable; } /** * Takes the mask from a scene, and creates the resulting image of applying it to a background image. * It writes the image in the foreground mask destination path * * @param foregroundPath * @param backgroundPath * @return the new path for the foreground */ public String applyForegroundMask(String foregroundPath, String backgroundPath) { BufferedImage foreground = resourcesConverter.loadImage(foregroundPath); BufferedImage background = resourcesConverter.loadImage(backgroundPath); String newUri = resourcesConverter.getPath(foregroundPath); if (!newUri.endsWith(".png")) { newUri += ".png"; } if (foreground != null && background != null) { 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); try { ImageIO.write(result, "png", new File(resourcesConverter .getProjectFolder(), newUri.substring(1))); } catch (IOException e) { logger.error("Error creating foreground image {}", foregroundPath, e); } foreground.flush(); background.flush(); result.flush(); } return newUri; } }