663 lines
23 KiB
C++
663 lines
23 KiB
C++
#include <SDL2/SDL.h>
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#include "stb_image.h"
|
|
#include "font.h"
|
|
#include "gif.c"
|
|
#include <stdio.h>
|
|
|
|
#define STATE_TILEMAP 0
|
|
#define STATE_TILEPAL 1
|
|
#define STATE_MINIMAP 2
|
|
|
|
#define MOUSE_BUTTON_LEFT 0
|
|
#define MOUSE_BUTTON_MIDDLE 1
|
|
#define MOUSE_BUTTON_RIGHT 2
|
|
|
|
#ifdef __APPLE__
|
|
#define CTRL SDL_SCANCODE_LGUI
|
|
#else
|
|
#define CTRL SDL_SCANCODE_LCTRL
|
|
#endif
|
|
|
|
struct Mouse {
|
|
int x, y;
|
|
bool buttons[3];
|
|
bool mouse_down[3];
|
|
bool mouse_up[3];
|
|
bool mouse_old[3];
|
|
};
|
|
|
|
typedef bool(*LoopFun)(void);
|
|
|
|
SDL_Window* sdlWindow = NULL;
|
|
SDL_Renderer* sdlRenderer = NULL;
|
|
SDL_Texture* sdlFontTexture = NULL;
|
|
SDL_Texture* sdlTilesTexture = NULL;
|
|
SDL_Texture* sdlMinimapTexture = NULL;
|
|
SDL_Event sdlEvent;
|
|
SDL_Scancode keyJustPressed = SDL_SCANCODE_UNKNOWN;
|
|
const Uint8* keyboard = nullptr;
|
|
Uint32* minitiles = nullptr;
|
|
bool ignoreMouse = false;
|
|
bool anyKey = false;
|
|
LoopFun loop;
|
|
Mouse mouse;
|
|
int error = 0;
|
|
int dialog = 0;
|
|
int state = STATE_TILEMAP;
|
|
|
|
int tile_width = 16;
|
|
int tile_height = 16;
|
|
int map_width = 240;
|
|
int map_height = 240;
|
|
int screen_width = 256;
|
|
int screen_height = 192;
|
|
int zoom = 2;
|
|
char tiles_filename[100] = { 0 };
|
|
char map_filename[100] = { 0 };
|
|
int tilemap_width = 0;
|
|
int tilemap_height = 0;
|
|
|
|
char path[400] = {0};
|
|
|
|
unsigned char* map = nullptr;
|
|
int map_x = 0;
|
|
int map_y = 0;
|
|
|
|
#define UNDO_MAX 16
|
|
unsigned char* undo = nullptr;
|
|
int undo_pointer = 0;
|
|
int undo_min = 0;
|
|
int undo_max = 0;
|
|
|
|
int tile_sel = 0;
|
|
int tile_back = 0;
|
|
|
|
int sprites = 208;
|
|
|
|
const char* GetPath(const char* filename) {
|
|
#ifdef __APPLE__
|
|
static char fullpath[400];
|
|
strcpy(fullpath, path);
|
|
strcat(fullpath, filename);
|
|
return fullpath;
|
|
#else
|
|
return filename;
|
|
#endif
|
|
}
|
|
|
|
int StrToInt(const char* str) {
|
|
int val = 0;
|
|
int size = strlen(str);
|
|
for (int i = 0; i < size; i++) {
|
|
if (str[i] < 48 || str[i] > 57) return 0;
|
|
val = val * 10 + (str[i] - 48);
|
|
}
|
|
return val;
|
|
}
|
|
|
|
#define UndoInc(var) (var = (var+1)%UNDO_MAX)
|
|
#define UndoDec(var) (var = (var-1+UNDO_MAX)%UNDO_MAX)
|
|
void Undo_Create(const bool actor) {
|
|
unsigned char* dest = undo + ((map_width*map_height+1)*undo_pointer);
|
|
*dest = actor ? 1 : 0;
|
|
dest++;
|
|
unsigned char* src = actor ? map + (map_width*map_height) : map;
|
|
memcpy(dest, src, map_width*map_height);
|
|
}
|
|
void Undo_Restore() {
|
|
unsigned char* src = undo + ((map_width*map_height+1)*undo_pointer);
|
|
const bool actor = (*src == 1);
|
|
src++;
|
|
unsigned char* dest = actor ? map + (map_width*map_height) : map;
|
|
memcpy(dest, src, map_width*map_height);
|
|
}
|
|
void Undo_Op(const bool actor = false) {
|
|
UndoInc(undo_pointer);
|
|
Undo_Create(actor);
|
|
undo_max = undo_pointer;
|
|
if (undo_pointer == undo_min) UndoInc(undo_min);
|
|
}
|
|
void Undo_Undo() {
|
|
if (undo_pointer != undo_min) {
|
|
Undo_Restore();
|
|
UndoDec(undo_pointer);
|
|
}
|
|
}
|
|
void Undo_Redo() {
|
|
if (undo_pointer != undo_max) {
|
|
UndoInc(undo_pointer);
|
|
Undo_Restore();
|
|
}
|
|
}
|
|
|
|
void LoadConfig() {
|
|
FILE* f = fopen(GetPath("config.ini"), "r");
|
|
if (!f) { error = 1; return; }
|
|
char key[50];
|
|
char val[255];
|
|
while (!feof(f)) {
|
|
fscanf(f, "%s = %s", key, val);
|
|
if (strcmp(key, "tile_width") == 0) { tile_width = StrToInt(val); }
|
|
else if (strcmp(key, "tile_height") == 0) { tile_height = StrToInt(val); }
|
|
else if (strcmp(key, "map_width") == 0) { map_width = StrToInt(val); }
|
|
else if (strcmp(key, "map_height") == 0) { map_height = StrToInt(val); }
|
|
else if (strcmp(key, "screen_width") == 0) { screen_width = StrToInt(val); }
|
|
else if (strcmp(key, "screen_height") == 0) { screen_height = StrToInt(val); }
|
|
else if (strcmp(key, "zoom") == 0) { zoom = StrToInt(val); }
|
|
else if (strcmp(key, "tiles") == 0) { strcpy(tiles_filename, val); }
|
|
else if (strcmp(key, "map") == 0) { strcpy(map_filename, val); }
|
|
else if (strcmp(key, "sprites") == 0) { sprites = StrToInt(val); }
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
void UpdateMiniMap() {
|
|
const int tmtw = (tilemap_width / tile_width);
|
|
Uint32* pixels = (Uint32*)malloc(map_width * map_height*sizeof(Uint32));
|
|
for (int y = 0; y < map_height; y++) {
|
|
for (int x = 0; x < map_width; x++) {
|
|
const Uint8 tile = map[x + y*map_width];
|
|
pixels[x + y*map_width] = minitiles[(tile % tmtw) + (tile / tmtw)*tmtw];
|
|
}
|
|
}
|
|
SDL_UpdateTexture(sdlMinimapTexture, NULL, pixels, map_width * sizeof(Uint32));
|
|
free(pixels);
|
|
}
|
|
|
|
void Init() {
|
|
LoadConfig();
|
|
|
|
SDL_Init(SDL_INIT_EVERYTHING);
|
|
sdlWindow = SDL_CreateWindow("Mappy v0.3", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_width*zoom, screen_height*zoom, SDL_WINDOW_SHOWN);
|
|
sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, SDL_RENDERER_PRESENTVSYNC);
|
|
SDL_SetRenderDrawBlendMode(sdlRenderer, SDL_BLENDMODE_BLEND);
|
|
SDL_RenderSetLogicalSize(sdlRenderer, screen_width, screen_height);
|
|
|
|
unsigned short w, h;
|
|
unsigned char* buffer = LoadGif(font, &w, &h);
|
|
|
|
sdlFontTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, w, h);
|
|
Uint32* pixels = (Uint32*)malloc(w*h*sizeof(Uint32));
|
|
for (int i = 0; i < w*h; i++) { pixels[i] = buffer[i] == 0 ? 0x00000000 : 0xffffffff; }
|
|
SDL_UpdateTexture(sdlFontTexture, NULL, pixels, w * sizeof(Uint32));
|
|
SDL_SetTextureBlendMode(sdlFontTexture, SDL_BLENDMODE_BLEND);
|
|
free(buffer);
|
|
free(pixels);
|
|
|
|
int c;
|
|
FILE* f = fopen(GetPath(tiles_filename), "rb");
|
|
if (!f) { error = 2; return; }
|
|
buffer = stbi_load_from_file(f, &tilemap_width, &tilemap_height, &c, 4);
|
|
sdlTilesTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, tilemap_width, tilemap_height);
|
|
SDL_UpdateTexture(sdlTilesTexture, NULL, buffer, tilemap_width * sizeof(Uint32));
|
|
SDL_SetTextureBlendMode(sdlTilesTexture, SDL_BLENDMODE_BLEND);
|
|
fclose(f);
|
|
|
|
const int tmtw = (tilemap_width / tile_width);
|
|
const int tmth = (tilemap_height / tile_height);
|
|
minitiles = (Uint32*)malloc(tmtw * tmth*sizeof(Uint32));
|
|
for (int tmy = 0; tmy < tmth; tmy++) {
|
|
for (int tmx = 0; tmx < tmth; tmx++) {
|
|
const int bx = tmx*tile_width;
|
|
const int by = tmy*tile_height;
|
|
int r = 0, g = 0, b = 0;
|
|
for (int ty = 0; ty < tile_width; ty++) {
|
|
for (int tx = 0; tx < tile_height; tx++) {
|
|
const Uint32 offset = (bx + tx) * 4 + (by + ty)*(tilemap_width * 4);
|
|
r += buffer[offset];
|
|
g += buffer[offset+1];
|
|
b += buffer[offset+2];
|
|
}
|
|
}
|
|
r /= (tile_width*tile_height);
|
|
g /= (tile_width*tile_height);
|
|
b /= (tile_width*tile_height);
|
|
minitiles[tmx + tmy*tmtw] = 0xFF000000 + b + (g << 8) + (r << 16);
|
|
}
|
|
}
|
|
stbi_image_free(buffer);
|
|
|
|
f = fopen(GetPath(map_filename), "rb");
|
|
map = (unsigned char*)calloc(map_width*map_height*2, 1);
|
|
undo = (unsigned char*)malloc((map_width*map_height*UNDO_MAX)+UNDO_MAX);
|
|
if (f) {
|
|
int old_map_width = 0, old_map_height = 0;
|
|
fread(&old_map_width, 1, 1, f);
|
|
fread(&old_map_height, 1, 1, f);
|
|
if (old_map_width == map_width && old_map_height == map_height) {
|
|
fread(map, map_width*map_height*2, 1, f);
|
|
} else {
|
|
unsigned char* old_map = (unsigned char*)malloc(old_map_width*old_map_height);
|
|
fread(old_map, old_map_width*old_map_height*2, 1, f);
|
|
for (int y = 0; y < map_height; y++) {
|
|
for (int x = 0; x < map_width; x++) {
|
|
map[x + y*map_width] = 0;
|
|
map[(x + y*map_width)+(map_width*map_height)] = 0;
|
|
if (old_map_width > x && old_map_height > y && (x + y*map_width) < (old_map_width*old_map_height)) {
|
|
map[x + y*map_width] = old_map[x + y*(old_map_width)];
|
|
map[(x + y*map_width)+(map_width*map_height)] = old_map[(x + y*(old_map_width))+(old_map_width*old_map_height)];
|
|
}
|
|
}
|
|
}
|
|
dialog = 2;
|
|
}
|
|
fclose(f);
|
|
} else {
|
|
f = fopen(GetPath(map_filename), "wb");
|
|
if (!f) { error = 3; return; }
|
|
fwrite(&map_width, 1, 1, f);
|
|
fwrite(&map_height, 1, 1, f);
|
|
fwrite(map, map_width*map_height*2, 1, f);
|
|
fclose(f);
|
|
dialog = 1;
|
|
}
|
|
|
|
sdlMinimapTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, map_width, map_height);
|
|
UpdateMiniMap();
|
|
|
|
keyboard = SDL_GetKeyboardState(nullptr);
|
|
//SDL_Surface* bmp = SDL_LoadBMP("assets.bmp");
|
|
//texture = SDL_CreateTextureFromSurface(renderer, bmp);
|
|
//SDL_FreeSurface(bmp);
|
|
}
|
|
|
|
void Quit() {
|
|
SDL_DestroyTexture(sdlFontTexture);
|
|
SDL_DestroyRenderer(sdlRenderer);
|
|
SDL_DestroyWindow(sdlWindow);
|
|
SDL_Quit();
|
|
}
|
|
|
|
void Flip() { SDL_RenderPresent(sdlRenderer); }
|
|
void Clear() { SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255); SDL_RenderClear(sdlRenderer); }
|
|
|
|
void Draw(SDL_Texture* texture, int x, int y, int sx, int sy, int w, int h) {
|
|
SDL_Rect src, dst;
|
|
src.x = sx; src.y = sy;
|
|
dst.x = x; dst.y = y;
|
|
src.w = dst.w = w;
|
|
src.h = dst.h = h;
|
|
SDL_RenderCopy(sdlRenderer, texture, &src, &dst);
|
|
}
|
|
|
|
void FillRect(int x, int y, int w, int h, Uint8 r, Uint8 g, Uint8 b, Uint8 a = 255) {
|
|
SDL_Rect src;
|
|
src.x = x; src.y = y; src.w = w; src.h = h;
|
|
SDL_SetRenderDrawColor(sdlRenderer, r, g, b, a);
|
|
SDL_RenderFillRect(sdlRenderer, &src);
|
|
}
|
|
|
|
void DrawRect(int x, int y, int w, int h, Uint8 r, Uint8 g, Uint8 b, Uint8 a = 255) {
|
|
SDL_Rect src;
|
|
src.x = x; src.y = y; src.w = w; src.h = h;
|
|
SDL_SetRenderDrawColor(sdlRenderer, r, g, b, a);
|
|
SDL_RenderDrawRect(sdlRenderer, &src);
|
|
}
|
|
|
|
void Print(int x, int y, const char* text) {
|
|
int str_size = strlen(text);
|
|
for (int i = 0; i < str_size; i++) {
|
|
char chr = text[i] - 32;
|
|
Draw(sdlFontTexture, x + (i * 6), y, (chr & 0x0f) * 6, (chr >> 4) * 6, 6, 6);
|
|
}
|
|
}
|
|
|
|
bool Button(int x, int y, char* text) {
|
|
bool inside = (mouse.x >= x) && (mouse.y >= y) && (mouse.x < x + 55) && (mouse.y < y + 12);
|
|
if (inside) {
|
|
FillRect(x, y, 55, 13, 128, 64, 64, 255);
|
|
} else {
|
|
FillRect(x, y, 55, 13, 255, 64, 64, 255);
|
|
}
|
|
Print(x+4, y+4, text);
|
|
return inside && mouse.buttons[0];
|
|
}
|
|
|
|
bool Update() {
|
|
anyKey = false;
|
|
keyJustPressed = SDL_SCANCODE_UNKNOWN;
|
|
while (SDL_PollEvent(&sdlEvent)) {
|
|
if (sdlEvent.type == SDL_QUIT) {return true; break; }
|
|
else if (sdlEvent.type == SDL_KEYDOWN) {
|
|
anyKey = true;
|
|
keyJustPressed = sdlEvent.key.keysym.scancode;
|
|
if (sdlEvent.key.keysym.scancode == SDL_SCANCODE_ESCAPE) { return true; }
|
|
}
|
|
}
|
|
Uint32 buttons = SDL_GetMouseState(&mouse.x, &mouse.y);
|
|
mouse.x /= zoom;
|
|
mouse.y /= zoom;
|
|
|
|
mouse.mouse_down[0] = mouse.mouse_down[1] = mouse.mouse_down[2] = mouse.mouse_up[0] = mouse.mouse_up[1] = mouse.mouse_up[2] = false;
|
|
if ((buttons & 1) == 1) { if (!mouse.mouse_old[0]) mouse.mouse_down[0] = true; } else { if (mouse.mouse_old[0]) mouse.mouse_up[0] = true; }
|
|
if ((buttons & 2) == 2) { if (!mouse.mouse_old[1]) mouse.mouse_down[1] = true; } else { if (mouse.mouse_old[1]) mouse.mouse_up[1] = true; }
|
|
if ((buttons & 4) == 4) { if (!mouse.mouse_old[2]) mouse.mouse_down[2] = true; } else { if (mouse.mouse_old[2]) mouse.mouse_up[2] = true; }
|
|
mouse.mouse_old[0] = (buttons & 1) == 1;
|
|
mouse.mouse_old[1] = (buttons & 2) == 2;
|
|
mouse.mouse_old[2] = (buttons & 4) == 4;
|
|
|
|
if (buttons == 0) ignoreMouse = false;
|
|
|
|
if (buttons != 0 && !ignoreMouse) {
|
|
mouse.buttons[0] = (buttons & 1) == 1;
|
|
mouse.buttons[1] = (buttons & 2) == 2;
|
|
mouse.buttons[2] = (buttons & 4) == 4;
|
|
}
|
|
else {
|
|
mouse.buttons[0] = mouse.buttons[1] = mouse.buttons[2] = false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void PrintFatalError(const char* errorMsg) {
|
|
int size = strlen(errorMsg);
|
|
Print((screen_width - (size*6)) / 2, (screen_height - 6) / 2, errorMsg);
|
|
}
|
|
void ShowError() {
|
|
switch (error) {
|
|
case 1: PrintFatalError("config.ini not found"); break;
|
|
case 2: PrintFatalError("tiles file not found"); break;
|
|
case 3: PrintFatalError("cannot create map file"); break;
|
|
}
|
|
}
|
|
|
|
void ShowDialog() {
|
|
int size = 0;
|
|
switch (dialog) {
|
|
case 1:
|
|
size = strlen("Map file not found");
|
|
Print((screen_width - (size * 6)) / 2, (screen_height - 6) / 2, "Map file not found");
|
|
size = strlen("A new one has been created");
|
|
Print((screen_width - (size * 6)) / 2, ((screen_height - 6) / 2)+6, "A new one has been created");
|
|
if (Button((screen_width - 55) / 2, screen_height - 40, "Ok")) { dialog = 0; ignoreMouse = true; }
|
|
break;
|
|
case 2:
|
|
size = strlen("Map has been resized");
|
|
Print((screen_width - (size * 6)) / 2, (screen_height - 6) / 2, "Map has been resized");
|
|
size = strlen("using config.ini info");
|
|
Print((screen_width - (size * 6)) / 2, ((screen_height - 6) / 2) + 6, "using config.ini info");
|
|
if (Button((screen_width - 55) / 2, screen_height - 40, "Ok")) { dialog = 0; ignoreMouse = true; }
|
|
break;
|
|
//case 3: PrintFatalError("No s'ha trobat l'arxiu de mapa"); break;
|
|
}
|
|
}
|
|
|
|
void DoTilePal() {
|
|
int ox = 0, oy = 0;
|
|
if (tilemap_width <= screen_width) {
|
|
ox = (screen_width - tilemap_width) / 2;
|
|
}
|
|
else {
|
|
const int max_offset = tilemap_width - screen_width;
|
|
const float mouse_ratio = float(mouse.x) / float(screen_width);
|
|
ox = -(mouse_ratio * max_offset);
|
|
}
|
|
if (tilemap_height <= screen_height) {
|
|
oy = (screen_height - tilemap_height) / 2;
|
|
}
|
|
else {
|
|
const int max_offset = tilemap_height - screen_height;
|
|
const float mouse_ratio = float(mouse.y) / float(screen_height);
|
|
oy = -(mouse_ratio * max_offset);
|
|
}
|
|
Draw(sdlTilesTexture, ox, oy, 0, 0, tilemap_width, tilemap_height);
|
|
int tiles_per_row = tilemap_width / tile_width;
|
|
DrawRect(ox + (tile_back % tiles_per_row)*tile_width - 1, oy + (tile_back / tiles_per_row)*tile_height - 1, tile_width + 2, tile_height + 2, 255, 64, 255);
|
|
DrawRect(ox + (tile_sel % tiles_per_row)*tile_width - 1, oy + (tile_sel / tiles_per_row)*tile_height - 1, tile_width + 2, tile_height + 2, 255, 255, 255);
|
|
if (mouse.buttons[2]) { tile_back = ((mouse.x - ox) / tile_width) + ((mouse.y - oy) / tile_height) * tiles_per_row; state = STATE_TILEMAP; ignoreMouse = true; }
|
|
if (mouse.buttons[0]) { tile_sel = ((mouse.x - ox) / tile_width) + ((mouse.y - oy) / tile_height) * tiles_per_row; state = STATE_TILEMAP; ignoreMouse = true; }
|
|
if (keyJustPressed == SDL_SCANCODE_Q) state = STATE_TILEMAP;
|
|
}
|
|
|
|
void floodfill_r(const int x, const int y, const int tile) {
|
|
const int width_in_tiles = screen_width / tile_width;
|
|
const int height_in_tiles = screen_height / tile_height;
|
|
if ( (keyboard[CTRL] ) || ( (x >= map_x && y >= map_y && x < (map_x + width_in_tiles) && y < (map_y + height_in_tiles)) ) ) {
|
|
if (map[x + y * map_width] == tile) {
|
|
map[x + y * map_width] = tile_sel;
|
|
floodfill_r(x + 1, y, tile);
|
|
floodfill_r(x - 1, y, tile);
|
|
floodfill_r(x, y + 1, tile);
|
|
floodfill_r(x, y - 1, tile);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FloodFill() {
|
|
const int x = map_x + (mouse.x / tile_width);
|
|
const int y = map_y + (mouse.y / tile_height);
|
|
const int tile = map[x + y * map_width];
|
|
if (tile != tile_sel) floodfill_r(x, y, tile);
|
|
}
|
|
|
|
void ReplaceTile() {
|
|
const int x = map_x + (mouse.x / tile_width);
|
|
const int y = map_y + (mouse.y / tile_height);
|
|
const int tile = map[x + y * map_width];
|
|
const bool all_map = keyboard[CTRL];
|
|
const int xi = all_map ? 0 : map_x;
|
|
const int yi = all_map ? 0 : map_y;
|
|
const int w = all_map ? map_width : xi+(screen_width / tile_width);
|
|
const int h = all_map ? map_height : yi+(screen_height / tile_height);
|
|
|
|
for (int yy = yi; yy < h; yy++) {
|
|
for (int xx = xi; xx < w; xx++) {
|
|
if (map[xx + yy * map_width] == tile) map[xx + yy * map_width] = tile_sel;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DoTileMap() {
|
|
static bool menu = false;
|
|
|
|
const int width_in_tiles = screen_width / tile_width;
|
|
const int height_in_tiles = screen_height / tile_height;
|
|
const int pal_width_in_tiles = tilemap_width / tile_width;
|
|
for (int y = 0; y < height_in_tiles; y++) {
|
|
for (int x = 0; x < width_in_tiles; x++) {
|
|
unsigned char tile = map[(map_x + x) + (map_y + y) * map_width];
|
|
Draw(sdlTilesTexture, x*tile_width, y*tile_height, (tile % pal_width_in_tiles)*tile_width, (tile / pal_width_in_tiles)*tile_height, tile_width, tile_height);
|
|
if (!keyboard[SDL_SCANCODE_LSHIFT]) {
|
|
unsigned char sprite = map[((map_x + x) + (map_y + y) * map_width) + (map_width*map_height)];
|
|
if (sprite != 0) Draw(sdlTilesTexture, x*tile_width, y*tile_height, (sprite % pal_width_in_tiles)*tile_width, (sprite / pal_width_in_tiles)*tile_height, tile_width, tile_height);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!menu) {
|
|
const int cur_x = mouse.x / tile_width;
|
|
const int cur_y = mouse.y / tile_height;
|
|
DrawRect(cur_x*tile_width - 1, cur_y*tile_height - 1, tile_width + 2, tile_height + 2, 255, 255, 255, 128);
|
|
|
|
if (keyJustPressed == SDL_SCANCODE_TAB) {
|
|
menu = true; return;
|
|
}
|
|
if (keyJustPressed == SDL_SCANCODE_Q) state = STATE_TILEPAL;
|
|
if (keyJustPressed == SDL_SCANCODE_E) { state = STATE_MINIMAP; UpdateMiniMap(); }
|
|
if (keyJustPressed == SDL_SCANCODE_X) { int temp = tile_back; tile_back = tile_sel; tile_sel = temp; }
|
|
if (keyJustPressed == SDL_SCANCODE_RIGHT || keyJustPressed == SDL_SCANCODE_D) if (map_x < map_width - width_in_tiles) map_x += width_in_tiles;
|
|
if (keyJustPressed == SDL_SCANCODE_LEFT || keyJustPressed == SDL_SCANCODE_A) if (map_x > 0) map_x -= width_in_tiles;
|
|
if (keyJustPressed == SDL_SCANCODE_DOWN || keyJustPressed == SDL_SCANCODE_S) if (map_y < map_height - height_in_tiles) map_y += height_in_tiles;
|
|
if (keyJustPressed == SDL_SCANCODE_UP || keyJustPressed == SDL_SCANCODE_W) if (map_y > 0) map_y -= height_in_tiles;
|
|
if (keyJustPressed == SDL_SCANCODE_F) { Undo_Op(); FloodFill(); }
|
|
if (keyJustPressed == SDL_SCANCODE_R) { Undo_Op(); ReplaceTile(); }
|
|
|
|
static int scroll_x = 0;
|
|
static int scroll_y = 0;
|
|
static int old_map_x = 0;
|
|
static int old_map_y = 0;
|
|
|
|
if (mouse.mouse_down[MOUSE_BUTTON_LEFT] || mouse.mouse_down[MOUSE_BUTTON_RIGHT]) { Undo_Op(); }
|
|
if (mouse.mouse_down[MOUSE_BUTTON_LEFT]) {
|
|
old_map_x = map_x; old_map_y = map_y;
|
|
scroll_x = cur_x; scroll_y = cur_y;
|
|
}
|
|
if (mouse.buttons[MOUSE_BUTTON_RIGHT]) { if (tile_back < sprites) map[(map_x + cur_x) + (map_y + cur_y)*map_width] = tile_back; }
|
|
if (mouse.buttons[MOUSE_BUTTON_LEFT]) {
|
|
if (keyboard[SDL_SCANCODE_SPACE]) {
|
|
map_x = old_map_x - (cur_x - scroll_x);
|
|
map_y = old_map_y - (cur_y - scroll_y);
|
|
} else {
|
|
const int pos = (map_x + cur_x) + (map_y + cur_y)*map_width;
|
|
if (tile_sel >= sprites) {
|
|
ignoreMouse = true;
|
|
if (map[pos + (map_width*map_height)] == 0) {
|
|
map[pos + (map_width*map_height)] = tile_sel;
|
|
} else {
|
|
map[pos + (map_width*map_height)] = 0;
|
|
}
|
|
} else {
|
|
map[pos] = tile_sel;
|
|
}
|
|
}
|
|
}
|
|
if (mouse.buttons[MOUSE_BUTTON_MIDDLE]) { tile_sel = map[(map_x + cur_x) + (map_y + cur_y)*map_width]; }
|
|
|
|
if (keyJustPressed == SDL_SCANCODE_Z && keyboard[CTRL]) { Undo_Undo(); }
|
|
if (keyJustPressed == SDL_SCANCODE_Y && keyboard[CTRL]) { Undo_Redo(); }
|
|
if (keyJustPressed == SDL_SCANCODE_Z && keyboard[CTRL] && keyboard[SDL_SCANCODE_LSHIFT]) { Undo_Redo(); }
|
|
}
|
|
else {
|
|
if (keyJustPressed == SDL_SCANCODE_TAB) { menu = false; return; }
|
|
FillRect(0, 0, screen_width, screen_height, 0, 0, 0, 192);
|
|
if (Button(6, 6, "Save")) {
|
|
FILE* f = fopen(GetPath(map_filename), "wb");
|
|
fwrite(&map_width, 1, 1, f);
|
|
fwrite(&map_height, 1, 1, f);
|
|
fwrite(map, map_width*map_height*2, 1, f);
|
|
fclose(f);
|
|
menu = false; ignoreMouse = true;
|
|
}
|
|
if (Button(6, 24, "Clear")) {
|
|
Undo_Op();
|
|
for (int y = 0; y < height_in_tiles; y++) {
|
|
for (int x = 0; x < width_in_tiles; x++) {
|
|
map[(map_x + x) + (map_y + y) * map_width] = tile_back;
|
|
}
|
|
}
|
|
menu = false; ignoreMouse = true;
|
|
}
|
|
if (Button(6, 42, "Border")) {
|
|
Undo_Op();
|
|
for (int y = 0; y < height_in_tiles; y++) {
|
|
map[(map_x) + (map_y + y) * map_width] = tile_sel;
|
|
map[(map_x + width_in_tiles - 1) + (map_y + y) * map_width] = tile_sel;
|
|
}
|
|
for (int x = 0; x < width_in_tiles; x++) {
|
|
map[(map_x + x) + (map_y) * map_width] = tile_sel;
|
|
map[(map_x + x) + (map_y + height_in_tiles - 1) * map_width] = tile_sel;
|
|
}
|
|
menu = false; ignoreMouse = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define mod(x, y) (((x % y)+y)%y)
|
|
|
|
void ShiftMap(int sx, int sy) {
|
|
Undo_Op();
|
|
int test = mod(-1, 240);
|
|
sx *= (screen_width/tile_width);
|
|
sy *= (screen_height / tile_height);
|
|
unsigned char* new_map = (unsigned char*)malloc(map_width*map_height);
|
|
for (int y = 0; y < map_height; y++) {
|
|
for (int x = 0; x < map_width; x++) {
|
|
new_map[x + y*map_width] = map[mod(x+sx, map_width) + mod(y+sy, map_height)*map_width];
|
|
}
|
|
}
|
|
free(map);
|
|
map = new_map;
|
|
UpdateMiniMap();
|
|
}
|
|
|
|
void DoMiniMap() {
|
|
int ox = 0, oy = 0;
|
|
if (map_width <= screen_width) {
|
|
ox = (screen_width - map_width) / 2;
|
|
}
|
|
else {
|
|
const int max_offset = map_width - screen_width;
|
|
const float mouse_ratio = float(mouse.x) / float(screen_width);
|
|
ox = -(mouse_ratio * max_offset);
|
|
}
|
|
if (map_height <= screen_height) {
|
|
oy = (screen_height - map_height) / 2;
|
|
}
|
|
else {
|
|
const int max_offset = map_height - screen_height;
|
|
const float mouse_ratio = float(mouse.y) / float(screen_height);
|
|
oy = -(mouse_ratio * max_offset);
|
|
}
|
|
Draw(sdlMinimapTexture, ox, oy, 0, 0, map_width, map_height);
|
|
|
|
const int screen_width_in_tiles = screen_width / tile_width;
|
|
const int screen_height_in_tiles = screen_height / tile_height;
|
|
DrawRect((ox + map_x) - 1, (oy + map_y) - 1, screen_width_in_tiles + 2, screen_height_in_tiles + 2, 255, 255, 255);
|
|
//DrawRect(ox + (tile_sel % tiles_per_row)*tile_width - 1, oy + (tile_sel / tiles_per_row)*tile_height - 1, tile_width + 2, tile_height + 2, 255, 255, 255);
|
|
DrawRect(ox - 1, oy - 1, map_width + 2, map_height + 2, 255, 0, 0);
|
|
if (mouse.buttons[MOUSE_BUTTON_LEFT]) {
|
|
map_x = int((mouse.x-ox) / screen_width_in_tiles) * screen_width_in_tiles;
|
|
map_y = int((mouse.y - oy) / screen_height_in_tiles) * screen_height_in_tiles;
|
|
state = STATE_TILEMAP;
|
|
ignoreMouse = true;
|
|
}
|
|
if (keyJustPressed == SDL_SCANCODE_E) state = STATE_TILEMAP;
|
|
if (keyboard[CTRL]) {
|
|
if (keyJustPressed == SDL_SCANCODE_A) ShiftMap(1, 0);
|
|
if (keyJustPressed == SDL_SCANCODE_D) ShiftMap(-1, 0);
|
|
if (keyJustPressed == SDL_SCANCODE_W) ShiftMap(0, 1);
|
|
if (keyJustPressed == SDL_SCANCODE_S) ShiftMap(0, -1);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
/*const int len = strlen(argv[0])-30;
|
|
memcpy(path, argv[0], len);
|
|
path[len] = '\0';*/
|
|
Init();
|
|
|
|
while (!Update()) {
|
|
Clear();
|
|
|
|
if (error == 0) {
|
|
if (dialog == 0) {
|
|
switch (state) {
|
|
case STATE_TILEMAP: DoTileMap(); break;
|
|
case STATE_TILEPAL: DoTilePal(); break;
|
|
case STATE_MINIMAP: DoMiniMap(); break;
|
|
};
|
|
|
|
/*char num[5];
|
|
sprintf(num, "%d", mouse.x);
|
|
Print(100, 100, num);
|
|
sprintf(num, ",%d", mouse.y);
|
|
Print(118, 100, num);
|
|
|
|
if (Button(2, 2, "New")) {
|
|
strcpy(state, "New pressed");
|
|
}
|
|
if (Button(2, 12, "Open")) {
|
|
strcpy(state, "open pressed");
|
|
}
|
|
if (Button(2, 22, "Save")) {
|
|
strcpy(state, "save pressed");
|
|
}
|
|
if (Button(2, 32, "Save As")) {
|
|
strcpy(state, "Save As pressed");
|
|
}
|
|
|
|
FillRect(0, 183, 256, 9, 128, 128, 128, 255);
|
|
Print(2, 185, state);*/
|
|
} else {
|
|
ShowDialog();
|
|
}
|
|
} else {
|
|
ShowError();
|
|
}
|
|
Flip();
|
|
}
|
|
|
|
Quit();
|
|
return 0;
|
|
} |