/**
* THIS IS CREATED BY tom_mai78101. PLEASE GIVE CREDIT FOR WORKING ON A CLONE.
*
* ALL WORKS COPYRIGHTED TO The Pokémon Company and Nintendo. I REPEAT, THIS IS A CLONE.
*
* YOU MAY NOT SELL COMMERCIALLY, OR YOU WILL BE PROSECUTED BY The Pokémon Company AND Nintendo.
*
* THE CREATOR IS NOT LIABLE FOR ANY DAMAGES DONE. FOLLOW LOCAL LAWS, BE RESPECTFUL, AND HAVE A GOOD DAY!
* */
package editor;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.util.ArrayList;
import java.util.Map;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import abstracts.Tile;
public class DrawingBoard extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
private LevelEditor editor;
private BufferedImage image;
private int[] tiles;
private int[] tilesEditorID;
private int[] triggers;
private int bitmapWidth, bitmapHeight;
private int offsetX, offsetY;
private int mouseOnTileX, mouseOnTileY;
public DrawingBoard(final LevelEditor editor, int width, int height) {
super();
this.editor = editor;
offsetX = offsetY = 0;
int w = width * Tile.WIDTH;
int h = height * Tile.HEIGHT;
Dimension size = new Dimension(w, h);
this.setSize(size);
this.setPreferredSize(size);
this.setMaximumSize(size);
this.setMinimumSize(size);
this.validate();
editor.validate();
}
@Override
public void run() {
long now, lastTime = System.nanoTime();
double unprocessed = 0.0;
final double nsPerTick = 1000000000.0 / 30.0;
while (editor.running) {
now = System.nanoTime();
unprocessed += (now - lastTime) / nsPerTick;
lastTime = now;
if (unprocessed >= 40.0)
unprocessed = 40.0;
if (unprocessed <= 0.0)
unprocessed = 1.0;
while (unprocessed >= 1.0) {
tick();
unprocessed -= 1.0;
}
try {
render();
Thread.sleep(1);
}
catch (InterruptedException e) {
e.printStackTrace();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
public void setImageSize(int w, int h) {
if (w <= 0 || h <= 0)
return;
if (image != null) {
image.flush();
image = null;
}
tiles = new int[w * h];
tilesEditorID = new int[w * h];
triggers = new int[w * h];
for (int i = 0; i < tiles.length; i++) {
tiles[i] = 0;
tilesEditorID[i] = 0;
triggers[i] = 0;
}
image = new BufferedImage(w * Tile.WIDTH, h * Tile.HEIGHT, BufferedImage.TYPE_INT_ARGB);
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
for (int j = 0; j < image.getHeight(); j++) {
for (int i = 0; i < image.getWidth(); i++) {
if (i % Tile.WIDTH == 0 || j % Tile.HEIGHT == 0)
pixels[j * image.getWidth() + i] = 0;
else
pixels[j * image.getWidth() + i] = -1;
}
}
bitmapWidth = w;
bitmapHeight = h;
offsetX = -((this.getWidth() - (w * Tile.WIDTH)) / 2);
offsetY = -((this.getHeight() - (h * Tile.HEIGHT)) / 2);
editor.input.offsetX = offsetX;
editor.input.offsetY = offsetY;
}
public void newImage() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JTextField widthField;
JTextField heightField;
int result;
do {
widthField = new JTextField("10");
heightField = new JTextField("10");
JPanel panel = new JPanel(new GridLayout(1, 2));
panel.add(new JLabel(" Width:"));
panel.add(widthField);
panel.add(new JLabel(" Height:"));
panel.add(heightField);
result = JOptionPane.showConfirmDialog(null, panel, "Create New Area", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);
}
while (Integer.valueOf(widthField.getText()) <= 0 || Integer.valueOf(heightField.getText()) <= 0);
if (result == JOptionPane.OK_OPTION) {
setImageSize(Integer.valueOf(widthField.getText()), Integer.valueOf(heightField.getText()));
}
}
});
}
public void newImage(final int x, final int y) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
setImageSize(x, y);
}
});
}
public void render() throws Exception {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
bs = this.getBufferStrategy();
}
hoverOver();
switch (EditorConstants.metadata) {
case Pixel_Data: {
if (tilesEditorID != null) {
for (int j = 0; j < tilesEditorID.length; j++) {
if (bitmapWidth <= 0)
break;
if (bitmapHeight <= 0)
break;
int w = j % bitmapWidth;
int h = j / bitmapWidth;
Map.Entry<Integer, Data> entry = EditorConstants.getInstance().getDatas().get(tilesEditorID[j]);
Data data = entry.getValue();
if (data == null) {
break;
}
if (data.image == null) {
tiles[j] = 0;
tilesEditorID[j] = 0;
continue;
}
if (image == null)
return;
Graphics g = this.image.getGraphics();
BufferedImage bimg = new BufferedImage(data.image.getIconWidth(), data.image.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics gB = bimg.getGraphics();
// TODO: Area Type ID must be included.
gB.drawImage(data.image.getImage(), 0, 0, null);
gB.dispose();
if (data.areaTypeIncluded) {
switch (data.areaTypeIDType) {
case ALPHA:
default:
this.setBiomeTile((tiles[j] >> 24) & 0xFF, g);
break;
case RED:
this.setBiomeTile((tiles[j] >> 16) & 0xFF, g);
break;
case GREEN:
this.setBiomeTile((tiles[j] >> 8) & 0xFF, g);
break;
case BLUE:
this.setBiomeTile(tiles[j] & 0xFF, g);
break;
}
}
else
g.setColor(Color.white);
g.fillRect(w * Tile.WIDTH, h * Tile.HEIGHT, Tile.WIDTH, Tile.HEIGHT);
g.drawImage(bimg, w * Tile.WIDTH, h * Tile.HEIGHT, Tile.WIDTH, Tile.HEIGHT, null);
g.dispose();
}
}
break;
}
case Triggers: {
if (triggers != null) {
for (int k = 0; k < triggers.length; k++) {
if (bitmapWidth <= 0)
break;
if (bitmapHeight <= 0)
break;
Trigger trigger = null;
try {
trigger = EditorConstants.getInstance().getTriggers().get(triggers[k]);
}
catch (Exception e) {
// Eraser.
trigger = EditorConstants.getInstance().getTriggers().get(0);
}
Data data = null;
try {
Map.Entry<Integer, Data> entry = EditorConstants.getInstance().getDatas().get(tilesEditorID[k]);
data = entry.getValue();
}
catch (Exception e) {
data = EditorConstants.getInstance().getDatas().get(0).getValue();
}
if (trigger == null)
break;
int w = k % bitmapWidth;
int h = k / bitmapWidth;
Graphics g = this.image.getGraphics();
if ((triggers[k] & 0xFFFF) != 0) {
g.setColor(Color.cyan);
g.fillRect(w * Tile.WIDTH, h * Tile.HEIGHT, Tile.WIDTH, Tile.HEIGHT);
}
else {
// g.drawImage(data.image.getImage(), w * Tile.WIDTH, h * Tile.HEIGHT, Tile.WIDTH, Tile.HEIGHT, null);
Graphics gD = this.image.getGraphics();
BufferedImage bimg = new BufferedImage(data.image.getIconWidth(), data.image.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics gB = bimg.getGraphics();
// TODO: Area Type ID must be included.
gB.drawImage(data.image.getImage(), 0, 0, null);
gB.dispose();
if (data.areaTypeIncluded) {
switch (data.areaTypeIDType) {
case ALPHA:
default:
this.setBiomeTile((tiles[k] >> 24) & 0xFF, g);
break;
case RED:
this.setBiomeTile((tiles[k] >> 16) & 0xFF, g);
break;
case GREEN:
this.setBiomeTile((tiles[k] >> 8) & 0xFF, g);
break;
case BLUE:
this.setBiomeTile(tiles[k] & 0xFF, g);
break;
}
}
else
gD.setColor(Color.white);
g.fillRect(w * Tile.WIDTH, h * Tile.HEIGHT, Tile.WIDTH, Tile.HEIGHT);
g.drawImage(bimg, w * Tile.WIDTH, h * Tile.HEIGHT, Tile.WIDTH, Tile.HEIGHT, null);
g.dispose();
}
g.dispose();
}
}
break;
}
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.translate(-offsetX, -offsetY);
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
if (image != null) {
g.drawImage(image, 0, 0, null);
}
g.dispose();
bs.show();
}
private void setBiomeTile(final int toCompare, Graphics g) {
switch (toCompare) {
case 0x00: // grass
g.setColor(EditorConstants.GRASS_GREEN);
break;
case 0x01: // Road
g.setColor(EditorConstants.ROAD_WHITE);
break;
case 0x02: // Dirt
case 0x04: // dirt
g.setColor(EditorConstants.DIRT_SIENNA);
break;
case 0x03: // Water
g.setColor(EditorConstants.WATER_BLUE);
break;
case 0x05: // Door/Carpet
default:
g.setColor(Color.white);
break;
}
}
public void tick() {
switch (EditorConstants.metadata) {
case Pixel_Data: {
if (editor.input.isDragging()) {
offsetX = editor.input.offsetX;
offsetY = editor.input.offsetY;
}
else if (editor.input.isDrawing()) {
this.mouseOnTileX = offsetX + editor.input.drawingX;
if (this.mouseOnTileX < 0)
return;
if (this.mouseOnTileX >= bitmapWidth * Tile.WIDTH)
return;
this.mouseOnTileY = offsetY + editor.input.drawingY;
if (this.mouseOnTileY < 0)
return;
if (this.mouseOnTileY >= bitmapHeight * Tile.HEIGHT)
return;
Data d = editor.controlPanel.getSelectedData();
if (d != null) {
setDataProperties(d);
}
editor.validate();
}
break;
}
case Triggers: {
if (editor.input.isDragging()) {
offsetX = editor.input.offsetX;
offsetY = editor.input.offsetY;
}
else if (editor.input.isDrawing()) {
this.mouseOnTileX = editor.input.offsetX + editor.input.drawingX;
this.mouseOnTileY = editor.input.offsetY + editor.input.drawingY;
if (this.mouseOnTileX < 0 || this.mouseOnTileX >= bitmapWidth * Tile.WIDTH)
return;
if (this.mouseOnTileY < 0 || this.mouseOnTileY >= bitmapHeight * Tile.HEIGHT)
return;
Trigger t = editor.controlPanel.getSelectedTrigger();
if (t != null) {
int x = this.getMouseTileX();
int y = this.getMouseTileY();
t.setTriggerPositionX((byte) x);
t.setTriggerPositionY((byte) y);
int i = y * bitmapWidth + x;
this.triggers[i] = t.getDataValue();
}
editor.validate();
}
break;
}
}
}
private void setDataProperties(Data d) {
switch (d.alpha) {
case 0x02: {
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
int i = this.getMouseTileY() * bitmapWidth + this.getMouseTileX();
Data temp = null;
for (Map.Entry<Integer, Data> entry : EditorConstants.getInstance().getDatas()) {
if (panel.dataValue == entry.getKey()) {
temp = entry.getValue();
break;
}
}
if (temp != null) {
tiles[i] = panel.dataValue;
tilesEditorID[i] = temp.editorID;
}
else {
tiles[i] = (d.alpha << 24) | (d.red << 16) | panel.dataValue & 0xFFFF;
tilesEditorID[i] = d.editorID;
}
break;
}
case 0x03: {
switch (d.red) {
case 0x05: { // Sign
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
int green = (panel.dataValue >> 8) & 0xFF;
int blue = (panel.dataValue & 0xFF);
int i = this.getMouseTileY() * bitmapWidth + this.getMouseTileX();
tiles[i] = (d.alpha << 24) | (d.red << 16) | (green << 8) | blue;
tilesEditorID[i] = d.editorID;
break;
}
default: {
defaultTileProperties(d);
break;
}
}
break;
}
case 0x04: // Warp point
case 0x05: // Sector point
case 0x09: // Door
case 0x0B: // Carpet
case 0x0C: { // Carpet
manualInputTileProperties(d);
break;
}
case 0x08: { // House
switch (d.red) {
case 0x0B: // Left roof
case 0x0C: // Middle roof
case 0x0D: {// Right roof
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
int i = this.getMouseTileY() * bitmapWidth + this.getMouseTileX();
tiles[i] = (d.alpha << 24) | (d.red << 16) | panel.dataValue & 0xFFFF;
tilesEditorID[i] = d.editorID;
break;
}
default:
defaultTileProperties(d);
break;
}
break;
}
case 0x0A: { // Items
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
int i = this.getMouseTileY() * bitmapWidth + this.getMouseTileX();
tiles[i] = (d.alpha << 24) | panel.dataValue & 0xFFFFFF;
tilesEditorID[i] = d.editorID;
break;
}
case 0x0D: { // Default starting point
int green = d.green;
int blue = d.blue;
if (d.greenByEditor)
green = this.getMouseTileX();
if (d.blueByEditor)
blue = this.getMouseTileY();
int i = this.getMouseTileY() * bitmapWidth + this.getMouseTileX();
tiles[i] = (d.alpha << 24) | (d.red << 16) | (green << 8) | blue;
tilesEditorID[i] = d.editorID;
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
panel.greenInputField.setText(Integer.toString(green));
panel.blueInputField.setText(Integer.toString(blue));
panel.greenField.setText(Integer.toString(green));
panel.blueField.setText(Integer.toString(blue));
panel.validate();
break;
}
default: {
defaultTileProperties(d);
break;
}
}
}
private void defaultTileProperties(Data d) {
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
int i = this.getMouseTileY() * bitmapWidth + this.getMouseTileX();
Data temp = null;
for (Map.Entry<Integer, Data> entry : EditorConstants.getInstance().getDatas()) {
if (panel.dataValue == entry.getKey()) {
temp = entry.getValue();
break;
}
}
if (temp != null) {
tiles[i] = panel.dataValue;
tilesEditorID[i] = temp.editorID;
}
else {
tiles[i] = d.getColorValue();
tilesEditorID[i] = d.editorID;
}
}
private void manualInputTileProperties(Data d) {
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
int i = this.getMouseTileY() * bitmapWidth + this.getMouseTileX();
tiles[i] = panel.dataValue;
tilesEditorID[i] = d.editorID;
}
public void start() {
new Thread(this).start();
}
public int getMouseTileX() {
return this.mouseOnTileX / Tile.WIDTH;
}
public int getMouseTileY() {
return this.mouseOnTileY / Tile.HEIGHT;
}
public int getBitmapWidth() {
return this.bitmapWidth;
}
public int getBitmapHeight() {
return this.bitmapHeight;
}
public BufferedImage getMapImage() {
if (bitmapWidth * bitmapHeight == 0)
return null;
int size = 0;
int h = 0;
if (this.triggers == null) {
this.triggers = new int[1];
this.triggers[0] = 0;
}
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i : this.triggers) {
if (i != 0)
list.add(Integer.valueOf(i));
}
size = list.size();
h = (size / bitmapHeight) + 1;
BufferedImage buffer = new BufferedImage(bitmapWidth, bitmapHeight + h, BufferedImage.TYPE_INT_ARGB);
int[] pixels = ((DataBufferInt) buffer.getRaster().getDataBuffer()).getData();
int index = 0;
int width = 0;
pixels[0] = list.size();
for (int i = 0; i < list.size(); i++) {
width = i + 1;
pixels[width + (index * bitmapHeight)] = list.get(i).intValue();
if (width >= bitmapHeight) {
index++;
width -= bitmapHeight;
}
}
for (int iterator = 0; iterator < tiles.length; iterator++) {
pixels[bitmapWidth * h + iterator] = tiles[iterator];
}
return buffer;
}
public boolean hasBitmap() {
return (this.bitmapHeight * this.bitmapWidth != 0);
}
public void openMapImage(BufferedImage image) {
try {
int[] srcTiles = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
int triggerCount = srcTiles[0];
int triggerRows = (triggerCount / image.getWidth()) + 1;
this.setImageSize(image.getWidth(), (image.getHeight() - triggerRows));
if (this.triggers != null)
this.triggers = null;
this.triggers = new int[image.getWidth() * (image.getHeight() - triggerRows)];
for (int i = 0; i < triggerCount; i++) {
int x = (srcTiles[i + 1] >> 24) & 0xFF;
int y = (srcTiles[i + 1] >> 16) & 0xFF;
this.triggers[y * image.getWidth() + x] = srcTiles[i + 1];
}
for (int i = 0; i < srcTiles.length - (triggerRows * image.getWidth()); i++)
this.tiles[i] = srcTiles[i + (triggerRows * image.getWidth())];
ArrayList<Map.Entry<Integer, Data>> list = EditorConstants.getInstance().getDatas();
for (int i = 0; i < tiles.length; i++) {
int alpha = ((tiles[i] >> 24) & 0xFF);
for (int j = 0; j < list.size(); j++) {
Map.Entry<Integer, Data> entry = list.get(j);
Data d = entry.getValue();
switch (alpha) {
case 0x01: // Path
case 0x02: // Ledges
case 0x03: // Obstacles
case 0x06: // Stairs
case 0x07: // Water
case 0x08: // House
// Extended Tile IDs are used to differentiate tiles.
if (alpha == Integer.valueOf(d.alpha)) {
int red = ((tiles[i] >> 16) & 0xFF);
if (red == Integer.valueOf(d.red)) {
tilesEditorID[i] = d.editorID;
}
}
continue;
case 0x05: {// Area Zone
// Extended Tile IDs are used to differentiate tiles.
if (alpha == Integer.valueOf(d.alpha)) {
int blue = tiles[i] & 0xFF;
if (blue == d.blue) {
tilesEditorID[i] = d.editorID;
break;
}
}
continue;
}
default: {
// Alpha value is only used.
if (alpha == Integer.valueOf(d.alpha)) {
tilesEditorID[i] = d.editorID;
break;
}
continue;
}
}
}
}
}
catch (NegativeArraySizeException e) {
JOptionPane.showMessageDialog(null, "Incorrect file format. The file does not contain necessary metadata.");
}
catch (Exception e) {
JOptionPane.showMessageDialog(null, "Error loading the file. Unable to pinpoint the cause.");
}
}
private void hoverOver() {
try {
int w = 0;
int h = 0;
// try...catch for X position
try {
w = (editor.input.offsetX + editor.input.mouseX) / Tile.WIDTH;
}
catch (Exception e) {
w = (editor.input.offsetX + editor.input.mouseX) / (LevelEditor.WIDTH * LevelEditor.SIZE);
}
// try catch for Y position
try {
h = (editor.input.offsetY + editor.input.mouseY) / Tile.HEIGHT;
}
catch (Exception e) {
h = (editor.input.offsetY + editor.input.mouseY) / (LevelEditor.WIDTH * LevelEditor.SIZE);
}
// checks for mouse hoving above triggers
int[] list = null;
switch (EditorConstants.metadata) {
case Pixel_Data:
default:
list = tiles;
break;
case Triggers:
list = triggers;
break;
}
int value = list[h * bitmapWidth + w];
// Show trigger IDs and stuffs.
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
panel.alphaField.setText(Integer.toString((value >> 24) & 0xFF));
panel.redField.setText(Integer.toString((value >> 16) & 0xFF));
panel.greenField.setText(Integer.toString((value >> 8) & 0xFF));
panel.blueField.setText(Integer.toString(value & 0xFF));
panel.validate();
}
catch (Exception e) {
TilePropertiesPanel panel = editor.controlPanel.getPropertiesPanel();
panel.alphaField.setText("");
panel.redField.setText("");
panel.greenField.setText("");
panel.blueField.setText("");
panel.validate();
}
}
}