summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoruntir_l <87096069+untir-l@users.noreply.github.com>2022-02-27 13:23:43 +0000
committeruntir_l <87096069+untir-l@users.noreply.github.com>2022-02-27 13:28:20 +0000
commit1ddd20748d01570929a88672366dff69ce300a51 (patch)
tree5c53f1765484427fc9334acfb7fa463c1d65b77b
parenta492064a97a04939ca5e995c3c6df4935b9e2cb9 (diff)
downloadhitomezashi-1ddd20748d01570929a88672366dff69ce300a51.tar
hitomezashi-1ddd20748d01570929a88672366dff69ce300a51.tar.gz
hitomezashi-1ddd20748d01570929a88672366dff69ce300a51.zip
Add support for choosing foreground and background colours
-rw-r--r--.gitignore1
-rw-r--r--README.md7
-rw-r--r--cli/hitomezashi_cli.c44
-rw-r--r--cli/hitomezashi_cli.h4
-rw-r--r--lib/hitomezashi.c20
-rw-r--r--lib/hitomezashi.h10
-rw-r--r--web/hitomezashi_web.c18
-rw-r--r--web/hitomezashi_web.h4
-rw-r--r--web/hitomezashi_web_shell.html4
9 files changed, 84 insertions, 28 deletions
diff --git a/.gitignore b/.gitignore
index db29d29..d22b09a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
*.wasm
hitomezashi_cli
**/docs
+.idea/
diff --git a/README.md b/README.md
index 247ddc4..3d75887 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
Library, CLI and web app to generate hitomezashi patterns. These are an example of visually complex and structured patterns arising from simple rules.
-Here is an example of such a pattern:
+Here is an example of such a pattern (different colours are also supported):
<img src="https://raw.githubusercontent.com/untir-l/hitomezashi/main/sample.png" alt="sample hitomezashi pattern" width="500" height="500">
@@ -32,6 +32,8 @@ To build, run `CC=gcc make libhitomezashi.a`.
This is in the `cli/` directory. Run `./hitomezashi_cli -h` for usage info.
+Colours are supported!
+
The output of the CLI app is a BMP image as this is supported by default in SDL2; this will change eventually to output PNGs since BMP is an antiquated format. For now, you can convert using FFmpeg or similar.
To build, run `CC=gcc make hitomezashi_cli`.
@@ -44,6 +46,8 @@ To build, first run `make clean` if you previously built to native code, then (w
You will need to serve, from a web server: `hitomezashi_web.html`, `hitomezashi_web.js`, `hitomezashi_web.wasm` in order for it to work; the `file://` protocol may not be sufficient.
+The UI is self-explanatory.
+
## Technical and copyright information
Written in C11 with SDL2. Code style: `make format-code` will run `clang-format` with the correct parameters.
@@ -52,4 +56,3 @@ Licensed under GPLv2 (see `LICENSE` file for full text). This project's source c
## Todos/potential future additions
- Add support for output to PNG/other formats to the CLI app
-- Add support for choosing foreground and background colours
diff --git a/cli/hitomezashi_cli.c b/cli/hitomezashi_cli.c
index 72d43b7..53a9568 100644
--- a/cli/hitomezashi_cli.c
+++ b/cli/hitomezashi_cli.c
@@ -2,7 +2,7 @@
#include "hitomezashi_cli.h"
-#include "SDL.h"
+#include "SDL2/SDL.h"
#define OPTPARSE_IMPLEMENTATION
#define OPTPARSE_API static
#include <limits.h>
@@ -25,9 +25,11 @@ int main(int argc, char **argv) {
char *y_pattern;
int gap;
int thickness;
+ Uint32 fg_colour;
+ Uint32 bg_colour;
hitomezashi_cli_handle_args(&out_file_path, &x_pattern_len, &y_pattern_len,
- &x_pattern, &y_pattern, &gap, &thickness, argc,
- argv);
+ &x_pattern, &y_pattern, &gap, &thickness,
+ &fg_colour, &bg_colour, argc, argv);
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
SDL_LogCritical(SDL_LOG_CATEGORY_ERROR, "Failed to initialise SDL: %s",
@@ -37,7 +39,8 @@ int main(int argc, char **argv) {
struct Hitomezashi_State state;
if (hitomezashi_state_init(&state, x_pattern_len, y_pattern_len, x_pattern,
- y_pattern, gap, thickness) != 0) {
+ y_pattern, gap, thickness, fg_colour,
+ bg_colour) != 0) {
return Hitomezashi_Cli_Exit_Code_Err_State_Init;
}
@@ -64,6 +67,10 @@ void hitomezashi_cli_help(void) {
"-y - specify the y pattern, as with -x\n"
"-g - specify the gap between lines as an integer\n"
"-t - specify the line thickness as an integer\n"
+ "-f - (optional) specify the foreground colour in RGB as a 32-bit "
+ "integer, eg. 0x000000"
+ "-b - (optional) specify the background colour in RGB as a 32-bit "
+ "integer, eg. 0xFFFFFF"
"-h - print this help and exit") < 0) {
exit(Hitomezashi_Cli_Exit_Code_Err_Print_Help);
}
@@ -73,17 +80,20 @@ void hitomezashi_cli_help(void) {
void hitomezashi_cli_handle_args(char **out_file_path, int *x_pattern_len,
int *y_pattern_len, char **x_pattern,
char **y_pattern, int *gap, int *thickness,
- int argc, char **argv) {
+ Uint32 *fg_colour, Uint32 *bg_colour, int argc,
+ char **argv) {
bool out_file_path_specified = false;
bool x_pattern_specified = false;
bool y_pattern_specified = false;
bool gap_specified = false;
bool thickness_specified = false;
+ *fg_colour = 0x000000;
+ *bg_colour = 0xffffff;
struct optparse options;
optparse_init(&options, argv);
int option;
- while ((option = optparse(&options, ":o:x:y:g:t:h")) != -1) {
+ while ((option = optparse(&options, ":o:x:y:g:t:f:b:h")) != -1) {
switch (option) {
case 'o':;
*out_file_path = options.optarg;
@@ -144,6 +154,28 @@ void hitomezashi_cli_handle_args(char **out_file_path, int *x_pattern_len,
*thickness = thickness_l;
thickness_specified = true;
break;
+ case 'f':;
+ long fg_colour_l = strtol(options.optarg, NULL, 0);
+ if (fg_colour_l < 0 || fg_colour_l > INT_MAX) {
+ SDL_LogCritical(
+ SDL_LOG_CATEGORY_ERROR,
+ "Value for foreground colour must be non-negative and less than %d",
+ INT_MAX);
+ exit(Hitomezashi_Cli_Exit_Code_Err_Handle_Args);
+ }
+ *fg_colour = fg_colour_l;
+ break;
+ case 'b':;
+ long bg_colour_l = strtol(options.optarg, NULL, 0);
+ if (bg_colour_l < 0 || bg_colour_l > INT_MAX) {
+ SDL_LogCritical(
+ SDL_LOG_CATEGORY_ERROR,
+ "Value for background colour must be non-negative and less than %d",
+ INT_MAX);
+ exit(Hitomezashi_Cli_Exit_Code_Err_Handle_Args);
+ }
+ *bg_colour = bg_colour_l;
+ break;
case 'h':;
hitomezashi_cli_help();
break;
diff --git a/cli/hitomezashi_cli.h b/cli/hitomezashi_cli.h
index 3c6b9bf..bce0128 100644
--- a/cli/hitomezashi_cli.h
+++ b/cli/hitomezashi_cli.h
@@ -2,6 +2,7 @@
#ifndef HITOMEZASHI_CLI_H
#define HITOMEZASHI_CLI_H
+#include "SDL2/SDL.h"
#include <stddef.h>
/** Exit codes for main().
@@ -31,7 +32,8 @@ enum Hitomezashi_Cli_Exit_Code {
void hitomezashi_cli_handle_args(char **out_file_path, int *x_pattern_len,
int *y_pattern_len, char **x_pattern,
char **y_pattern, int *gap, int *thickness,
- int argc, char **argv);
+ Uint32 *fg_colour, Uint32 *bg_colour, int argc,
+ char **argv);
/** Print the help text and exit.
* Exits with Hitomezashi_Cli_Exit_Code_Success (0) on success, and
* Hitomezashi_Cli_Exit_Code_Print_Help (2) on failure.
diff --git a/lib/hitomezashi.c b/lib/hitomezashi.c
index c87073f..9275517 100644
--- a/lib/hitomezashi.c
+++ b/lib/hitomezashi.c
@@ -8,7 +8,8 @@ SDL_Color HITOMEZASHI_BG_COLOUR = {.r = 255, .g = 255, .b = 255};
enum Hitomezashi_State_Init_Result
hitomezashi_state_init(struct Hitomezashi_State *state, int x_pattern_len,
int y_pattern_len, char *x_pattern, char *y_pattern,
- int gap, int line_thickness) {
+ int gap, int line_thickness, Uint32 fg_colour,
+ Uint32 bg_colour) {
assert(x_pattern_len >= 0);
assert(y_pattern_len >= 0);
assert(gap >= 0);
@@ -22,6 +23,8 @@ hitomezashi_state_init(struct Hitomezashi_State *state, int x_pattern_len,
state->line_thickness = line_thickness;
state->output_width = x_pattern_len * gap;
state->output_height = y_pattern_len * gap;
+ state->fg_colour = fg_colour;
+ state->bg_colour = bg_colour;
state->surface = SDL_CreateRGBSurface(0, state->output_width,
state->output_height, 32, 0, 0, 0, 0);
@@ -36,14 +39,7 @@ enum Hitomezashi_Draw_Result hitomezashi_draw(struct Hitomezashi_State *state) {
return Hitomezashi_Draw_Result_Err_Lock_Surface;
}
- Uint32 bg_colour =
- SDL_MapRGB(state->surface->format, HITOMEZASHI_BG_COLOUR.r,
- HITOMEZASHI_BG_COLOUR.g, HITOMEZASHI_BG_COLOUR.b);
- Uint32 fg_colour =
- SDL_MapRGB(state->surface->format, HITOMEZASHI_FG_COLOUR.r,
- HITOMEZASHI_FG_COLOUR.g, HITOMEZASHI_FG_COLOUR.b);
-
- SDL_FillRect(state->surface, NULL, bg_colour);
+ SDL_FillRect(state->surface, NULL, state->bg_colour);
SDL_Rect rect;
// Draw y pattern (horizontal) lines
@@ -54,7 +50,7 @@ enum Hitomezashi_Draw_Result hitomezashi_draw(struct Hitomezashi_State *state) {
rect.y = i * state->gap;
rect.w = state->gap;
rect.h = state->line_thickness;
- SDL_FillRect(state->surface, &rect, fg_colour);
+ SDL_FillRect(state->surface, &rect, state->fg_colour);
}
}
}
@@ -66,7 +62,7 @@ enum Hitomezashi_Draw_Result hitomezashi_draw(struct Hitomezashi_State *state) {
rect.y = j * state->gap;
rect.w = state->line_thickness;
rect.h = state->gap;
- SDL_FillRect(state->surface, &rect, fg_colour);
+ SDL_FillRect(state->surface, &rect, state->fg_colour);
}
}
}
@@ -78,7 +74,7 @@ enum Hitomezashi_Draw_Result hitomezashi_draw(struct Hitomezashi_State *state) {
rect.y = y;
rect.w = state->line_thickness;
rect.h = state->line_thickness;
- SDL_FillRect(state->surface, &rect, fg_colour);
+ SDL_FillRect(state->surface, &rect, state->fg_colour);
}
}
diff --git a/lib/hitomezashi.h b/lib/hitomezashi.h
index 64b17af..51da75b 100644
--- a/lib/hitomezashi.h
+++ b/lib/hitomezashi.h
@@ -25,6 +25,9 @@ struct Hitomezashi_State {
int line_thickness;
+ Uint32 fg_colour;
+ Uint32 bg_colour;
+
/** Width in pixels of the SDL_Surface needed to hold the pattern. This is
* calculated by hitomezashi_state_init(). */
int output_width;
@@ -32,11 +35,10 @@ struct Hitomezashi_State {
* calculated by hitomezashi_state_init(). */
int output_height;
- /** SDL_Surface the pattern is drawn to by hitomezashi_draw(). */
+ /** Surface the pattern is drawn to by hitomezashi_draw(). */
SDL_Surface *surface;
};
-/** Result of hitomezashi_state_init(). */
enum Hitomezashi_State_Init_Result {
Hitomezashi_State_Init_Result_Success,
/** The function failed as it encountered an error initialising the
@@ -44,7 +46,6 @@ enum Hitomezashi_State_Init_Result {
Hitomezashi_State_Init_Result_Err_Create_Surface,
};
-/** Result of hitomezashi_draw() */
enum Hitomezashi_Draw_Result {
Hitomezashi_Draw_Result_Success,
/** The function failed as it encountered an error "locking" the surface to
@@ -57,7 +58,8 @@ enum Hitomezashi_Draw_Result {
enum Hitomezashi_State_Init_Result
hitomezashi_state_init(struct Hitomezashi_State *state, int x_pattern_len,
int y_pattern_len, char *x_pattern, char *y_pattern,
- int gap, int line_thickness);
+ int gap, int line_thickness, Uint32 fg_colour,
+ Uint32 bg_colour);
/** Draw the hitomezashi pattern to state->surface. */
enum Hitomezashi_Draw_Result hitomezashi_draw(struct Hitomezashi_State *state);
diff --git a/web/hitomezashi_web.c b/web/hitomezashi_web.c
index 4859c20..539fa96 100644
--- a/web/hitomezashi_web.c
+++ b/web/hitomezashi_web.c
@@ -32,6 +32,9 @@ int EMSCRIPTEN_KEEPALIVE main(void) {
int gap = strtol(strtok(NULL, "\n"), NULL, 0);
int line_thickness = strtol(strtok(NULL, "\n"), NULL, 0);
+ Uint32 fg_colour = strtol(strtok(NULL, "\n"), NULL, 0);
+ Uint32 bg_colour = strtol(strtok(NULL, "\n"), NULL, 0);
+
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
return Hitomezashi_Web_Result_Err_Sdl_Init;
}
@@ -42,7 +45,8 @@ int EMSCRIPTEN_KEEPALIVE main(void) {
struct Hitomezashi_State state;
if (hitomezashi_state_init(&state, x_pattern_len, y_pattern_len, x_pattern,
- y_pattern, gap, line_thickness) != 0) {
+ y_pattern, gap, line_thickness, fg_colour,
+ bg_colour) != 0) {
return Hitomezashi_Web_Result_Err_State_Init;
}
@@ -81,6 +85,16 @@ EM_JS(char *, hitomezashi_web_get_args, (void), {
const y_pattern = search_params.get("y_pattern");
const gap = search_params.get("gap");
const line_thickness = search_params.get("line_thickness");
+ let fg_colour = search_params.get("fg_colour");
+ let bg_colour = search_params.get("bg_colour");
+ if (!fg_colour) {
+ fg_colour = "#000000";
+ }
+ if (!bg_colour) {
+ bg_colour = "#FFFFFF";
+ }
+ fg_colour = "0x" + fg_colour.slice(1);
+ bg_colour = "0x" + bg_colour.slice(1);
if (!(x_pattern && y_pattern && gap && line_thickness)) {
result_js = "i";
@@ -91,7 +105,7 @@ EM_JS(char *, hitomezashi_web_get_args, (void), {
result_js = "i";
} else {
result_js = x_pattern + "\n" + y_pattern + "\n" + gap + "\n" +
- line_thickness + "\n";
+ line_thickness + "\n" + fg_colour + "\n" + bg_colour + "\n";
}
}
diff --git a/web/hitomezashi_web.h b/web/hitomezashi_web.h
index 5d4f523..361a8c2 100644
--- a/web/hitomezashi_web.h
+++ b/web/hitomezashi_web.h
@@ -2,6 +2,7 @@
#ifndef HITOMEZASHI_WEB_H
#define HITOMEZASHI_WEB_H
+#include "SDL2/SDL.h"
#include "emscripten.h"
enum Hitomezashi_Web_Result {
@@ -12,7 +13,8 @@ enum Hitomezashi_Web_Result {
};
int hitomezashi_web(int x_pattern_len, int y_pattern_len, char *x_pattern,
- char *y_pattern, int gap, int line_thickness);
+ char *y_pattern, int gap, int line_thickness,
+ Uint32 fg_colour, Uint32 bg_colour);
/** Parse the URL query string and return the parameters thereof.
*
diff --git a/web/hitomezashi_web_shell.html b/web/hitomezashi_web_shell.html
index 7b3ad76..d3224dd 100644
--- a/web/hitomezashi_web_shell.html
+++ b/web/hitomezashi_web_shell.html
@@ -39,6 +39,8 @@
<p><label>y pattern: <input name="y_pattern"></label></p>
<p><label>gap: <input name="gap" type="number"></label></p>
<p><label>line thickness: <input name="line_thickness" type="number"></label></p>
+ <p><label>foreground colour: <input name="fg_colour" type="color"></label></p>
+ <p><label>background colour: <input name="bg_colour" type="color"></label></p>
<p><input type="submit" value="submit"></p>
</form>
<br>
@@ -63,6 +65,8 @@
document.querySelector("input[name=\"y_pattern\"]").value = params.get("y_pattern");
document.querySelector("input[name=\"gap\"]").value = params.get("gap");
document.querySelector("input[name=\"line_thickness\"]").value = params.get("line_thickness");
+ document.querySelector("input[name=\"fg_colour\"]").value = params.get("fg_colour");
+ document.querySelector("input[name=\"bg_colour\"]").value = params.get("bg_colour");
</script>
{{{ SCRIPT }}}
</body>