/* vim:expandtab:ts=2 sw=2:
*/
/* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2011 Yves Rizoud
Copyright 2010-2011 Adrien Destugues
Grafx2 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
Grafx2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grafx2; if not, see
*/
#include "struct.h"
#include "global.h"
#include "graph.h"
#include "sdlscreen.h"
#include "engine.h"
#include "windows.h"
#include "input.h"
#include "misc.h"
#include "tiles.h"
// These helpers are only needed internally at the moment
#define TILE_FOR_COORDS(x,y) (((y)-Snap_offset_Y)/Snap_height*Main.tilemap_width+((x)-Snap_offset_X)/Snap_width)
#define TILE_AT(x,y) (y)*Main.tilemap_width+(x)
#define TILE_X(t) (((t)%Main.tilemap_width)*Snap_width+Snap_offset_X)
#define TILE_Y(t) (((t)/Main.tilemap_width)*Snap_height+Snap_offset_Y)
enum TILE_FLIPPED
{
TILE_FLIPPED_NONE = 0,
TILE_FLIPPED_X = 1,
TILE_FLIPPED_Y = 2,
TILE_FLIPPED_XY = 3, // needs be TILE_FLIPPED_X|TILE_FLIPPED_Y
};
// globals
///
/// Draw a pixel while Tilemap mode is active : This will paint on all
/// similar tiles of the layer, visible on the screen or not.
void Tilemap_draw(word x, word y, byte color)
{
int tile, first_tile;
int rel_x, rel_y;
if (x < Snap_offset_X
|| y < Snap_offset_Y
|| x >= Snap_offset_X + Main.tilemap_width*Snap_width
|| y >= Snap_offset_Y + Main.tilemap_height*Snap_height)
return;
tile = first_tile = TILE_FOR_COORDS(x,y);
rel_x = (x - Snap_offset_X + Snap_width) % Snap_width;
rel_y = (y - Snap_offset_Y + Snap_height) % Snap_height;
do
{
int xx,yy;
switch(Main.tilemap[tile].Flipped ^ Main.tilemap[first_tile].Flipped)
{
case 0: // no
default:
xx = (tile % Main.tilemap_width)*Snap_width+Snap_offset_X + rel_x;
yy = (tile / Main.tilemap_width)*Snap_height+Snap_offset_Y + rel_y;
break;
case 1: // horizontal
xx = (tile % Main.tilemap_width)*Snap_width+Snap_offset_X + Snap_width-rel_x-1;
yy = (tile / Main.tilemap_width)*Snap_height+Snap_offset_Y + rel_y;
break;
case 2: // vertical
xx = (tile % Main.tilemap_width)*Snap_width+Snap_offset_X + rel_x;
yy = (tile / Main.tilemap_width)*Snap_height+Snap_offset_Y + Snap_height - rel_y - 1;
break;
case 3: // both
xx = (tile % Main.tilemap_width)*Snap_width+Snap_offset_X + Snap_width-rel_x-1;
yy = (tile / Main.tilemap_width)*Snap_height+Snap_offset_Y + Snap_height - rel_y - 1;
break;
}
if (yy>=Limit_top&&yy<=Limit_bottom&&xx>=Limit_left&&xx<=Limit_right)
Pixel_in_current_screen_with_preview(xx,yy,color);
else
Pixel_in_current_screen(xx,yy,color);
tile = Main.tilemap[tile].Next;
} while (tile != first_tile);
Update_rect(0,0,0,0);
}
///
int Tile_is_same(int t1, int t2)
{
byte *bmp1,*bmp2;
int y;
bmp1 = Main.backups->Pages->Image[Main.current_layer].Pixels+(TILE_Y(t1))*Main.image_width+(TILE_X(t1));
bmp2 = Main.backups->Pages->Image[Main.current_layer].Pixels+(TILE_Y(t2))*Main.image_width+(TILE_X(t2));
for (y=0; y < Snap_height; y++)
{
if (memcmp(bmp1+y*Main.image_width, bmp2+y*Main.image_width, Snap_width))
return 0;
}
return 1;
}
///
int Tile_is_same_flipped_x(int t1, int t2)
{
byte *bmp1,*bmp2;
int y, x;
bmp1 = Main.backups->Pages->Image[Main.current_layer].Pixels+(TILE_Y(t1))*Main.image_width+(TILE_X(t1));
bmp2 = Main.backups->Pages->Image[Main.current_layer].Pixels+(TILE_Y(t2))*Main.image_width+(TILE_X(t2)+Snap_width-1);
for (y=0; y < Snap_height; y++)
{
for (x=0; x < Snap_width; x++)
if (*(bmp1+y*Main.image_width+x) != *(bmp2+y*Main.image_width-x))
return 0;
}
return 1;
}
///
int Tile_is_same_flipped_y(int t1, int t2)
{
byte *bmp1,*bmp2;
int y;
bmp1 = Main.backups->Pages->Image[Main.current_layer].Pixels+(TILE_Y(t1))*Main.image_width+(TILE_X(t1));
bmp2 = Main.backups->Pages->Image[Main.current_layer].Pixels+(TILE_Y(t2)+Snap_height-1)*Main.image_width+(TILE_X(t2));
for (y=0; y < Snap_height; y++)
{
if (memcmp(bmp1+y*Main.image_width, bmp2-y*Main.image_width, Snap_width))
return 0;
}
return 1;
}
///
int Tile_is_same_flipped_xy(int t1, int t2)
{
byte *bmp1,*bmp2;
int y, x;
bmp1 = Main.backups->Pages->Image[Main.current_layer].Pixels+(TILE_Y(t1))*Main.image_width+(TILE_X(t1));
bmp2 = Main.backups->Pages->Image[Main.current_layer].Pixels+(TILE_Y(t2)+Snap_height-1)*Main.image_width+(TILE_X(t2)+Snap_width-1);
for (y=0; y < Snap_height; y++)
{
for (x=0; x < Snap_width; x++)
if (*(bmp1+y*Main.image_width+x) != *(bmp2-y*Main.image_width-x))
return 0;
}
return 1;
}
/// Create or update a tilemap based on current screen (layer)'s pixels.
void Tilemap_update(void)
{
int width;
int height;
int tile;
int count=1;
T_Tile * tile_ptr;
int wait_window=0;
byte old_cursor=0;
if (!Main.tilemap_mode)
return;
width=(Main.image_width-Snap_offset_X)/Snap_width;
height=(Main.image_height-Snap_offset_Y)/Snap_height;
if (width<1 || height<1 || width*height>1000000l
|| (tile_ptr=(T_Tile *)malloc(width*height*sizeof(T_Tile))) == NULL)
{
// Cannot enable tilemap because either the image is too small
// for the grid settings (and I don't want to implement partial tiles)
// Or the number of tiles seems unreasonable (one million) : This can
// happen if you set grid 1x1 for example.
Disable_tilemap(&Main);
return;
}
if (Main.tilemap)
{
// Recycle existing tilemap
free(Main.tilemap);
Main.tilemap=NULL;
}
Main.tilemap=tile_ptr;
Main.tilemap_width=width;
Main.tilemap_height=height;
if (width*height > 1000 || Config.Tilemap_show_count)
{
wait_window=1;
old_cursor=Cursor_shape;
Open_window(180,36,"Creating tileset");
Print_in_window(26, 20, "Please wait...",MC_Black,MC_Light);
Cursor_shape=CURSOR_SHAPE_HOURGLASS;
Update_window_area(0,0,Window_width, Window_height);
Display_cursor();
Get_input(0);
}
// Initialize array with all tiles unique by default
for (tile=0; tiletilemap)
{
// Recycle existing tilemap
free(doc->tilemap);
doc->tilemap=NULL;
}
doc->tilemap_width=0;
doc->tilemap_height=0;
doc->tilemap_mode=0;
}