/*
* JavaXYQ Engine
*
* javaxyq@2008 all rights.
* http://www.javaxyq.com
*/
package com.javaxyq.widget;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.*;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.imageio.ImageIO;
import com.javaxyq.config.MapConfig;
import com.javaxyq.core.GameMain;
import com.javaxyq.resources.DefaultTileMapProvider;
import com.javaxyq.resources.MapUnit;
import com.javaxyq.resources.MaskUnit;
import com.javaxyq.widget.Player;
/**
* @author ����ΰ
* @history 2008-5-22 ����ΰ �½�
* 2013-12-25 wpaul modify
*/
public class TileMap extends AbstractWidget {
/** ��ͼ�����ؿ�� */
public static final int MAP_BLOCK_WIDTH = 320;
/** ��ͼ�����ظ߶� */
public static final int MAP_BLOCK_HEIGHT = 240;
public static final int STEP_DISTANCE = 20;
private DefaultTileMapProvider provider;
private SoftReference<Image>[][] blockTable;
/** ��ͼX������� */
private int xBlockCount;
/** ��ͼY������� */
private int yBlockCount;
// private int offsetX;
// private int offsetY;
// private int firstTileX;
// private int lastTileX;
// private int firstTileY;
// private int lastTileY;
private int width;
private int height;
private MapConfig config;
private int lastCount;
//�ӵ�ͼCell����
private byte [][] cellData;
// �ӵ�ͼ��maskͼ ����
private MaskUnit[] maskUnits;
private BufferedImage[] tileImageDes;
private ColorModel cm;
private Object data;
private int[] des;
/**
* ����TileMap
* �����ӵ�ͼtileImage
* ����MASK����ͼtileImageDes
*/
public TileMap(DefaultTileMapProvider provider, MapConfig cfg) {
//ˮƽ����w�飬��ֱ����h��
this.config = cfg;
this.xBlockCount = provider.getXBlockCount();
this.yBlockCount = provider.getYBlockCount();
this.width = provider.getWidth();
this.height = provider.getHeight();
blockTable = new SoftReference[this.xBlockCount][this.yBlockCount];
this.provider = provider;
//totalcell��ʼ��
int wbol,hbol;
if(width%320==0){
wbol=0;
}else{
wbol=1;
}
if(height%240==0){
hbol=0;
}else{
hbol=1;
}
int swidth = (width / 320 + wbol) * 320/STEP_DISTANCE;
int sheight = (height / 240 + hbol) * 240/STEP_DISTANCE;
cellData = new byte[sheight][swidth];
//mask���أ�
tileImageDes = new BufferedImage[provider.getMaskCount()];
maskUnits = new MaskUnit[provider.getMaskCount()];
// rasterDes = new WritableRaster[provider.offsetlsize];
// tiles = new ArrayList<Object>();
//cell= new boolean[(int) rMap.m_SubMapRowNum][(int) rMap.m_SubMapColNum][12][16];
// maskkey= new ArrayList<int[]>();
// mask = new ArrayList<int[]>();
// mask_data = new ArrayList<int[]>();
// m_anteroposterior = new int[provider.getWidth()][provider.getHeight()];
// mapwidth=width;
//mapheight=height;
//ȷ����������
int b=yBlockCount;
int a=xBlockCount;
//System.out.println("a,b is:"+a+","+b);
//��ȡ�ӵ�ͼ
for(int y=0;y<yBlockCount;y++){
for(int x=0;x<xBlockCount;x++){
MapUnit mapUnit = provider.ReadUnit(x,y);
//�ӵ�ͼ�ϳ�cell
byte[] cellData = mapUnit.getCellData();
for(int ch=0;ch<12;ch++){
for(int cw=0;cw<16;cw++){
//System.out.println(provider.m_cell[c]);
//totalcell[((12*y+ch)*16*xBlockCount)+(16*x+cw)] = provider.m_cell[ch*16+cw];
this.cellData[y*12+ch][x*16+cw]=cellData[ch*16+cw];
}
}
//tiles.add(tileImage);
}
}
}
/**
* ����totalRaster��KEYX,KEYY������
* ��rasterDes�� ���ж��Ƿ�drawmask
*/
//maskͼ�����ǩ
public void loadMask(int viewX,int viewY){
//��ʼ��MASK����ͼ�����
int firstTilex = pixelsToTilesw(viewX);
int lastTilex = pixelsToTilesw(viewX + MAP_BLOCK_WIDTH*2);
int firstTiley = pixelsToTilesh(viewY);
int lastTiley = pixelsToTilesh(viewY + MAP_BLOCK_HEIGHT*3);
lastTilex=Math.min(lastTilex, (int)(provider.getXBlockCount()-1));
lastTiley=Math.min(lastTiley, (int)provider.getYBlockCount());
//System.out.println("fistX,Y is:"+firstTilex+","+firstTiley);
//System.out.println("lastX,Y is:"+lastTilex+","+lastTiley);
//��ȡ��ͼmask��Ϣ;
for (int y = firstTiley; y <lastTiley; y++) {
for (int x = firstTilex; x <= lastTilex; x++) {
int unitnum = (y*xBlockCount+x);
//System.out.println("unitnum"+ "is:"+unitnum);
MapUnit mapUnit = provider.ReadUnit(x, y);
int []masknum = mapUnit.getMaskIndexs();
for(int i=0;i<masknum.length;i++){
int maskIndex = masknum[i];
if(tileImageDes[maskIndex] != null) {
continue;
}
MaskUnit maskUnit = getMaskUnit(maskIndex);
createTileMaskImg(masknum[i],maskUnit.getX(),maskUnit.getY(),maskUnit.getWidth(),
maskUnit.getHeight(), maskUnit.getData());
}
}
}
//TODO �ͷ�û��ʾ��maskͼ��
}
private MaskUnit getMaskUnit(int maskIndex) {
MaskUnit maskUnit = maskUnits[maskIndex];
if(maskUnit == null) {
maskUnit = provider.ReadMask(maskIndex);
maskUnits[maskIndex] = maskUnit;
}
return maskUnit;
}
private void createTileMaskImg(int unitnum,int keyx,int keyy,int width,int height,int []mask){
if(tileImageDes[unitnum] != null) {
return;
}
// tileImageDes[unitnum] = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
int firstTilex = pixelsToTilesw(keyx);
int lastTilex = pixelsToTilesw(keyx + width - 1);
int firstTiley = pixelsToTilesh(keyy);
int lastTiley = pixelsToTilesh(keyy + height - 1);
// lastTileX=Math.min(lastTileX, (int)(rMap.m_SubMapRowNum-1));
// lastTileY=Math.min(lastTileY, (int)rMap.m_SubMapColNum);
//System.out.println("fistX,Y is:"+firstTilex+","+firstTiley);
//System.out.println("lastX,Y is:"+lastTilex+","+lastTiley);
//�ϲ��ӵ�ͼ���������ֵ��
BufferedImage tempMaskImage = new BufferedImage((lastTilex+1-firstTilex)*320,
(lastTiley+1-firstTiley)*240,BufferedImage.TYPE_3BYTE_BGR);
WritableRaster tempMaskRaster = tempMaskImage.getRaster();
for (int y = firstTiley; y < lastTiley+1; y++) {
for (int x = firstTilex; x < lastTilex+1; x++) {
try {
//��ȡIMAGE����
InputStream buffin = new ByteArrayInputStream(provider.getJpegData(x, y));
BufferedImage Image= ImageIO.read(buffin);
Raster raster = Image.getRaster();
//�ϲ�raster���ؾ���
//System.out.println("x,y is:"+320*(x-firstTilex)+","+240*(y-firstTiley));
//System.out.println("num is:"+(y*xBlockCount+x));
tempMaskRaster.setRect(320*(x-firstTilex), 240*(y-firstTiley),
raster);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
writerRaster(tempMaskImage,tempMaskRaster,unitnum,keyx,keyy,width,height,mask);
//���ͼ��
// String name ="mask/"+unitnum+".png";
// try {
// File jpegdata=new File(name);
// jpegdata.getParentFile().mkdirs();
// FileOutputStream fout =new FileOutputStream(jpegdata);
// ImageIO.write(tileImageDes[unitnum], "png", fout);
// fout.close();
// } catch (IOException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
}
//maskͼ�����ǩ
private void writerRaster(BufferedImage tempMaskImage,WritableRaster tempMaskRaster,
int num,int keyx,int keyy,int width,int height,int []mask){
if(tileImageDes[num] != null) {
return;
}
tileImageDes[num] = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
cm = tempMaskImage.getColorModel();
// data = null;
//int m=0;
des = new int [4];
//System.out.println("keyx,keyy is:"+keyx+","+keyy);
//System.out.println("width,height is:"+width+","+height);
for(int h=0;h<height;h++){
for(int w=0;w<width;w++){
//System.out.println("rgb is:");
//data = totalRaster.getDataElements(keyx+w, keyy+h, null);
//int rgb=cm.getRGB(data);
//System.out.println("x,y is:"+(keyx+w)+","+(keyy+h));
data = tempMaskRaster.getDataElements(keyx%320+w,keyy%240+h, null);
int rgb = cm.getRGB(data);
int sr,sg,sb;
sr = (rgb & 0xFF0000)>>16;
sg = (rgb & 0xFF00)>>8;
sb = rgb & 0xFF;
des[0]=sr;
des[1]=sg;
des[2]=sb;
if(mask[h*width+w]==3){
des[3]=110;
}else if(mask[h*width+w] == 1){
des[0]=0;
des[1]=0;
des[2]=0;
des[3]=0;
}
else{
des[3]=0;
}
//rasterDes[num].setPixel(w, h, des);
WritableRaster raster = tileImageDes[num].getRaster();
raster.setPixel(w, h, des);
}
}
}
@Override
protected void doDraw(Graphics2D g2, int x, int y, int width, int height) {
// 1.����Rect���ڵ�ͼ��
Point pFirstBlock = viewToBlock(x, y);
// 2.�����һ���ͼ���ViewRect��ƫ����,����Graphicsƫ��
int dx = pFirstBlock.x * MAP_BLOCK_WIDTH - x;
int dy = pFirstBlock.y * MAP_BLOCK_HEIGHT - y;
//System.out.println("x,y is:"+dx+","+dy);
//System.out.println("x,y is:"+pFirstBlock.x+","+pFirstBlock.y);
g2.translate(dx, dy);
//System.out.printf("x=%s,y=%s,dx=%s,dy=%s,block=%s\n", x, y, dx, dy, pFirstBlock);
// 3.����X��,Y�᷽����Ҫ�ĵ�ͼ������
int offsetX = x;
int offsetY = y;
int firstTileX = pixelsToTilesw(offsetX);
int lastTileX = pixelsToTilesw(offsetX + MAP_BLOCK_WIDTH*2);
int firstTileY = pixelsToTilesh(offsetY);
int lastTileY = pixelsToTilesh(offsetY + MAP_BLOCK_HEIGHT*3);
lastTileX=Math.min(lastTileX, (int)(provider.getXBlockCount()-1));
lastTileY=Math.min(lastTileY, (int)provider.getYBlockCount());
//System.out.printf("xCount=%s,yCount=%s\n",xCount,yCount);
// 4.�ӻ����ȡ��ͼ��,����Graphics��
for (int i = firstTileX; i <= lastTileX; i++) {
for (int j = firstTileY; j < lastTileY; j++) {
//System.out.println("i , j is:"+i+","+j);
Image b = getBlock(i , j );
//Image b = tileImage[j*xBlockCount+i];
//System.out.println("b width is:"+b.getWidth(null));
g2.drawImage(b, (i-firstTileX)*MAP_BLOCK_WIDTH,
(j-firstTileY)*MAP_BLOCK_HEIGHT, null);
}
}
loadMask(x, y);
}
/**
* ����MASKǰ�����ݹ�ϵ
* �ж��Ƿ�drawmask
*/
public void drawMask(Player player,int pcoordx,int pcoordy, Graphics g,int viewx, int viewy, int offsetX, int offsetY) {
// 1.����Rect���ڵ�ͼ��
/* Point pFirstBlock = viewToBlock(x, y);
// 2.�����һ���ͼ���ViewRect��ƫ����,����Graphicsƫ��
int dx = pFirstBlock.x * MAP_BLOCK_WIDTH - x;
int dy = pFirstBlock.y * MAP_BLOCK_HEIGHT - y;*/
//System.out.println("x,y is:"+pFirstBlock.x+","+pFirstBlock.y);
//g2.translate(dx, dy);
//System.out.printf("x=%s,y=%s,dx=%s,dy=%s,block=%s\n", x, y, dx, dy, pFirstBlock);
// 3.����X��,Y�᷽����Ҫ�ĵ�ͼ������
// doDraw�Ѽ���
//System.out.printf("xCount=%s,yCount=%s\n",xCount,yCount);
// 4.�ӻ����ȡ��ͼ��,����Graphics��
//��ȡplayer��Ϣ��������
int pkeyx = player.getRefPixelX(); //person RefPixelX
int pOffsetX = pcoordx- pkeyx;
int pkeyy = player.getRefPixelY();//person RefPixelY
int pOffsetY = pcoordy- pkeyy;
int pwidth = player.getWidth();//person width
int pheight = player.getHeight(); //person height
int offsetx = viewx;
int offsety = viewy;
int firstTileX = pixelsToTilesw(offsetx);
int lastTileX = pixelsToTilesw(offsetx + MAP_BLOCK_WIDTH*2);
int firstTileY = pixelsToTilesh(offsety);
int lastTileY = pixelsToTilesh(offsety + MAP_BLOCK_HEIGHT*3);
lastTileX=Math.min(lastTileX, (int)(provider.getXBlockCount()-1));
lastTileY=Math.min(lastTileY, (int)provider.getYBlockCount());
//System.out.println("firstx,y is:"+firstTileX+","+firstTileY);
//System.out.println("lastx,y is:"+lastTileX+","+lastTileY);
//System.out.printf("xCount=%s,yCount=%s\n",xCount,yCount);
Set<Integer> paintedMaskSet = new HashSet<Integer>();
// 4.�ӻ����ȡ��ͼ��,����Graphics��
for (int y = firstTileY; y < lastTileY; y++) {
for (int x = firstTileX; x <= lastTileX; x++) {
// int unitnum = (y*xBlockCount+x);
//System.out.println("unitnum"+ "is:"+unitnum);
MapUnit mapUnit = provider.ReadUnit(x, y);
int[] masknum = mapUnit.getMaskIndexs();
//System.out.println("mapUnit: ("+x+","+y+")"+", maskIndex: "+Arrays.toString(masknum));
for(int i=0;i<masknum.length;i++){
int maskIndex = masknum[i];
//��ֹ�ظ�����ͬһ��mask
if(paintedMaskSet.contains(maskIndex)) {
continue;
}
paintedMaskSet.add(maskIndex);
MaskUnit maskUnit = getMaskUnit(maskIndex);
int []maskdata = maskUnit.getData();
//this.createTileMaskImg(maskIndex, maskUnit.getX(), maskUnit.getY(), maskUnit.getWidth(),
// maskUnit.getHeight(), maskdata);
//���mask�Ƿ��ס�������NPC
boolean bDrawMask = true;//false;
if(pcoordx<=maskUnit.getX()+maskUnit.getWidth()-1 && pcoordx>=maskUnit.getX()){
bDrawMask = true;
int length = maskUnit.getWidth()*maskUnit.getHeight();
if(maskUnit.getY()+maskUnit.getHeight() < pcoordy ){
for(int l=length-maskUnit.getWidth()-1;l<length;l++){
if(maskdata[l]==1){
bDrawMask=false;
}
}
}else if(maskUnit.getY()+maskUnit.getHeight() > pcoordy){
int row = pcoordy-maskUnit.getY();
for(int l=row*(maskUnit.getWidth()-1);l<row*maskUnit.getWidth();l++){
if(maskdata[l]==1){
bDrawMask=false;
}
}
}
}else if(pcoordx<maskUnit.getX() && pOffsetX+pwidth>maskUnit.getX()){
bDrawMask = true;
int length = maskUnit.getWidth()*maskUnit.getHeight();
if(maskUnit.getY()+maskUnit.getHeight() < pcoordy ){
int col = maskUnit.getX()+maskUnit.getWidth()-(pOffsetX+pwidth);
for(int l=length-maskUnit.getWidth()-1;l<Math.min(length-col, length);l++){
if(maskdata[l]==1){
bDrawMask=false;
}
}
}else if(maskUnit.getY()+maskUnit.getHeight() > pcoordy && pcoordy>maskUnit.getY()){
int col = maskUnit.getX()+maskUnit.getWidth()-(pOffsetX+pwidth);
int row = pcoordy-maskUnit.getY();
for(int l=row*(maskUnit.getWidth()-1);
l<Math.min(row*maskUnit.getWidth()-col,row*maskUnit.getWidth());l++){
if(maskdata[l]==1){
bDrawMask=false;
}
}
}
}else if(pcoordx>maskUnit.getX()+maskUnit.getWidth()-1 &&
pOffsetX<maskUnit.getX()+maskUnit.getWidth()-1){
bDrawMask = true;
int length = maskUnit.getWidth()*maskUnit.getHeight();
if(maskUnit.getY()+maskUnit.getHeight() < pcoordy ){
int col = maskUnit.getX()+maskUnit.getWidth()-pOffsetX;
for(int l=length-Math.min(col,maskUnit.getWidth());l<length;l++){
if(maskdata[l]==1){
bDrawMask=false;
}
}
}else if(maskUnit.getY()+maskUnit.getHeight() > pcoordy && pcoordy>maskUnit.getY()){
int col = maskUnit.getX()+maskUnit.getWidth()-pOffsetX;
int row = pcoordy-maskUnit.getY();
for(int l=Math.max(row*maskUnit.getWidth()-col, maskUnit.getX());
l<row*maskUnit.getWidth();l++){
if(maskdata[l]==1){
bDrawMask=false;
}
}
}
}
if(bDrawMask){
g.drawImage(this.tileImageDes[maskIndex], maskUnit.getX()-viewx,
maskUnit.getY()-viewy,null);
}
}
}
}
}
/**
* Ԥ���ش�����ĵ�ͼ��
*
* @param x
* @param y
* @param width
* @param height
*/
public void prepare(int x, int y, int width, int height) {
// 1.����Rect���ڵ�ͼ��
Point pFirstBlock = viewToBlock(x, y);
// 2.�����һ���ͼ���ViewRect��ƫ����,����Graphicsƫ��
int dx = pFirstBlock.x * MAP_BLOCK_WIDTH - x;
int dy = pFirstBlock.y * MAP_BLOCK_HEIGHT - y;
//System.out.printf("x=%s,y=%s,dx=%s,dy=%s,block=%s\n", x, y, dx, dy, pFirstBlock);
// 3.����X��,Y�᷽����Ҫ�ĵ�ͼ������
int xCount = 1 + (width - dx - 1) / MAP_BLOCK_WIDTH;
int yCount = 1 + (height - dy - 1) / MAP_BLOCK_HEIGHT;
//System.out.printf("xCount=%s,yCount=%s\n",xCount,yCount);
// 4.���������ĵ�ͼ��
Image[][] images = new Image[xCount][yCount];
for (int i = 0; i < xCount; i++) {
for (int j = 0; j < yCount; j++) {
Image img = getBlock(i + pFirstBlock.x, j + pFirstBlock.y);
images[i][j] = img;
}
}
}
private int checkTable() {
int count = 0;
int width = this.blockTable.length;
int height = this.blockTable[0].length;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
SoftReference<Image> reference = this.blockTable[i][j];
if (reference != null && reference.get() != null) {
count++;
}
}
}
// if (count != lastCount) {
// System.out.printf("map loaded block count: %s \n", count);
// }
lastCount = count;
return count;
}
private Image getBlock(int x, int y) {
SoftReference<Image> reference = this.blockTable[x][y];
//����˵�ͼ�黹û����,��ȡ��ͼ�����ݲ�����ͼ��
//���GC���ڵ��ڴ�,���ͷ�image,��Ҫ����װ��
if (reference == null || reference.get() == null) {
reference = new SoftReference<Image>(provider.getBlock(x, y));
this.blockTable[x][y] = reference;
}
this.checkTable();
return reference.get();
}
public int getXBlockCount() {
return xBlockCount;
}
public void setXBlockCount(int blockCount) {
xBlockCount = blockCount;
}
public int getYBlockCount() {
return yBlockCount;
}
public void setYBlockCount(int blockCount) {
yBlockCount = blockCount;
}
public int tileswToPixels(int numTiles) {
int pixelSize = numTiles * MAP_BLOCK_WIDTH ;
return pixelSize;
}
public int pixelsToTilesw(int pixelCoord) {
int numTiles = pixelCoord / MAP_BLOCK_WIDTH ;
return numTiles;
}
public int tileshToPixels(int numTiles){
int pixelSize = numTiles * MAP_BLOCK_HEIGHT ;
return pixelSize;
}
public int pixelsToTilesh(int pixelCoord) {
int numTiles = pixelCoord / MAP_BLOCK_HEIGHT ;
return numTiles;
}
/**
* ����view����vp���Ӧ�ĵ�ͼ���ݿ�λ�� ����vp�������ĸ���ͼ���ϣ�
*
* @param vp view's top left position
* @return the map block index of the vp
*/
private Point viewToBlock(int x, int y) {
Point p = new Point();
p.x = x / MAP_BLOCK_WIDTH;
p.y = y / MAP_BLOCK_HEIGHT;
if (p.x < 0)
p.x = 0;
if (p.y < 0)
p.y = 0;
return p;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public void dispose() {
this.provider.dispose();
this.provider = null;
for (SoftReference<Image>[] refs : this.blockTable) {
for (SoftReference<Image> ref : refs) {
if (ref != null) {
ref.clear();
}
}
}
this.blockTable = null;
}
public MapConfig getConfig() {
return config;
}
public void setConfig(MapConfig config) {
this.config = config;
}
public boolean contains(int x, int y) {
return true;
}
public byte[][] getCellData() {
return cellData;
}
}