package domain;
import static core.Script.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.TexturePaint;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import persist.ExtendedDataInputStream;
import persist.ExtendedDataOutputStream;
import core.Script;
public class Vsp {
public static final int VID_BYTESPERPIXEL = 3;
public static final int VSP_SIGNATURE = 5264214;
public static final int VSP_VERSION = 6;
public static final int ANIM_MODE_FORWARD = 0;
public static final int ANIM_MODE_BACKWARD = 1;
public static final int ANIM_MODE_RANDOM = 2;
public static final int ANIM_MODE_PINGPONG = 3;
public static int mytimer;
// .vsp format: https://github.com/Bananattack/v3tiled/wiki/.vsp-file
private int signature = VSP_SIGNATURE;
private int version = VSP_VERSION;
private int tileSize = 16;
private int format = 1;
private int compression = 1;
private int numtiles = 0;
private Animation[] anims = new Animation[0];
private byte[] obsPixels = new byte[16*16]; // width * height * 1 bytes!
int numobs;
int vadelay[], tileidx[], flipped[];
// [Rafael, the Esper]
private BufferedImage [] tiles;
public static void main(String args[]) throws Exception{
/*// EXAMPLE OF ADDING ANIMATIONS PROGRAMATICALLY
Vsp v = new Vsp(new URL("file:///C:\\JavaRef3\\EclipseWorkspace\\wmap.vsp"));
Animation[] anims = new Animation[42];
int j=0;
for(int i=45; i<=250;i+=5) {
Animation a = v.new Animation();
a.delay = 30;
a.start = i;
a.finish = i+4;
a.mode = 3;
a.name = "Anim" + ((i-40)/5);
anims[j++] = a;
System.out.println(a);
}
v.anims = anims;
v.save("C:\\JAVAREF3\\ECLIPSEWORKSPACE\\wmap2.vsp");
*/
Vsp v = new Vsp(new URL("file:///C:\\javaref\\workspace\\Phantasy\\src\\ps\\ps1.vsp"));
int NEW_PIXELS = 4;
byte[] newPixels = new byte[256*(v.numobs+NEW_PIXELS)];
int pos=0;
for(int i=0;i<256*v.numobs; i++) {
newPixels[i] = v.obsPixels[i];
pos++;
}
for(int i=0; i<256; i++) { // Add vertical | left obs
if(i%16==0)
newPixels[pos++] = 1;
else
newPixels[pos++] = 0;
}
for(int i=0; i<256; i++) { // Add vertical | right obs
if(i%16==15)
newPixels[pos++] = 1;
else
newPixels[pos++] = 0;
}
for(int i=0; i<256; i++) { // Add horizontal _ bottom obs
if(i<16)
newPixels[pos++] = 1;
else
newPixels[pos++] = 0;
}
for(int i=0; i<256; i++) { // Add horizontal -- top obs
if(i>=240)
newPixels[pos++] = 1;
else
newPixels[pos++] = 0;
}
v.numobs = v.numobs + NEW_PIXELS;
v.obsPixels = newPixels;
v.save("C:\\ps1.vsp");
System.out.println(v.obsPixels.length);
}
public Vsp() {
}
public Vsp(URL urlpath) {
try {
this.load(urlpath.openStream());
} catch (FileNotFoundException fnfe) {
error("VSP::FileNotFoundException : " + urlpath);
} catch (IOException e) {
error("VSP::IOException : " + e.getMessage());
}
}
private void load (InputStream fis) {
try
{
ExtendedDataInputStream f = new ExtendedDataInputStream(fis);
this.signature = f.readSignedIntegerLittleEndian();
this.version = f.readSignedIntegerLittleEndian();
this.tileSize = f.readSignedIntegerLittleEndian();
this.format = f.readSignedIntegerLittleEndian();
this.numtiles = f.readSignedIntegerLittleEndian();
this.compression = f.readSignedIntegerLittleEndian();
System.out.println(this.signature + ";"+this.version+";"+this.getNumtiles()+";"+this.compression);
byte[] vspdata = f.readCompressedUnsignedShortsIntoBytes(); // tileCount * width * height * 3 bytes!
int numAnim = f.readSignedIntegerLittleEndian(); // anim.length
this.anims = new Vsp.Animation[numAnim];
System.out.println("numAnim = " + numAnim);
for(int i=0; i<numAnim; i++) {
Vsp.Animation a = this.new Animation();
a.name = f.readFixedString(256);
a.start = f.readSignedIntegerLittleEndian();
a.finish = f.readSignedIntegerLittleEndian();
a.delay = f.readSignedIntegerLittleEndian();
a.mode = f.readSignedIntegerLittleEndian();
this.anims[i] = a;
}
this.numobs = f.readSignedIntegerLittleEndian(); // obs.length
System.out.println("numObs = " + numobs);
this.obsPixels = f.readCompressedUnsignedShortsIntoBytes();
/* Obs array DEBUG
* for(int i=0;i<obsPixels.length;i++) {
if(i%16==0)
System.out.println();
if(i%256==0)
System.out.println();
System.out.print(obsPixels[i]);
}*/
f.close();
// initialize tile anim stuff
tileidx = new int[getNumtiles()];
flipped = new int[getNumtiles()];
vadelay = new int[numAnim];
int i;
for (i=0; i<numAnim; i++)
vadelay[i]=0;
for (i=0; i<getNumtiles(); i++)
{
flipped[i] = 0;
tileidx[i] = i;
}
mytimer = systemtime;
// Get image tiles from pixel array
System.out.println("Numtiles: " + getNumtiles() + "(" + vspdata.length + " bytes)");
this.tiles = f.getBufferedImageArrayFromPixels(vspdata, getNumtiles(), 16, 16);
//for(int x=0; x<tiles.length; x++)
//Script.graycolorfilter(tiles[x]);
}catch (IOException e) {
System.out.println("IOException : " + e);
}
}
private void save(String filename) {
System.out.println("VSP::save at " + filename);
ExtendedDataOutputStream f = null;
try {
OutputStream os = new FileOutputStream(filename);
f = new ExtendedDataOutputStream(os);
f.writeSignedIntegerLittleEndian(this.signature);
f.writeSignedIntegerLittleEndian(this.version);
f.writeSignedIntegerLittleEndian(this.tileSize);
f.writeSignedIntegerLittleEndian(this.format);
f.writeSignedIntegerLittleEndian(this.getNumtiles());
f.writeSignedIntegerLittleEndian(this.compression);
System.out.println(this.signature + ";"+this.version+";"+this.getNumtiles()+";"+this.compression);
byte[] pixels = f.getPixelArrayFromFrames(tiles, tiles.length, this.tileSize, this.tileSize);
f.writeCompressedBytes(pixels);
f.writeSignedIntegerLittleEndian(this.anims.length);
for(int i=0; i<this.anims.length; i++) {
Animation a = anims[i];
f.writeFixedString(a.name, 256);
f.writeSignedIntegerLittleEndian(a.start);
f.writeSignedIntegerLittleEndian(a.finish);
f.writeSignedIntegerLittleEndian(a.delay);
f.writeSignedIntegerLittleEndian(a.mode);
}
f.writeSignedIntegerLittleEndian(this.numobs);
f.writeCompressedBytes(this.obsPixels);
}
catch(IOException e) {
System.err.println("VSP::save " + e.getMessage());
}
finally {
try {
f.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void exportToClipboard(int tiles_per_row) {
int row_size = tiles_per_row*16;
VImage clipboard = new VImage(row_size, (this.getNumtiles()/tiles_per_row+1) * 16);
Font font = new Font("Serif", Font.PLAIN, 7);
for(int i=0; i<this.getNumtiles(); i++) {
clipboard.blit((i*16)%row_size, i/tiles_per_row*16, getTiles()[i]);
//if(i%tiles_per_row == 0)
//clipboard.printstring(0, i/tiles_per_row*16+7, font, Integer.toString(i/tiles_per_row));
}
clipboard.copyImageToClipboard();
}
static void createVspFromImages(VImage[] images) {
// First pixel is default transparent color
//Color transC = new Color(images[0].image.getRGB(0, 0));
ArrayList<VImage> allTiles = new ArrayList<VImage>();
for(int img=0; img<images.length; img++) {
int posx=0, posy=0;
int sizex = images[img].width;
int sizey = images[img].height;
System.out.println("Analysing image " + img);
for(int j=0; j<sizey/16;j++) {
for(int i=0; i<sizex/16;i++) {
VImage newTile = new VImage(16, 16);
newTile.grabRegion(posx, posy, posx+16, posy+16, 0, 0, images[img].image);
posx+=16;
// Checks for repeated tile
/*int repeated = 0;
for(BufferedImage bi: allTiles) {
for(int py=0;py<16;py++)
for(int px=0;px<16;px++)
if(bi.getRGB(px, py) == newTile.getRGB(px, py)) {
repeated++;
}
else
{px=20;py=20;}
}
if(repeated < 256)*/
allTiles.add(newTile);
/*else
allTiles.add(new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB));
repeated = 0;*/
}
posy+=16;
posx=0;
}
}
VImage clipboard = new VImage(512, (allTiles.size()/32+1) * 16);
Font font = new Font("Serif", Font.PLAIN, 7);
Vsp v = new Vsp();
v.tiles = new BufferedImage[allTiles.size()];
System.out.println("Got " + allTiles.size() + " tiles");
for(int i=0; i<allTiles.size(); i++) {
v.getTiles()[i] = allTiles.get(i).image;
clipboard.blit((i*16)%512, i/32*16, v.getTiles()[i]);
clipboard.printString((i*16)%512, i/32*16+16, font, Integer.toString(i));
}
clipboard.copyImageToClipboard();
v.numtiles = v.tiles.length;
v.obsPixels = new byte[512];
for(int i=0; i<512; i++) {
v.obsPixels[i] = (byte) ((i >= 256) ? 1: 0);
}
v.save("C:\\TEMP.VSP");
}
public int getNumtiles() {
return numtiles;
}
public BufferedImage [] getTiles() {
return tiles;
}
boolean GetObs(int t, int x, int y)
{
if (t==0) return false;
if (t>=numobs || t<0) return true;
if (x<0 || y<0 || x>15 || y>15) return true;
return obsPixels[(t*256)+(y*16)+x] == 0 ? false: true;
}
public boolean UpdateAnimations()
{
boolean animated = false;
while (mytimer < systemtime)
{
animated = AnimateTiles();
mytimer++;
}
return animated;
}
public void Blit(int x, int y, int index, VImage dest)
{
// tileidx[index] = the actual pointer to a tile, can change due to VSP animation
if (index >= getNumtiles() || tileidx[index] >= getNumtiles()) {
System.err.printf("VSP::BlitTile(), tile %d exceeds %d", index, getNumtiles());
return;
}
//if(systemtime%3!=0)
dest.blit(x, y, current_map.getTileSet().getTiles()[tileidx[index]]);
//dest.g.drawImage(current_map.tileset.tiles[index], x, y, Color.BLACK, null);
// Faster, but doesn't support animations
/*Graphics2D g2 = (Graphics2D) dest.g;
g2.setPaint(new TexturePaint(current_map.tileset.tiles[index], new Rectangle(x,y,16,16)));
g2.fillRect(x,y,16,16);*/
}
public void TBlit(int x, int y, int index, VImage dest)
{
/*while (mytimer < systemtime)
{
AnimateTiles();
mytimer++;
}*/
//if (index >= numtiles) err("VSP::BlitTile(), tile %d exceeds %d", index, numtiles);
if (index >= getNumtiles() || tileidx[index] >= getNumtiles()) {
System.err.printf("VSP::TBlitTile(), tile %d exceeds %d", index, getNumtiles());
return;
}
dest.tblit(x, y, current_map.getTileSet().getTiles()[tileidx[index]]);
//dest.g.drawImage(current_map.tileset.tiles[index], x, y, null);
}
void BlitObs(int x, int y, int index, VImage dest)
{
if (index >= numobs) return;
//[Rafael, the Esper] char c[] = (char) obs + (index * 256);
//[Rafael, the Esper] int white = MakeColor(255,255,255);
for (int yy=0; yy<16; yy++)
for (int xx=0; xx<16; xx++)
;//[Rafael, the Esper] if (c[(yy*16)+xx]>0) PutPixel(x+xx, y+yy, white, dest);
}
void AnimateTile(int i, int l)
{
switch (anims[i].mode)
{
case ANIM_MODE_FORWARD:
if (tileidx[l]<anims[i].finish) tileidx[l]++;
else tileidx[l]=anims[i].start;
break;
case ANIM_MODE_BACKWARD:
if (tileidx[l]>anims[i].start) tileidx[l]--;
else tileidx[l]=anims[i].finish;
break;
case ANIM_MODE_RANDOM:
tileidx[l]=Script.random(anims[i].start, anims[i].finish);
break;
case ANIM_MODE_PINGPONG:
if (flipped[l]>0)
{
if (tileidx[l]!=anims[i].start) tileidx[l]--;
else { tileidx[l]++; flipped[l]=0; }
}
else
{
if (tileidx[l]!=anims[i].finish) tileidx[l]++;
else { tileidx[l]--; flipped[l]=1; }
}
break;
}
}
boolean AnimateTiles()
{
boolean animated = false;
for (int i=0; i<anims.length; i++)
{
if(anims[i] == null || vadelay==null) // [Rafael, the Esper]
return animated;
if ((anims[i].delay>0) && (anims[i].delay<vadelay[i]))
{
vadelay[i]=0;
animated = true;
for (int l=anims[i].start; l<=anims[i].finish; l++)
AnimateTile(i,l);
}
vadelay[i]++;
}
return animated;
}
void ValidateAnimations()
{
for (int i=0; i<anims.length; i++)
if (anims[i].start<0 || anims[i].start>=getNumtiles() || anims[i].finish<0 || anims[i].finish>=getNumtiles())
System.err.printf("VSP::ValidateAnimations() - animation %d references out of index tiles", i);
}
public class Animation {
public String name = "";
public int start = 0, finish = 0;
public int delay, mode;
public String toString() {
return "Animation: " + name + "; startTile:" + start + "; endTile:" + finish + "; delay:" + delay + "; mode: " + mode;
}
}
}