001package squidpony.squidgrid.gui.gdx;
002
003import com.badlogic.gdx.graphics.Color;
004import com.badlogic.gdx.graphics.g2d.Batch;
005import com.badlogic.gdx.graphics.g2d.BitmapFont;
006import com.badlogic.gdx.graphics.g2d.TextureRegion;
007import com.badlogic.gdx.scenes.scene2d.Group;
008import squidpony.ArrayTools;
009import squidpony.IColorCenter;
010import squidpony.squidgrid.Direction;
011import squidpony.squidmath.OrderedSet;
012import squidpony.squidmath.SeededNoise;
013
014import java.util.ArrayList;
015import java.util.Collection;
016
017import static com.badlogic.gdx.math.MathUtils.clamp;
018
019/**
020 * A helper class to make using multiple SquidPanels easier.
021 * Created by Tommy Ettinger on 7/6/2015.
022 */
023public class SquidLayers extends Group {
024    protected int width;
025    protected int height;
026    protected int cellWidth;
027    protected int cellHeight;
028    public int[][] lightnesses;
029    protected SquidPanel backgroundPanel, foregroundPanel;
030    protected ArrayList<SquidPanel> extraPanels;
031    protected TextCellFactory textFactory;
032    protected float animationDuration;
033
034    public static final char EMPTY_CELL = ' ';
035
036    /**
037     * The pixel width of the entire map as displayed.
038     *
039     * @return the pixel width of the entire map as displayed
040     */
041    @Override
042    public float getWidth() {
043        return width * cellWidth;
044    }
045
046    /**
047     * The pixel height of the entire map as displayed.
048     *
049     * @return the pixel height of the entire map as displayed
050     */
051    @Override
052    public float getHeight() {
053        return height * cellHeight;
054    }
055
056    /**
057     * Width of the shown area of the map in grid cells.
058     *
059     * @return the width of the map in grid cells
060     */
061    public int getGridWidth() {
062        return width;
063    }
064
065    /**
066     * Height of the shown area of the map in grid cells.
067     *
068     * @return the height of the map in grid cells
069     */
070    public int getGridHeight() {
071        return height;
072    }
073
074    /**
075     * Width of one cell in pixels.
076     *
077     * @return the width of one cell in pixels
078     */
079    public int getCellWidth() {
080        return cellWidth;
081    }
082
083    /**
084     * Height of one cell in pixels.
085     *
086     * @return the height of one cell in pixels
087     */
088    public int getCellHeight() {
089        return cellHeight;
090    }
091
092    public float getAnimationDuration() {
093        return animationDuration;
094    }
095
096    public void setAnimationDuration(float animationDuration) {
097        this.animationDuration = animationDuration;
098    }
099
100    public TextCellFactory getTextFactory() {
101        return textFactory;
102    }
103
104    /**
105     * Get the lightness modifiers used for background cells as an int[][], with elements between 0 and 511, 256 as the
106     * unmodified lightness level, lower numbers meaning darker, and higher meaning lighter.
107     *
108     * @return
109     */
110    public int[][] getLightnesses() {
111        return lightnesses;
112    }
113    /**
114     * Alters the lightnesses that affect the background colors, accepting a parameter for
115     * animation frame if rippling water and waving grass using {@link SeededNoise} are desired. It may make sense to
116     * pass some fraction of the current time, as given by {@link System#currentTimeMillis()}, instead of a frame.
117     * Does not allocate a new 2D int array like {@link MapUtility#generateLightnessModifiers(char[][])} or its
118     * equivalent in DungeonUtility, and directly mutates the lightness data. You can use the {@link #lightnesses} field
119     * to access the 2D array directly, where you can make further modifications to the lighting.
120     * @return this for chaining
121     */
122    public SquidLayers autoLight () {
123        return autoLight(1.2345, '~', ',');
124    }
125
126    /**
127     * Alters the lightnesses that affect the background colors, accepting a parameter for
128     * animation frame if rippling water and waving grass using {@link SeededNoise} are desired. It may make sense to
129     * pass some fraction of the current time, as given by {@link System#currentTimeMillis()}, instead of a frame.
130     * Does not allocate a new 2D int array like {@link MapUtility#generateLightnessModifiers(char[][])} or its
131     * equivalent in DungeonUtility, and directly mutates the lightness data. You can use the {@link #lightnesses} field
132     * to access the 2D array directly, where you can make further modifications to the lighting.
133     * @param frame         a counter that typically should increase by between 10.0 and 20.0 each second; higher numbers make
134     *                      water and grass move more, and 0.013 multiplied by the current time in milliseconds works well
135     *                      as long as only the smaller digits of the time are used; this can be accomplished with
136     *                      {@code (System.currentTimeMillis() & 0xFFFFFF) * 0.013} .
137     * @return a 2D array of lightness values from -255 to 255 but usually close to 0; can be passed to SquidLayers
138     */
139    public SquidLayers autoLight (double frame) {
140        return autoLight(frame, '~', ',');
141    }
142    /**
143     * Alters the lightnesses that affect the background colors, accepting a parameter for
144     * animation frame if rippling water and waving grass using {@link SeededNoise} are desired. It may make sense to
145     * pass some fraction of the current time, as given by {@link System#currentTimeMillis()}, instead of a frame.
146     * Also allows additional chars to be treated like deep and shallow water regarding the ripple animation.
147     * Does not allocate a new 2D int array like {@link MapUtility#generateLightnessModifiers(char[][])} or its
148     * equivalent in DungeonUtility, and directly mutates the lightness data. You can use the {@link #lightnesses} field
149     * to access the 2D array directly, where you can make further modifications to the lighting.
150     * @param frame         a counter that typically should increase by between 10.0 and 20.0 each second; higher numbers make
151     *                      water and grass move more, and 0.013 multiplied by the current time in milliseconds works well
152     *                      as long as only the smaller digits of the time are used; this can be accomplished with
153     *                      {@code (System.currentTimeMillis() & 0xFFFFFF) * 0.013} .
154     * @param deepLiquid    a char that will be treated like deep water when animating ripples
155     * @param shallowLiquid a char that will be treated like shallow water when animating ripples
156     * @return a 2D array of lightness values from -255 to 255 but usually close to 0; can be passed to SquidLayers
157     */
158    public SquidLayers autoLight (double frame, char deepLiquid, char shallowLiquid) {
159        final char[][] map = foregroundPanel.contents;
160        final int w = getTotalWidth(), h = getTotalHeight();
161        for (int i = 0; i < w; i++) {
162            for (int j = 0; j < h; j++) {
163                switch (map[i][j]) {
164                    case '\1':
165                    case '├':
166                    case '┤':
167                    case '┴':
168                    case '┬':
169                    case '┌':
170                    case '┐':
171                    case '└':
172                    case '┘':
173                    case '│':
174                    case '─':
175                    case '┼':
176                    case '#':
177                        lightnesses[i][j] = 30;
178                        break;
179                    case '.':
180                    case ' ':
181                    case '\u0006':
182                        lightnesses[i][j] = 0;
183                        break;
184                    case ':':
185                        lightnesses[i][j] = -15;
186                        break;
187                    case '+':
188                    case '/':
189                        lightnesses[i][j] = -10;
190                        break;
191                    case ',':
192                        lightnesses[i][j] = (int) (85 * (SeededNoise.noise(i * 0.16, j * 0.16, frame * 0.05, 1234567) * 0.55 - 0.7));
193                        break;
194                    case '~':
195                        lightnesses[i][j] = (int) (100 * (SeededNoise.noise(i * 0.16, j * 0.16, frame * 0.05, 1234567) * 0.4 - 0.65));
196                        break;
197                    case '"':
198                        lightnesses[i][j] = (int) (95 * (SeededNoise.noise(i * 0.16, j * 0.16, frame * 0.05, 123456789) * 0.3 - 1.5));
199                        break;
200                    case '^':
201                        lightnesses[i][j] = 40;
202                        break;
203                    default:
204                        if (map[i][j] == deepLiquid)
205                            lightnesses[i][j] = (int) (180 * (SeededNoise.noise(i * 0.46, j * 0.46, frame * 0.041, 987654321) * 0.45 - 0.7));
206                        else if (map[i][j] == shallowLiquid)
207                            lightnesses[i][j] = (int) (110 * (SeededNoise.noise(i * 0.56, j * 0.56, frame * 0.061, 987654321) * 0.4 - 0.65));
208                        else lightnesses[i][j] = 0;
209                }
210            }
211        }
212        return this;
213    }
214
215    /**
216     * Sets the lightness modifiers used for background cells with the int[][] passed as lightnesses. This 2D array
217     * should have elements between 0 to 511, with 256 as the unmodified lightness level, lower numbers meaning darker,
218     * and higher meaning lighter. Elements less than 0 or higher than 511 will probably cause array out-of-bounds
219     * exceptions to be thrown when this renders, so just don't do that. This doesn't validate because maps can get
220     * large, validating many cells could be expensive, and this might be called often if it's being called at all.
221     *
222     * @param lightnesses 2D array, width and height should match this class' gridWidth and gridHeight. elements must
223     *                    be between 0 and 511.
224     */
225    public void setLightnesses(int[][] lightnesses) {
226        this.lightnesses = lightnesses;
227    }
228
229    /**
230     * Create a new SquidLayers widget with a default stretchable font, 40 cells wide and 40 cells high,
231     * and 12x12 pixels for each cell.
232     * <br>
233     * This uses a default font that is not supplied in the JAR library of SquidLib; you need two files to use it if it
234     * does not render correctly:
235     * <ul>
236     * <li>https://github.com/SquidPony/SquidLib/blob/master/assets/Inconsolata-LGC-Custom-distance.fnt</li>
237     * <li>https://github.com/SquidPony/SquidLib/blob/master/assets/Inconsolata-LGC-Custom-distance.png</li>
238     * </ul>
239     */
240    public SquidLayers() {
241        this(40, 40);
242    }
243
244    /**
245     * Create a new SquidLayers widget with a default stretchable font, the given number of cells for gridWidth
246     * and gridHeight, and 12x12 pixels for each cell.
247     * <br>
248     * This uses a default font that is not supplied in the JAR library of SquidLib; you need two files to use it if it
249     * does not render correctly:
250     * <ul>
251     * <li>https://github.com/SquidPony/SquidLib/blob/master/assets/Inconsolata-LGC-Custom-distance.fnt</li>
252     * <li>https://github.com/SquidPony/SquidLib/blob/master/assets/Inconsolata-LGC-Custom-distance.png</li>
253     * </ul>
254     *
255     * @param gridWidth  in grid cells
256     * @param gridHeight in grid cells
257     */
258    public SquidLayers(int gridWidth, int gridHeight) {
259        this(gridWidth, gridHeight, 12, 12);
260    }
261
262    /**
263     * Create a new SquidLayers widget with a default stretchable font (it will adapt to the cellWidth and cellHeight
264     * you give it), the given number of cells for gridWidth and gridHeight, and the size in pixels for each cell
265     * given by cellWidth and cellHeight.
266     * <br>
267     * This uses a default font that is not supplied in the JAR library of SquidLib; you need two files to use it if it
268     * does not render correctly:
269     * <ul>
270     * <li>https://github.com/SquidPony/SquidLib/blob/master/assets/Inconsolata-LGC-Custom-distance.fnt</li>
271     * <li>https://github.com/SquidPony/SquidLib/blob/master/assets/Inconsolata-LGC-Custom-distance.png</li>
272     * </ul>
273     *
274     * @param gridWidth  in grid cells
275     * @param gridHeight in grid cells
276     * @param cellWidth  in pixels
277     * @param cellHeight in pixels
278     */
279    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight) {
280        this(gridWidth, gridHeight, cellWidth, cellHeight, DefaultResources.getSCC(), DefaultResources.getSCC());
281    }
282
283    /**
284     * Create a new SquidLayers widget with the given path to a BitmapFont file, the given number of cells for gridWidth
285     * and gridHeight, and the size in pixels for each cell given by cellWidth and cellHeight.
286     *
287     * @param gridWidth  in grid cells
288     * @param gridHeight in grid cells
289     * @param cellWidth  in pixels
290     * @param cellHeight in pixels
291     * @param fontpath   A path to a BitmapFont in the assets folder
292     */
293    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight, String fontpath) {
294        this(gridWidth, gridHeight, cellWidth, cellHeight, fontpath,
295                DefaultResources.getSCC(), DefaultResources.getSCC());
296    }
297
298    /**
299     * Create a new SquidLayers widget with the given path to a BitmapFont file, the given number of cells for gridWidth
300     * and gridHeight, and the size in pixels for each cell given by cellWidth and cellHeight.
301     *
302     * @param gridWidth  in grid cells
303     * @param gridHeight in grid cells
304     * @param cellWidth  in pixels
305     * @param cellHeight in pixels
306     * @param bitmapFont A BitmapFont that you already constructed
307     */
308    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight, BitmapFont bitmapFont) {
309        this(gridWidth, gridHeight, cellWidth, cellHeight, bitmapFont,
310                DefaultResources.getSCC(), DefaultResources.getSCC());
311    }
312
313    /**
314     * Create a new SquidLayers widget with the given path pre-constructed TextCellFactory, the given number of cells
315     * for gridWidth and gridHeight, and the size in pixels for each cell given by cellWidth and cellHeight.
316     * Consider using predefined TextCellFactory objects from {@link DefaultResources}, which will be configured by
317     * this constructor for sizing when passed here.
318     *
319     * @param gridWidth  in grid cells
320     * @param gridHeight in grid cells
321     * @param cellWidth  in pixels
322     * @param cellHeight in pixels
323     * @param tcf        A TextCellFactory that you already constructed
324     */
325    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight, TextCellFactory tcf) {
326        this(gridWidth, gridHeight, cellWidth, cellHeight, tcf,
327                DefaultResources.getSCC(), DefaultResources.getSCC());
328    }
329
330    /**
331     * Create a new SquidLayers widget with a default stretchable font (it will adapt to the cellWidth and cellHeight
332     * you give it), the given number of cells for gridWidth and gridHeight, the size in pixels for each cell
333     * given by cellWidth and cellHeight, and the given SquidColorCenter instances to affect colors.
334     * <br>
335     * This uses a default font that is not supplied in the JAR library of SquidLib; you need two files to use it if it
336     * does not render correctly:
337     * <ul>
338     * <li>https://github.com/SquidPony/SquidLib/blob/master/assets/Inconsolata-LGC-Custom-distance.fnt</li>
339     * <li>https://github.com/SquidPony/SquidLib/blob/master/assets/Inconsolata-LGC-Custom-distance.png</li>
340     * </ul>
341     *
342     * @param gridWidth     in grid cells
343     * @param gridHeight    in grid cells
344     * @param cellWidth     in pixels
345     * @param cellHeight    in pixels
346     * @param bgColorCenter a SquidColorCenter (possibly with a filter) to use for the background
347     * @param fgColorCenter a SquidColorCenter (possibly with a filter) to use for the foreground
348     */
349    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight,
350                       SquidColorCenter bgColorCenter, SquidColorCenter fgColorCenter) {
351        this(gridWidth, gridHeight, cellWidth, cellHeight, DefaultResources.getStretchableFont(),
352                bgColorCenter, fgColorCenter);
353    }
354
355    /**
356     * Create a new SquidLayers widget with the given path to a BitmapFont file, the given number of cells for gridWidth
357     * and gridHeight, and the size in pixels for each cell given by cellWidth and cellHeight.
358     *
359     * @param gridWidth     in grid cells
360     * @param gridHeight    in grid cells
361     * @param cellWidth     in pixels
362     * @param cellHeight    in pixels
363     * @param fontpath      A path to a BitmapFont that can be on the classpath (in SquidLib) or in the assets folder.
364     * @param bgColorCenter a SquidColorCenter (possibly with a filter) to use for the background
365     * @param fgColorCenter a SquidColorCenter (possibly with a filter) to use for the foreground
366     */
367    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight, String fontpath,
368                       SquidColorCenter bgColorCenter, SquidColorCenter fgColorCenter) {
369        this(gridWidth, gridHeight, cellWidth, cellHeight, new TextCellFactory().font(fontpath), bgColorCenter, fgColorCenter);
370    }
371
372    /**
373     * Create a new SquidLayers widget with the given BitmapFont (already constructed), the given number of cells for
374     * gridWidth and gridHeight, and the size in pixels for each cell given by cellWidth and cellHeight.
375     *
376     * @param gridWidth     in grid cells
377     * @param gridHeight    in grid cells
378     * @param cellWidth     in pixels
379     * @param cellHeight    in pixels
380     * @param bitmapFont    A BitmapFont that you already constructed
381     * @param bgColorCenter a SquidColorCenter (possibly with a filter) to use for the background
382     * @param fgColorCenter a SquidColorCenter (possibly with a filter) to use for the foreground
383     */
384    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight, BitmapFont bitmapFont,
385                       SquidColorCenter bgColorCenter, SquidColorCenter fgColorCenter) {
386        this(gridWidth, gridHeight, cellWidth, cellHeight, new TextCellFactory().font(bitmapFont), bgColorCenter, fgColorCenter);
387    }
388
389    /**
390     * Create a new SquidLayers widget with the given TextCellFactory, the given number of cells for gridWidth
391     * and gridHeight, the size in pixels for each cell given by cellWidth and cellHeight, and the given
392     * SquidColorCenters for background and foreground. Consider using predefined TextCellFactory objects from
393     * {@link DefaultResources}, which will be configured by this constructor for sizing when passed here.
394     *
395     * @param gridWidth     in grid cells
396     * @param gridHeight    in grid cells
397     * @param cellWidth     in pixels
398     * @param cellHeight    in pixels
399     * @param tcf           A TextCellFactory that will be (re-)initialized here with the given cellHeight and cellWidth.
400     * @param bgColorCenter a SquidColorCenter (possibly with a filter) to use for the background
401     * @param fgColorCenter a SquidColorCenter (possibly with a filter) to use for the foreground
402     */
403    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight, TextCellFactory tcf,
404                       SquidColorCenter bgColorCenter, SquidColorCenter fgColorCenter) {
405        this(gridWidth, gridHeight, cellWidth, cellHeight, tcf, bgColorCenter, fgColorCenter, null);
406    }
407
408    /**
409     * Create a new SquidLayers widget with the given TextCellFactory, the given number of cells for gridWidth
410     * and gridHeight, the size in pixels for each cell given by cellWidth and cellHeight, the given
411     * SquidColorCenters for background and foreground, and the given 2D char array for an area map that may be
412     * sized differently than gridWidth by gridHeight (it is usually larger than gridWidth by gridHeight, which
413     * allows camera scrolling across the map). This requires some special work with the Camera and Viewports to
414     * get working correctly; in the squidlib module's examples,
415     * <a href="https://github.com/SquidPony/SquidLib/blob/master/squidlib/src/test/java/squidpony/gdx/examples/EverythingDemo.java">EverythingDemo</a>
416     * may be a good place to see how this can be done. You can pass null for actualMap, which will simply create
417     * a char array to use internally that is exactly gridWidth by gridHeight, in cells. Consider using predefined
418     * TextCellFactory objects from {@link DefaultResources}, which will be configured by this constructor for
419     * sizing when passed here.
420     *
421     * @param gridWidth     in grid cells
422     * @param gridHeight    in grid cells
423     * @param cellWidth     in pixels
424     * @param cellHeight    in pixels
425     * @param tcf           A TextCellFactory that will be (re-)initialized here with the given cellHeight and cellWidth.
426     * @param bgColorCenter a SquidColorCenter (possibly with a filter) to use for the background
427     * @param fgColorCenter a SquidColorCenter (possibly with a filter) to use for the foreground
428     * @param actualMap     will often be a different size than gridWidth by gridHeight, which enables camera scrolling
429     */
430    public SquidLayers(int gridWidth, int gridHeight, int cellWidth, int cellHeight, TextCellFactory tcf,
431                       SquidColorCenter bgColorCenter, SquidColorCenter fgColorCenter, char[][] actualMap) {
432        this.setTransform(false);
433
434        width = gridWidth;
435        height = gridHeight;
436
437        this.cellWidth = cellWidth;
438        this.cellHeight = cellHeight;
439        textFactory = tcf.width(cellWidth).height(cellHeight).initBySize();
440
441        if (actualMap == null || actualMap.length <= 0) {
442            backgroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory, bgColorCenter);
443            foregroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory, fgColorCenter);
444            lightnesses = new int[width][height];
445        } else {
446            backgroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory, bgColorCenter, 0, 0, ArrayTools.fill(' ', actualMap.length, actualMap[0].length));
447            foregroundPanel = new SquidPanel(gridWidth, gridHeight, textFactory, fgColorCenter, 0, 0, actualMap);
448            lightnesses = new int[actualMap.length][actualMap[0].length];
449        }
450        animationDuration = foregroundPanel.DEFAULT_ANIMATION_DURATION;
451
452        extraPanels = new ArrayList<>();
453
454        addActorAt(0, backgroundPanel);
455        addActorAt(2, foregroundPanel);
456
457        setSize(backgroundPanel.getWidth(), backgroundPanel.getHeight());
458    }
459
460    /**
461     * Add an extra layer on top of the foreground layer. Use putInto methods to specify the layer when adding a char (0
462     * is background, 1 is unused, 2 is foreground, and the first call to this method creates layer 3).
463     *
464     * @return this for chaining
465     */
466    public SquidLayers addExtraLayer() {
467        SquidPanel sp;
468        if (width != foregroundPanel.getTotalWidth() || height != foregroundPanel.getTotalHeight())
469            sp = new SquidPanel(width, height, textFactory, foregroundPanel.getColorCenter(), 0, 0,
470                    ArrayTools.fill(' ', foregroundPanel.getTotalWidth(), foregroundPanel.getTotalHeight()));
471        else
472            sp = new SquidPanel(width, height, textFactory);
473        addActor(sp);
474        extraPanels.add(sp);
475        return this;
476    }
477
478    /**
479     * Sets the size of the text in the given layer  (but not the size of the cells) to the given width and height in
480     * pixels (which may be stretched by viewports later on, if your program uses them).
481     *
482     * @param layer the layer to affect; 0 is background, 1 is unused, 2 is foreground, 3 and higher are extra panels
483     * @param wide  the width of a glyph in pixels
484     * @param high  the height of a glyph in pixels
485     * @return this for chaining
486     */
487    public SquidLayers setTextSize(int layer, float wide, float high) {
488        SquidPanel p = backgroundPanel;
489        switch (layer) {
490            case 0:
491            case 1:
492                break;
493            case 2:
494                p = foregroundPanel;
495                break;
496            default:
497                p = extraPanels.get(layer - 3);
498        }
499        p.setTextSize(wide, high);
500        return this;
501    }
502
503    /**
504     * Sets the size of the text in all layers (but not the size of the cells) to the given width and height in pixels
505     * (which may be stretched by viewports later on, if your program uses them).
506     *
507     * @param wide the width of a glyph in pixels
508     * @param high the height of a glyph in pixels
509     * @return this for chaining
510     */
511    public SquidLayers setTextSize(float wide, float high) {
512        textFactory.tweakHeight(high).tweakWidth(wide).initBySize();
513        setTextSize(0, wide, high);
514        setTextSize(2, wide, high);
515        for (int i = 0; i < extraPanels.size(); i++) {
516            setTextSize(i + 3, wide, high);
517        }
518        return this;
519    }
520
521
522    /**
523     * Place a char c into the foreground at position x, y, with the default color.
524     *
525     * @param x in grid cells.
526     * @param y in grid cells.
527     * @param c a character to be drawn in the foreground
528     * @return this for chaining
529     */
530    public SquidLayers put(int x, int y, char c) {
531        foregroundPanel.put(x, y, c);
532        return this;
533    }
534
535    /**
536     * Place a char c into the foreground, with a foreground color as a libGDX Color (or SColor).
537     *
538     * @param x          in grid cells.
539     * @param y          in grid cells.
540     * @param c          a character to be drawn in the foreground
541     * @param foreground Color for the char being drawn
542     * @return this for chaining
543     */
544    public SquidLayers put(int x, int y, char c, Color foreground) {
545        foregroundPanel.put(x, y, c, foreground);
546        return this;
547    }
548
549    /**
550     * Place a char c into the foreground, with a foreground color as a packed float.
551     *
552     * @param x                 in grid cells.
553     * @param y                 in grid cells.
554     * @param c                 a character to be drawn in the foreground
555     * @param encodedForeground float encoding the color for the char being drawn
556     * @return this for chaining
557     */
558    public SquidLayers put(int x, int y, char c, float encodedForeground) {
559        foregroundPanel.put(x, y, c, encodedForeground);
560        return this;
561    }
562
563    /**
564     * Place a char c into the foreground, with a specified foreground color and background color.
565     *
566     * @param x          in grid cells.
567     * @param y          in grid cells.
568     * @param c          a character to be drawn in the foreground
569     * @param foreground Color for the char being drawn
570     * @param background Color for the background
571     * @return this for chaining
572     */
573    public SquidLayers put(int x, int y, char c, Color foreground, Color background) {
574        foregroundPanel.put(x, y, c, foreground);
575        backgroundPanel.put(x, y, background);
576        return this;
577    }
578
579    /**
580     * Place a char c into the foreground, with a foreground and background libGDX Color and a lightness variation for
581     * the background (255 will make the background equal the background panel's
582     * {@link SquidPanel#getLightingColor()}, -255 will use the background as-is, and values in between will be
583     * linearly interpolated between those two extremes).
584     *
585     * @param x                   in grid cells.
586     * @param y                   in grid cells.
587     * @param c                   a character to be drawn in the foreground
588     * @param foreground          Color for the char being drawn
589     * @param background          Color for the background
590     * @param backgroundLightness int between -255 and 255 , lower numbers are changed less, higher changed closer to the lighting color
591     * @return this for chaining
592     */
593    public SquidLayers put(int x, int y, char c, Color foreground, Color background, int backgroundLightness) {
594        foregroundPanel.put(x, y, c, foreground);
595        backgroundPanel.put(x, y, background, (clamp(lightnesses[x][y] + 256 + backgroundLightness, 1, 511)) * 0.001953125f);
596        return this;
597    }
598
599    /**
600     * Place a char c into the foreground, with a foreground and background libGDX Color and a lightness variation for
601     * the background (255 will make the background equal the background panel's
602     * {@link SquidPanel#getLightingColor()}, -255 will use the background as-is, and values in between will be
603     * linearly interpolated between those two extremes).
604     *
605     * @param x             in grid cells.
606     * @param y             in grid cells.
607     * @param c             a character to be drawn in the foreground
608     * @param foreground    Color for the char being drawn
609     * @param background    Color for the background
610     * @param mixAmount     int between -255 and 255 , lower numbers are changed less, higher changed closer to mixBackground
611     * @param mixBackground Color to mix with the background, dependent on mixAmount
612     * @return this for chaining
613     */
614    public SquidLayers put(int x, int y, char c, Color foreground, Color background, int mixAmount, Color mixBackground) {
615        foregroundPanel.put(x, y, c, foreground);
616        backgroundPanel.put(x, y, background,
617                (clamp(lightnesses[x][y] + 256 + mixAmount, 1, 511)) * 0.001953125f,
618                mixBackground);
619        return this;
620    }
621
622    /**
623     * Place a char c into the foreground, with a foreground and background color each encoded as a packed float and a
624     * lightness variation for the background (255 will make the background equal the background panel's
625     * {@link SquidPanel#getLightingColor()}, -255 will use encodedBackground as-is, and values in between will be
626     * linearly interpolated between those two extremes).
627     *
628     * @param x                   in grid cells.
629     * @param y                   in grid cells.
630     * @param c                   a character to be drawn in the foreground
631     * @param encodedForeground   float encoding the color for the char being drawn
632     * @param encodedBackground   float encoding the color for the background
633     * @param backgroundLightness int between -255 and 255 , lower numbers are darker, higher lighter.
634     * @return this for chaining
635     */
636    public SquidLayers put(int x, int y, char c, float encodedForeground, float encodedBackground, int backgroundLightness) {
637        foregroundPanel.put(x, y, c, encodedForeground);
638        backgroundPanel.put(x, y, encodedBackground,
639                (clamp(lightnesses[x][y] + 256 + backgroundLightness, 1, 511)) * 0.001953125f);
640        return this;
641    }
642
643    /**
644     * Place a char c into the foreground, with a foreground, background, and mix color (which affects the background)
645     * each encoded as a packed float and a lightness variation for the background (255 will make the background equal
646     * mixColor, -255 will use encodedBackground as-is, and values in between will be linearly interpolated between
647     * those two extremes).
648     *
649     * @param x                   in grid cells.
650     * @param y                   in grid cells.
651     * @param c                   a character to be drawn in the foreground
652     * @param encodedForeground   float encoding the color for the char being drawn
653     * @param encodedBackground   float encoding the color for the background
654     * @param backgroundLightness int between -255 and 255 , lower numbers are darker, higher lighter.
655     * @param mixBackground       float encoding a color to mix with the background instead of the normal lighting color
656     * @return this for chaining
657     */
658    public SquidLayers put(int x, int y, char c, float encodedForeground, float encodedBackground, int backgroundLightness, float mixBackground) {
659        foregroundPanel.put(x, y, c, encodedForeground);
660        backgroundPanel.put(x, y, encodedBackground,
661                (clamp(lightnesses[x][y] + 256 + backgroundLightness, 1, 511)) * 0.001953125f, mixBackground);
662        return this;
663    }
664
665    /**
666     * Place a char c into the foreground, with a foreground, background, and mix color (which affects the background)
667     * each encoded as a packed float and a lightness variation for the background (using the style that SquidPanel
668     * does, with the "lightness" a float between 0.0f and 1.0f inclusive, encodedBackground used on its own for 0
669     * lightness, mixBackground used on its own for 1 lightness, and values in between mixing the two).
670     *
671     * @param x                   in grid cells.
672     * @param y                   in grid cells.
673     * @param c                   a character to be drawn in the foreground
674     * @param encodedForeground   float encoding the color for the char being drawn
675     * @param encodedBackground   float encoding the color for the background
676     * @param backgroundLightness float between 0.0f and 1.0f (both inclusive); higher means closer to mixBackground
677     * @param mixBackground       float encoding a color to mix with the background instead of the normal lighting color
678     * @return this for chaining
679     */
680    public SquidLayers put(int x, int y, char c, float encodedForeground, float encodedBackground, float backgroundLightness, float mixBackground) {
681        foregroundPanel.put(x, y, c, encodedForeground);
682        backgroundPanel.put(x, y, encodedBackground, backgroundLightness, mixBackground);
683        //        lightnesses[x][y] + (int) (backgroundLightness * 255), mixBackground);
684        return this;
685    }
686
687    public SquidLayers put(int x, int y, char[][] c) {
688        foregroundPanel.put(x, y, c);
689        return this;
690    }
691
692    public SquidLayers put(int x, int y, char[][] c, Color[][] foreground, Color[][] background) {
693        foregroundPanel.put(x, y, c, foreground);
694        backgroundPanel.put(x, y, background);
695        return this;
696    }
697
698
699    /**
700     * Place a 2@ char array c into the foreground, with foreground colors specified by a 2D Color array, background
701     * colors with another 2D Color array, and lightness variations for the background in a 2D int array (255 will make
702     * the background equal the background panel's {@link SquidPanel#getLightingColor()}, -255 will use the background
703     * as-is, and values in between will be linearly interpolated between those two extremes).
704     *
705     * @param x                   in grid cells.
706     * @param y                   in grid cells.
707     * @param c                   char[][] to be drawn in the foreground starting from x, y
708     * @param foregrounds         Color[][] of colors for the char being drawn
709     * @param backgrounds         Color[][] of colors for the background
710     * @param backgroundLightness int[][] with elements between -255 and 255 , lower darker, higher lighter.
711     * @return this for chaining
712     */
713    public SquidLayers put(int x, int y, char[][] c, Color[][] foregrounds, Color[][] backgrounds, int[][] backgroundLightness) {
714
715        foregroundPanel.put(x, y, c, foregrounds);
716        for (int i = x; i < getTotalWidth() && i - x < backgroundLightness.length; i++) {
717            for (int j = y; j < getTotalHeight() && j - y < backgroundLightness[i].length; j++) {
718                backgroundPanel.put(i, j, backgrounds[i - x][j - y],
719                        (clamp(lightnesses[i][j] + 256 + backgroundLightness[i - x][j - y], 1, 511)) * 0.001953125f);
720            }
721        }
722        return this;
723    }
724
725
726    /**
727     * Place a char c into the specified layer, using the specified layer's default foreground color.
728     *
729     * @param layer 0 or 1 for background, 2 for foreground, 3 or higher for extra layers added on.
730     * @param x     in grid cells.
731     * @param y     in grid cells.
732     * @param c     char to be drawn in the foreground at x, y
733     * @return this for chaining
734     */
735    public SquidLayers putInto(int layer, int x, int y, char c) {
736        getLayer(layer).put(x, y, c);
737        return this;
738    }
739
740    /**
741     * Place a char c into the specified layer with the specified Color.
742     *
743     * @param layer the layer to draw into
744     * @param x     in grid cells.
745     * @param y     in grid cells.
746     * @param c     a character to be drawn in the specified layer
747     * @param color Color for the char being drawn
748     * @return this for chaining
749     */
750    public SquidLayers putInto(int layer, int x, int y, char c, Color color) {
751        getLayer(layer).put(x, y, c, color);
752        return this;
753    }
754
755    /**
756     * Place a 2D char array c into the specified layer, using the specified layer's default foreground color.
757     *
758     * @param layer 0 or 1 for background, 2 for foreground, 3 or higher for extra layers added on.
759     * @param x     in grid cells.
760     * @param y     in grid cells.
761     * @param c     char[][] to be drawn in the foreground starting from x, y
762     * @return this for chaining
763     */
764    public SquidLayers putInto(int layer, int x, int y, char[][] c) {
765        getLayer(layer).put(x, y, c);
766        return this;
767    }
768
769    /**
770     * Place a 2D char array c into the specified layer, using the matching Color from the given 2D Color array.
771     *
772     * @param layer  0 or 1 for background, 2 for foreground, 3 or higher for extra layers added on.
773     * @param x      in grid cells.
774     * @param y      in grid cells.
775     * @param c      char[][] to be drawn in the foreground starting from x, y
776     * @param colors Color[][] that should have the same width and height as c
777     * @return this for chaining
778     */
779    public SquidLayers putInto(int layer, int x, int y, char[][] c, Color[][] colors) {
780        getLayer(layer).put(x, y, c, colors);
781        return this;
782    }
783
784    /**
785     * Put a string at the given x, y position, using the default foreground color.
786     *
787     * @param x in grid cells.
788     * @param y in grid cells.
789     * @param s the string to print
790     * @return this for chaining
791     */
792    public SquidLayers putString(int x, int y, String s) {
793        foregroundPanel.put(x, y, s);
794        return this;
795    }
796
797    /**
798     * Put a string at the given x, y position, with the given foreground Color.
799     *
800     * @param x               in grid cells.
801     * @param y               in grid cells.
802     * @param s               the string to print
803     * @param foreground      the Color to use
804     * @return this, for chaining
805     */
806    public SquidLayers putString(int x, int y, String s, Color foreground) {
807        foregroundPanel.put(x, y, s, foreground);
808        return this;
809    }
810
811    /**
812     * Put a string at the given x, y position, with the given foreground and background Colors.
813     *
814     * @param x          in grid cells.
815     * @param y          in grid cells.
816     * @param s          the string to print
817     * @param foreground the Color of the string's chars
818     * @param background the Color of the background of the string
819     * @return this, for chaining
820     */
821    public SquidLayers putString(int x, int y, String s, Color foreground, Color background) {
822        foregroundPanel.put(x, y, s, foreground);
823        for (int i = x; i < x + s.length() && i < getTotalWidth(); i++) {
824            backgroundPanel.put(i, y, background);
825        }
826        return this;
827    }
828
829    /**
830     * A utility method that draws a 1-cell-wide black box around the text you request (as s) and replaces the contents
831     * of anything that was below or adjacent to the string's new position. Useful for message boxes.
832     *
833     * @param x in grid cells.
834     * @param y in grid cells.
835     * @param s the string to print inside the box
836     * @return this, for chaining
837     */
838    public SquidLayers putBoxedString(int x, int y, String s) {
839        if (y > 0 && y + 1 < getTotalHeight() && x > 0 && x + 1 < getTotalWidth()) {
840            for (int j = y - 1; j < y + 2 && j < getTotalHeight(); j++) {
841                for (int i = x - 1; i < s.length() + x + 2 && i < getTotalWidth(); i++) {
842                    foregroundPanel.put(i, j, ' ');
843                    lightnesses[i][j] = -200;
844
845                    backgroundPanel.put(i, j, backgroundPanel.getAt(i, j),
846                            SColor.DARK_GRAY, 0f * 0.001953125f);
847                }
848            }
849        }
850        foregroundPanel.put(x, y, s, SColor.CREAM);
851
852        return this;
853    }
854
855    /**
856     * Change the lightness for the background of the cell at x, y (0 is no change, 100 is
857     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
858     *
859     * @param x         in grid cells.
860     * @param y         in grid cells.
861     * @param lightness int between -255 and 255 , lower numbers are darker, higher lighter.
862     */
863    public SquidLayers highlight(int x, int y, int lightness) {
864        backgroundPanel.put(x, y, backgroundPanel.getAt(x, y),
865                backgroundPanel.getColorAt(x, y),
866                (clamp(lightnesses[x][y] + 256 + lightness, 1, 511)) * 0.001953125f);
867        return this;
868    }
869
870    /**
871     * Change the lightness for the background of the cell at x, y (0 is no change, 100 is
872     * very bright, -100 is very dark, anything past -150 or 150 will make the background almost fully black or white).
873     *
874     * @param x         in grid cells.
875     * @param y         in grid cells.
876     * @param lightness int[][] with elements between -255 and 255 , lower numbers are darker, higher lighter.
877     */
878    public SquidLayers highlight(int x, int y, int[][] lightness) {
879        for (int i = 0; i < lightness.length && x + i < getTotalWidth(); i++) {
880            for (int j = 0; j < lightness[i].length && y + j < getTotalHeight(); j++) {
881                backgroundPanel.put(x, y, backgroundPanel.getAt(x, y),
882                        backgroundPanel.getColorAt(x, y), (clamp(lightnesses[x + i][y + j] + 256 + lightness[i][j], 1, 511)) * 0.001953125f);
883            }
884        }
885        return this;
886    }
887
888    /**
889     * Very basic check to see if something was rendered at the x,y cell requested; this only checks the
890     * foreground. If the foreground contains the character {@code ' '} at the given position or has not
891     * been assigned a value at that position, then this returns false, otherwise it returns true.
892     *
893     * @param x in grid cells.
894     * @param y in grid cells.
895     * @return true if something was rendered in the foreground at the given x,y position
896     */
897    public boolean hasValue(int x, int y) {
898        return foregroundPanel.getAt(x, y) != ' ';
899    }
900
901    /**
902     * Clear one cell at position x, y of  its foreground contents.
903     * <p>
904     * You may be looking for the erase() method, which erases all panels and all cells.
905     *
906     * @param x in grid cells
907     * @param y in grid cells
908     * @return this for chaining
909     */
910    public SquidLayers clear(int x, int y) {
911        foregroundPanel.clear(x, y);
912        return this;
913    }
914
915    public SquidLayers eraseLayer(int layer) {
916        getLayer(layer).erase();
917        return this;
918    }
919
920    /**
921     * Erase everything visible in all cells or all layers.  This is not at all expensive to do compared to the
922     * pre-SquidLib-3.0.0 version of this method that used Swing and took a long time to erase.
923     *
924     * @return this, for chaining
925     */
926    public SquidLayers erase() {
927        foregroundPanel.erase();
928        backgroundPanel.erase();
929        for (SquidPanel sp : extraPanels) {
930            sp.erase();
931        }
932        return this;
933    }
934
935    public SquidLayers bump(int x, int y, int layer, Direction dir, float duration) {
936        if (duration < 0)
937            duration = animationDuration;
938        getLayer(layer).bump(x, y, dir, duration);
939        return this;
940    }
941
942    public SquidLayers bump(AnimatedEntity ae, int layer, Direction dir, float duration) {
943        if (duration < 0)
944            duration = animationDuration;
945        getLayer(layer).bump(ae, dir, duration);
946        return this;
947    }
948
949    public SquidLayers bump(int x, int y, Direction dir) {
950        return bump(x, y, 2, dir, -1);
951    }
952
953    public SquidLayers bump(AnimatedEntity ae, Direction dir) {
954        return bump(ae, 2, dir, -1);
955    }
956
957    public SquidLayers slide(AnimatedEntity ae, int endX, int endY, int layer, float duration) {
958        if (duration < 0)
959            duration = animationDuration;
960        getLayer(layer).slide(ae, endX, endY, duration);
961        return this;
962    }
963
964    public SquidLayers slide(int x, int y, int endX, int endY, int layer, float duration) {
965        if (duration < 0)
966            duration = animationDuration;
967        getLayer(layer).slide(x, y, endX, endY, duration);
968        return this;
969    }
970
971    public SquidLayers slide(int x, int y, int endX, int endY) {
972        return slide(x, y, endX, endY, 2, -1);
973    }
974
975    public SquidLayers slide(AnimatedEntity ae, int endX, int endY) {
976        return slide(ae, endX, endY, 2, -1);
977    }
978
979    public SquidLayers wiggle(int x, int y, int layer, float duration) {
980        if (duration < 0)
981            duration = animationDuration;
982        getLayer(layer).wiggle(x, y, duration);
983        return this;
984    }
985
986    public SquidLayers wiggle(AnimatedEntity ae, int layer, float duration) {
987        if (duration < 0)
988            duration = animationDuration;
989        getLayer(layer).wiggle(ae, duration);
990        return this;
991    }
992
993    public SquidLayers wiggle(int x, int y) {
994        return wiggle(x, y, 2, -1);
995    }
996
997    public SquidLayers wiggle(AnimatedEntity ae) {
998        return wiggle(ae, 2, -1);
999    }
1000
1001    public SquidLayers tint(int x, int y, Color color, int layer, float duration) {
1002        if (duration < 0)
1003            duration = animationDuration;
1004        getLayer(layer).tint(x, y, color, duration);
1005        return this;
1006    }
1007
1008    public SquidLayers tint(AnimatedEntity ae, Color color, int layer, float duration) {
1009        if (duration < 0)
1010            duration = animationDuration;
1011        getLayer(layer).tint(ae, color, duration);
1012        return this;
1013    }
1014
1015    public SquidLayers tint(int x, int y, Color color) {
1016        return tint(x, y, color, 2, -1);
1017    }
1018
1019    public SquidLayers tint(AnimatedEntity ae, Color color) {
1020        return tint(ae, color, 2, -1);
1021    }
1022
1023    public boolean hasActiveAnimations() {
1024        if (foregroundPanel.hasActiveAnimations())
1025            return true;
1026        if (backgroundPanel.hasActiveAnimations())
1027            return true;
1028        for (SquidPanel panel : extraPanels) {
1029            if (panel.hasActiveAnimations())
1030                return true;
1031        }
1032        return false;
1033    }
1034
1035    public AnimatedEntity directionMarker(int x, int y, Color color, int layer, boolean doubleWidth) {
1036        return getLayer(layer).directionMarker(x, y, doubleWidth, color);
1037    }
1038
1039    public AnimatedEntity directionMarker(int x, int y, Collection<Color> colors, float loopTime, int layer, boolean doubleWidth) {
1040        return getLayer(layer).directionMarker(x, y, doubleWidth, colors, loopTime);
1041    }
1042
1043    public AnimatedEntity animateActor(int x, int y, char c, Color color, int layer) {
1044        return getLayer(layer).animateActor(x, y, c, color);
1045    }
1046
1047    public AnimatedEntity animateActor(int x, int y, char c, Color color) {
1048        return foregroundPanel.animateActor(x, y, c, color);
1049    }
1050
1051    public AnimatedEntity animateActor(int x, int y, char c, Color color, boolean doubleWidth) {
1052        return foregroundPanel.animateActor(x, y, doubleWidth, c, color);
1053    }
1054
1055    public AnimatedEntity animateActor(int x, int y, char c, Collection<Color> colors, boolean doubleWidth) {
1056        return foregroundPanel.animateActor(x, y, doubleWidth, String.valueOf(c), colors);
1057    }
1058
1059    public AnimatedEntity animateActor(int x, int y, char c, Collection<Color> colors, float loopTime, boolean doubleWidth) {
1060        return foregroundPanel.animateActor(x, y, doubleWidth, String.valueOf(c), colors, loopTime);
1061    }
1062
1063    public AnimatedEntity animateActor(int x, int y, String s, Color color, int layer) {
1064        return getLayer(layer).animateActor(x, y, s, color);
1065    }
1066
1067    public AnimatedEntity animateActor(int x, int y, String s, Color color, int layer, boolean doubleWidth) {
1068        return getLayer(layer).animateActor(x, y, doubleWidth, s, color);
1069    }
1070
1071    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color, int layer) {
1072        return getLayer(layer).animateActor(x, y, tr, color);
1073    }
1074
1075    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color, int layer, boolean doubleWidth, boolean stretch) {
1076        return getLayer(layer).animateActor(x, y, doubleWidth, stretch, tr, color);
1077    }
1078
1079    public AnimatedEntity animateActor(int x, int y, String s, Color color) {
1080        return foregroundPanel.animateActor(x, y, s, color);
1081    }
1082
1083    public AnimatedEntity animateActor(int x, int y, String s, Color color, boolean doubleWidth) {
1084        return foregroundPanel.animateActor(x, y, doubleWidth, s, color);
1085    }
1086
1087    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color) {
1088        return foregroundPanel.animateActor(x, y, tr, color);
1089    }
1090
1091    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color, boolean doubleWidth) {
1092        return foregroundPanel.animateActor(x, y, doubleWidth, tr, color);
1093    }
1094
1095    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, Color color, boolean doubleWidth, boolean stretch) {
1096        return foregroundPanel.animateActor(x, y, doubleWidth, stretch, tr, color);
1097    }
1098
1099    public AnimatedEntity animateActor(int x, int y, TextureRegion tr) {
1100        return animateActor(x, y, tr, Color.WHITE);
1101    }
1102
1103    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, boolean doubleWidth) {
1104        return animateActor(x, y, tr, Color.WHITE, doubleWidth);
1105    }
1106
1107    public AnimatedEntity animateActor(int x, int y, TextureRegion tr, boolean doubleWidth, boolean stretch) {
1108        return animateActor(x, y, tr, Color.WHITE, doubleWidth, stretch);
1109    }
1110
1111    public OrderedSet<AnimatedEntity> getAnimatedEntities(int layer) {
1112        return getLayer(layer).getAnimatedEntities();
1113    }
1114
1115    public OrderedSet<AnimatedEntity> getAnimatedEntities() {
1116        return foregroundPanel.getAnimatedEntities();
1117    }
1118
1119    public AnimatedEntity getAnimatedEntityByCell(int x, int y, int layer) {
1120        return getLayer(layer).getAnimatedEntityByCell(x, y);
1121    }
1122
1123    public void removeAnimatedEntity(AnimatedEntity ae, int layer) {
1124        getLayer(layer).removeAnimatedEntity(ae);
1125    }
1126
1127    public void removeAnimatedEntity(AnimatedEntity ae) {
1128        foregroundPanel.removeAnimatedEntity(ae);
1129    }
1130
1131    public AnimatedEntity getAnimatedEntityByCell(int x, int y) {
1132        return foregroundPanel.getAnimatedEntityByCell(x, y);
1133    }
1134
1135    public void removeAnimatedEntityByCell(int x, int y, int layer) {
1136        getLayer(layer).removeAnimatedEntity(getAnimatedEntityByCell(x, y, layer));
1137    }
1138
1139    public void removeAnimatedEntityByCell(int x, int y) {
1140        foregroundPanel.removeAnimatedEntity(getAnimatedEntityByCell(x, y));
1141    }
1142
1143    @Override
1144    public void draw(Batch batch, float parentAlpha) {
1145        //textFactory.configureShader(batch);
1146        super.draw(batch, parentAlpha);
1147    }
1148
1149    public void drawActor(Batch batch, float parentAlpha, AnimatedEntity ae, int layer) {
1150        getLayer(layer).drawActor(batch, parentAlpha, ae);
1151    }
1152
1153    public void drawActor(Batch batch, float parentAlpha, AnimatedEntity ae) {
1154        foregroundPanel.drawActor(batch, parentAlpha, ae);
1155    }
1156
1157    public void setLightingColor(Color lightingColor) {
1158        backgroundPanel.setLightingColor(lightingColor);
1159    }
1160
1161    public Color getLightingColor() {
1162        return backgroundPanel.getLightingColor();
1163    }
1164
1165
1166    /**
1167     * Sets the position of the actor's bottom left corner.
1168     *
1169     * @param x
1170     * @param y
1171     */
1172    @Override
1173    public void setPosition(float x, float y) {
1174        //super.setPosition(x, y);
1175        //setBounds(x, y, getWidth(), getHeight());
1176        foregroundPanel.setPosition(x, y);
1177        backgroundPanel.setPosition(x, y);
1178        for (SquidPanel panel : extraPanels) {
1179            panel.setPosition(x, y);
1180        }
1181    }
1182
1183    /**
1184     * Gets a SquidPanel from this SquidLayers and returns a direct reference. Layer 0 is the background, layer 1 or 2
1185     * is the foreground, and any values 3 or higher are extra SquidPanels added via {@link #addExtraLayer()}.
1186     * If the layer is not found, this returns the foreground SquidPanel.
1187     * @param layer 0 for background, 1 or 2 for foreground, 3 for any extra layers; defaults to foreground
1188     * @return the corresponding SquidPanel as a direct reference
1189     */
1190    public SquidPanel getLayer(int layer) {
1191        SquidPanel p = foregroundPanel;
1192        switch (layer) {
1193            case 0:
1194                p = backgroundPanel;
1195                break;
1196            case 1:
1197            case 2:
1198                break;
1199            default:
1200                p = extraPanels.get(layer - 3);
1201        }
1202        return p;
1203    }
1204
1205    public SquidPanel getForegroundLayer() {
1206        return foregroundPanel;
1207    }
1208
1209    /**
1210     * Sets the foreground panel to match the given SquidPanel (it can also be a subclass of SquidPanel, a likely use).
1211     * This does not do any validation of size, but the {@link SquidPanel#getTotalWidth()} and
1212     * {@link SquidPanel#getTotalHeight()} of panel should almost always match this object's {@link #getTotalWidth()}
1213     * and {@link #getTotalHeight()}, though there are good reasons why the cell sizes or text sizes might not match.
1214     * This method is probably most useful when you want a system of {@link ImageSquidPanel} layers; as long as you have
1215     * the reference to an ImageSquidPanel outside this class, you can call its additional methods there and have it
1216     * affect {@code panel} here.
1217     *
1218     * @param panel a SquidPanel, ImageSquidPanel, or other subclass of SquidPanel that should have identical size
1219     */
1220    public void setForegroundLayer(SquidPanel panel) {
1221        if (panel != null) {
1222            removeActor(foregroundPanel);
1223            foregroundPanel = panel;
1224            addActorAt(2, panel);
1225
1226        }
1227    }
1228
1229    public SquidPanel getBackgroundLayer() {
1230        return backgroundPanel;
1231    }
1232
1233    /**
1234     * Sets the background panel to match the given SquidPanel (it can also be a subclass of SquidPanel, a likely use).
1235     * This does not do any validation of size, but the {@link SquidPanel#getTotalWidth()} and
1236     * {@link SquidPanel#getTotalHeight()} of panel should almost always match this object's {@link #getTotalWidth()}
1237     * and {@link #getTotalHeight()}, though there are good reasons why the cell sizes or text sizes might not match.
1238     * This method is probably most useful when you want a system of {@link ImageSquidPanel} layers; as long as you have
1239     * the reference to an ImageSquidPanel outside this class, you can call its additional methods there and have it
1240     * affect {@code panel} here.
1241     *
1242     * @param panel a SquidPanel, ImageSquidPanel, or other subclass of SquidPanel that should have identical size
1243     */
1244    public void setBackgroundLayer(SquidPanel panel) {
1245
1246        if (panel != null) {
1247            removeActor(backgroundPanel);
1248            backgroundPanel = panel;
1249            addActorAt(0, panel);
1250        }
1251    }
1252
1253    /**
1254     * Sets an extra panel to match the given SquidPanel (it can also be a subclass of SquidPanel, a likely use).
1255     * This tries to find the SquidPanel at the given index in the extra panels that may have been added to this with
1256     * {@link #addExtraLayer()}; if index is invalid because it is negative, this does nothing. If index is higher
1257     * than the highest index for a layer, this will simply add {@code panel} to the extra panels, possibly at an
1258     * earlier index (it will use the next available index, which could easily be 0 or 1). If index is valid, this sets
1259     * the extra panel at that index to {@code panel}, without changes.
1260     * This does not do any validation of size, but the {@link SquidPanel#getTotalWidth()} and
1261     * {@link SquidPanel#getTotalHeight()} of panel should almost always match this object's {@link #getTotalWidth()}
1262     * and {@link #getTotalHeight()}, though there are good reasons why the cell sizes or text sizes might not match.
1263     * This method is probably most useful when you want a system of {@link ImageSquidPanel} layers; as long as you have
1264     * the reference to an ImageSquidPanel outside this class, you can call its additional methods there and have it
1265     * affect {@code panel} here.
1266     *
1267     * @param panel a SquidPanel, ImageSquidPanel, or other subclass of SquidPanel that should have identical size
1268     * @param index the 0-based index into the extra panels list to try to assign panel to, or to append panel to
1269     */
1270
1271    public void setExtraPanel(SquidPanel panel, int index) {
1272        if (index < 0 || panel == null || extraPanels == null)
1273            return;
1274        if (index >= extraPanels.size()) {
1275            extraPanels.add(panel);
1276            addActor(panel);
1277        } else {
1278            removeActor(extraPanels.get(index));
1279            extraPanels.set(index, panel);
1280            addActorAt(index, panel);
1281        }
1282    }
1283
1284
1285    /**
1286     * Sets the IColorCenter used by the foreground layer.
1287     *
1288     * @param scc an IColorCenter<Color>; commonly a SquidColorCenter with an optional filter
1289     */
1290    public void setFGColorCenter(IColorCenter<Color> scc) {
1291        foregroundPanel.setColorCenter(scc);
1292    }
1293
1294    /**
1295     * Sets the IColorCenter used by the background layer.
1296     *
1297     * @param scc an IColorCenter<Color>; commonly a SquidColorCenter with an optional filter
1298     */
1299    public void setBGColorCenter(IColorCenter<Color> scc) {
1300        backgroundPanel.setColorCenter(scc);
1301    }
1302
1303    public void setOffsets(float x, float y) {
1304        foregroundPanel.setOffsets(x, y);
1305        backgroundPanel.setOffsets(x, y);
1306        for (SquidPanel p : extraPanels)
1307            p.setOffsets(x, y);
1308    }
1309
1310    public int getGridOffsetX() {
1311        return foregroundPanel.getGridOffsetX();
1312    }
1313
1314    public int getGridOffsetY() {
1315        return foregroundPanel.getGridOffsetY();
1316    }
1317
1318    public void setGridOffsetX(int offset) {
1319        foregroundPanel.setGridOffsetX(offset);
1320        backgroundPanel.setGridOffsetX(offset);
1321        for (SquidPanel sp : extraPanels)
1322            sp.setGridOffsetX(offset);
1323    }
1324
1325    public void setGridOffsetY(int offset) {
1326        foregroundPanel.setGridOffsetY(offset);
1327        backgroundPanel.setGridOffsetY(offset);
1328        for (SquidPanel sp : extraPanels)
1329            sp.setGridOffsetY(offset);
1330    }
1331
1332    public int getTotalWidth() {
1333        return foregroundPanel.getTotalWidth();
1334    }
1335
1336    public int getTotalHeight() {
1337        return foregroundPanel.getTotalHeight();
1338    }
1339}