diff --git a/CMakeLists.txt b/CMakeLists.txt index 75f81c0..15f3f78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required (VERSION 3.0) cmake_policy(VERSION 3.0) -project (mazemaker VERSION 1.2) +project (mazemaker VERSION 1.3) SET(EXEC_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE PATH "Installation prefix for executables and object code libraries" FORCE) SET(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "Installation prefix for C header files" FORCE) @@ -8,6 +8,8 @@ SET(LIB_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib CACHE PATH "Installation prefix CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/mazemaker.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/mazemaker.pc) +link_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/lib) + add_subdirectory(lib) add_subdirectory(utils) diff --git a/include/mazemaker.h b/include/mazemaker.h index 20b2f32..a8cc735 100644 --- a/include/mazemaker.h +++ b/include/mazemaker.h @@ -22,9 +22,18 @@ typedef enum { EDGE_LEFT } mazeedge_dir_t; +typedef struct mazeoptions mazeoptions_t; + void mazemaker_generate_maze(int width, int height, mazegrid_t* result); void mazemaker_free_maze(mazegrid_t* maze); int mazemaker_maze_to_png(mazegrid_t const* maze, char const* filename); +int mazemaker_maze_to_png_opt(mazegrid_t const* maze, char const* filename, mazeoptions_t const*); int mazemaker_maze_to_png_mem(mazegrid_t const* maze, size_t* len, uint8_t** buf); +int mazemaker_maze_to_png_mem_opt(mazegrid_t const* maze, size_t* len, uint8_t** buf, mazeoptions_t const*); + +mazeoptions_t* mazemaker_options_new(); +void mazemaker_options_free(mazeoptions_t*); +int mazemaker_options_set_wall_color(mazeoptions_t*, char const* color_desc); +int mazemaker_options_set_background_color(mazeoptions_t*, char const* color_desc); #endif // !def(_MAZEMAKER_H) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 03cd733..d5bb57a 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,7 +1,7 @@ project(mazemaker_lib) cmake_minimum_required (VERSION 2.8.12) set (mazemaker_SOVERSION_CURRENT 0) -set (mazemaker_SOVERSION_REVISION 1) +set (mazemaker_SOVERSION_REVISION 2) set (mazemaker_SOVERSION_AGE 0) math (EXPR mazemaker_SOVERSION_MAJOR "${mazemaker_SOVERSION_CURRENT} - ${mazemaker_SOVERSION_AGE}") math (EXPR mazemaker_SOVERSION_MINOR "${mazemaker_SOVERSION_AGE} + ${mazemaker_SOVERSION_REVISION}") diff --git a/lib/image.c b/lib/image.c index c57d0a0..c7d8295 100644 --- a/lib/image.c +++ b/lib/image.c @@ -6,6 +6,7 @@ #include #include #include "grid.h" +#include "options.h" #define LINE_THICKNESS 3 #define BLOCK_SIZE 32 @@ -43,7 +44,7 @@ static img_data_t* gridToImageData(mazegrid_t const* g) { result->data = malloc(result->w * result->h); //fprintf(stderr, "Box dimensions: %d x %d\n", result->w, result->h); - // white background + // set background memset(result->data, 0, result->w * result->h); // draw basic outline @@ -71,16 +72,20 @@ static img_data_t* gridToImageData(mazegrid_t const* g) { return result; } -static void writeImageData(img_data_t const* img, png_structp png_ptr) { +static void writeImageData(img_data_t const* img, png_structp png_ptr, mazeoptions_t const* options) { for (int i = 0; i < img->h; i++) { png_byte row[3 * img->w]; for (int j = 0; j < img->w; j++) { if (img->data[i * img->w + j]) { - // black - row[3 * j] = row[3 * j + 1] = row[3 * j + 2] = 0; + // wall color + row[3 * j] = options->wall_color[0]; + row[3 * j + 1] = options->wall_color[1]; + row[3 * j + 2] = options->wall_color[2]; } else { - // white - row[3 * j] = row[3 * j + 1] = row[3 * j + 2] = 255; + // background + row[3 * j] = options->background_color[0]; + row[3 * j + 1] = options->background_color[1]; + row[3 * j + 2] = options->background_color[2]; } } png_write_row(png_ptr, row); @@ -92,7 +97,7 @@ static void freeImageData(img_data_t* img) { free(img); } -int mazemaker_maze_to_png(mazegrid_t const* g, char const* filename) { +int mazemaker_maze_to_png_opt(mazegrid_t const* g, char const* filename, mazeoptions_t const* options) { int code = 1; img_data_t* img = gridToImageData(g); FILE *f = NULL; @@ -139,7 +144,7 @@ int mazemaker_maze_to_png(mazegrid_t const* g, char const* filename) { png_write_info(png_ptr, info_ptr); - writeImageData(img, png_ptr); + writeImageData(img, png_ptr, options); png_write_end(png_ptr, NULL); @@ -156,6 +161,13 @@ exit: return code; } +int mazemaker_maze_to_png(mazegrid_t const* g, char const* filename) { + mazeoptions_t* options = mazemaker_options_new(); // use default options + int result = mazemaker_maze_to_png_opt(g, filename, options); + mazemaker_options_free(options); + return result; +} + static void append_png_data(png_structp png_ptr, png_bytep data, png_size_t length) { struct mem_encode* p = (struct mem_encode*)png_get_io_ptr(png_ptr); size_t nsize = p->size + length; @@ -173,7 +185,7 @@ static void png_no_flush(png_structp png_ptr) { /* noop */ } -int mazemaker_maze_to_png_mem(mazegrid_t const* g, size_t* len, uint8_t** buf) { +int mazemaker_maze_to_png_mem_opt(mazegrid_t const* g, size_t* len, uint8_t** buf, mazeoptions_t const* options) { int code = 1; img_data_t* img = gridToImageData(g); png_structp png_ptr = NULL; @@ -209,7 +221,7 @@ int mazemaker_maze_to_png_mem(mazegrid_t const* g, size_t* len, uint8_t** buf) { png_write_info(png_ptr, info_ptr); - writeImageData(img, png_ptr); + writeImageData(img, png_ptr, options); png_write_end(png_ptr, NULL); @@ -228,3 +240,10 @@ exit: if (img != NULL) freeImageData(img); return code; } + +int mazemaker_maze_to_png_mem(mazegrid_t const* g, size_t* len, uint8_t** buf) { + mazeoptions_t* options = mazemaker_options_new(); // use default options + int result = mazemaker_maze_to_png_mem_opt(g, len, buf, options); + mazemaker_options_free(options); + return result; +} diff --git a/lib/options.c b/lib/options.c new file mode 100644 index 0000000..034a4e4 --- /dev/null +++ b/lib/options.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include "options.h" + +mazeoptions_t* mazemaker_options_new() { + mazeoptions_t* result = malloc(sizeof(mazeoptions_t)); + + // set defaults + memset(result->wall_color, 0, 3); + memset(result->background_color, 0xff, 3); + + return result; +} + +void mazemaker_options_free(mazeoptions_t* options) { + free(options); +} + +static int stringToColor(char const* color_desc, rgb_color_t dst) { + if (color_desc[0] != '#') return -1; // bad format + + size_t l; + for (l = 1; color_desc[l] != '\0'; l++) if (!isxdigit(color_desc[l])) return -1; // bad format + + if ((l != 4) && (l != 7)) return -1; // bad format + + char x2[3] = { 0, 0, 0}; + if (l == 4) { + x2[0] = x2[1] = color_desc[1]; + sscanf(x2, "%hhx", &dst[0]); + x2[0] = x2[1] = color_desc[2]; + sscanf(x2, "%hhx", &dst[1]); + x2[0] = x2[1] = color_desc[3]; + sscanf(x2, "%hhx", &dst[2]); + } else { + strncpy(x2, color_desc + 1, 2); + sscanf(x2, "%hhx", &dst[0]); + strncpy(x2, color_desc + 3, 2); + sscanf(x2, "%hhx", &dst[1]); + strncpy(x2, color_desc + 5, 2); + sscanf(x2, "%hhx", &dst[2]); + } + return 0; +} + +int mazemaker_options_set_wall_color(mazeoptions_t* options, char const* color_desc) { + return stringToColor(color_desc, options->wall_color); +} + +int mazemaker_options_set_background_color(mazeoptions_t* options, char const* color_desc) { + return stringToColor(color_desc, options->background_color); +} + diff --git a/lib/options.h b/lib/options.h new file mode 100644 index 0000000..5066608 --- /dev/null +++ b/lib/options.h @@ -0,0 +1,13 @@ +#ifndef _OPTIONS_H +#define _OPTIONS_H 1 + +#include + +typedef uint8_t rgb_color_t[3]; + +typedef struct mazeoptions { + rgb_color_t wall_color; + rgb_color_t background_color; +} mazeoptions_t; + +#endif // !def(_OPTIONS_H) diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt index 941a85a..91adb10 100644 --- a/utils/CMakeLists.txt +++ b/utils/CMakeLists.txt @@ -3,9 +3,8 @@ pkg_search_module(POPT REQUIRED popt) add_executable(mazemaker) target_sources(mazemaker PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/mazemaker.c) -target_link_libraries(mazemaker PRIVATE mazemaker_shared PUBLIC ${POPT_LIBRARIES}) +target_link_libraries(mazemaker PUBLIC mazemaker_shared ${POPT_LIBRARIES}) target_include_directories(mazemaker PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include PUBLIC ${POPT_INCLUDE_DIRS}) target_compile_options(mazemaker PUBLIC ${POPT_CFLAGS_OTHER}) -target_link_options(mazemaker PUBLIC -L${POPT_LIBDIR}) install (TARGETS mazemaker DESTINATION bin) diff --git a/utils/mazemaker.c b/utils/mazemaker.c index b52efde..173c35d 100644 --- a/utils/mazemaker.c +++ b/utils/mazemaker.c @@ -6,12 +6,16 @@ int main(int argc, char* argv[]) { char c; int width = 0, height = 0; - char const *filename = NULL; + char const *filename = NULL, *fg_color = NULL, *bg_color = NULL; struct poptOption options_table[] = { { "width", 'w', POPT_ARG_INT, &width, 0, "Width of the maze", "BLOCKS" }, { "height", 'h', POPT_ARG_INT, &height, 0, "Height of the maze", "BLOCKS" }, + { "foreground", 'f', POPT_ARG_STRING, &fg_color, 0, + "Foreground (wall) color", "#rrggbb" }, + { "background", 'b', POPT_ARG_STRING, &bg_color, 0, + "Background color", "#rrggbb" }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } }; @@ -36,8 +40,12 @@ int main(int argc, char* argv[]) { return 1; } mazegrid_t maze; + mazeoptions_t* options = mazemaker_options_new(); + if (fg_color != NULL) mazemaker_options_set_wall_color(options, fg_color); + if (bg_color != NULL) mazemaker_options_set_background_color(options, bg_color); mazemaker_generate_maze(width, height, &maze); - mazemaker_maze_to_png(&maze, filename); + mazemaker_maze_to_png_opt(&maze, filename, options); mazemaker_free_maze(&maze); + mazemaker_options_free(options); poptFreeContext(ctx); }