diff --git a/.gitignore b/.gitignore index 8bd652d..3a56698 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.zip -packing +packing_* build.sh +*.a diff --git a/justfile b/justfile index 3536170..1845430 100644 --- a/justfile +++ b/justfile @@ -1,20 +1,34 @@ name := "freling_netatmo_algo" -exe := "./packing" +exe_cli := "./packing_cli" +exe_gui := "./packing_gui" build_sh := "build.sh" -build: - tup +build-raylib: + cd src/3rd-party/raylib-4.0.0/src && \ + make CC=clang \ + PLATFORM=PLATFORM_DESKTOP \ + RAYLIB_MODULE_AUDIO=FALSE \ + RAYLIB_MODULE_MODELS=FALSE -run: build - {{exe}} lenna.png 0 0 0 0 +build-cli: + tup {{exe_cli}} + +build-gui: build-raylib + tup {{exe_gui}} + +run-cli: build-cli + {{exe_cli}} lenna.png 0 0 0 0 + +run-gui: build-gui + nixGL {{exe_gui}} generate-build: git clean -xf src/ - rm --force {{exe}} + rm --force {{exe_cli}} {{exe_gui}} tup generate {{build_sh}} -debug: build - lldb {{exe}} +debug: build-cli + lldb {{exe_cli}} archive: generate-build git archive --add-file={{build_sh}} --output={{name}}.zip --prefix={{name}}/ HEAD diff --git a/shell.nix b/shell.nix index 7e20d6e..b943bd7 100644 --- a/shell.nix +++ b/shell.nix @@ -6,5 +6,15 @@ pkgs.mkShell { just tup valgrind + + xorg.libX11 + xorg.libXcursor + xorg.libXi + xorg.libXext + xorg.libXrandr + xorg.libXinerama + xorg.libxcb + libGL + libGLU ]; } diff --git a/src/Tupfile b/src/Tupfile index 276acb3..0da7a88 100644 --- a/src/Tupfile +++ b/src/Tupfile @@ -1,3 +1,4 @@ +include nix.tup CPPFLAGS_ = -Wall -Werror -std=c++17 -fcolor-diagnostics -g -O1 -I./3rd-party/stb CPPFLAGS_ASAN = $(CPPFLAGS_) -fsanitize=address -fno-omit-frame-pointer CPPFLAGS_THREAD = $(CPPFLAGS_) -fsanitize=thread @@ -5,5 +6,16 @@ CPPFLAGS_MEM = $(CPPFLAGS_) -fsanitize=memory -fno-omit-frame-pointer CPPFLAGS_UB = $(CPPFLAGS_) -fsanitize=undefined CPPFLAGS = $(CPPFLAGS_) -: foreach *.cpp |> ^ CXX %f^ clang++ -c %f -o %o $(CPPFLAGS) |> %B.o {objs} -: {objs} |> ^ LINK %o^ clang++ %f -o %o $(CPPFLAGS) -lpthread |> ../packing +LINK_FLAGS = -L. -lpacking + +GUI_FLAGS = -I3rd-party/raylib-4.0.0/src +GUI_LINK_FLAGS = $(LINK_FLAGS) -L3rd-party/raylib-4.0.0 -lraylib -lGL -lc -lm -lpthread -ldl -lrt -lX11 + +: foreach *.cpp ^main_cli.cpp ^main_gui.cpp ^png_impl.cpp |> ^ CXX %f^ clang++ -c %f -o %o $(CPPFLAGS) |> %B.o {objs} +: {objs} |> ^ AR %o^ ar rcs %o %f |> libpacking.a + +: foreach main_cli.cpp png_impl.cpp |> ^ CXX %f^ clang++ -c %f -o %o $(CPPFLAGS) |> %B.o {cli} +: libpacking.a {cli} |> ^ LINK %o^ clang++ %f -o %o $(LINK_FLAGS) |> ../packing_cli + +: main_gui.cpp |> ^ CXX %f^ clang++ -c %f -o %o $(CPPFLAGS) $(GUI_FLAGS) |> %B.o {gui} +: libpacking.a {gui} | 3rd-party/ |> ^ LINK %o^ clang++ %f -o %o $(GUI_LINK_FLAGS) |> ../packing_gui diff --git a/src/main_gui.cpp b/src/main_gui.cpp new file mode 100644 index 0000000..2097604 --- /dev/null +++ b/src/main_gui.cpp @@ -0,0 +1,198 @@ +/******************************************************************************************* + * + * raylib [textures] example - Image processing + * + * NOTE: Images are loaded in CPU memory (RAM); textures are loaded in GPU + *memory (VRAM) + * + * This example has been created using raylib 3.5 (www.raylib.com) + * raylib is licensed under an unmodified zlib/libpng license (View raylib.h + *for details) + * + * Copyright (c) 2016 Ramon Santamaria (@raysan5) + * + ********************************************************************************************/ + +#include "raylib.h" + +#include // Required for: free() + +#define NUM_PROCESSES 8 + +typedef enum { + NONE = 0, + COLOR_GRAYSCALE, + COLOR_TINT, + COLOR_INVERT, + COLOR_CONTRAST, + COLOR_BRIGHTNESS, + FLIP_VERTICAL, + FLIP_HORIZONTAL +} ImageProcess; + +static const char* processText[] = { + "NO PROCESSING", "COLOR GRAYSCALE", "COLOR TINT", "COLOR INVERT", + "COLOR CONTRAST", "COLOR BRIGHTNESS", "FLIP VERTICAL", "FLIP HORIZONTAL"}; + +int main(void) { + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + InitWindow(screenWidth, screenHeight, + "raylib [textures] example - image processing"); + + // NOTE: Textures MUST be loaded after Window initialization (OpenGL context + // is required) + + Image imOrigin = + LoadImage("resources/parrots.png"); // Loaded in CPU memory (RAM) + ImageFormat( + &imOrigin, + PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); // Format image to RGBA 32bit + // (required for texture update) + // <-- ISSUE + Texture2D texture = LoadTextureFromImage( + imOrigin); // Image converted to texture, GPU memory (VRAM) + + Image imCopy = ImageCopy(imOrigin); + + int currentProcess = NONE; + bool textureReload = false; + + Rectangle toggleRecs[NUM_PROCESSES] = {{0}}; + int mouseHoverRec = -1; + + for (int i = 0; i < NUM_PROCESSES; i++) + toggleRecs[i] = (Rectangle){40.0f, (float)(50 + 32 * i), 150.0f, 30.0f}; + + SetTargetFPS(60); + //--------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + + // Mouse toggle group logic + for (int i = 0; i < NUM_PROCESSES; i++) { + if (CheckCollisionPointRec(GetMousePosition(), toggleRecs[i])) { + mouseHoverRec = i; + + if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) { + currentProcess = i; + textureReload = true; + } + break; + } else + mouseHoverRec = -1; + } + + // Keyboard toggle group logic + if (IsKeyPressed(KEY_DOWN)) { + currentProcess++; + if (currentProcess > (NUM_PROCESSES - 1)) + currentProcess = 0; + textureReload = true; + } else if (IsKeyPressed(KEY_UP)) { + currentProcess--; + if (currentProcess < 0) + currentProcess = 7; + textureReload = true; + } + + // Reload texture when required + if (textureReload) { + UnloadImage(imCopy); // Unload image-copy data + imCopy = + ImageCopy(imOrigin); // Restore image-copy from image-origin + + // NOTE: Image processing is a costly CPU process to be done every + // frame, If image processing is required in a frame-basis, it + // should be done with a texture and by shaders + switch (currentProcess) { + case COLOR_GRAYSCALE: + ImageColorGrayscale(&imCopy); + break; + case COLOR_TINT: + ImageColorTint(&imCopy, GREEN); + break; + case COLOR_INVERT: + ImageColorInvert(&imCopy); + break; + case COLOR_CONTRAST: + ImageColorContrast(&imCopy, -40); + break; + case COLOR_BRIGHTNESS: + ImageColorBrightness(&imCopy, -80); + break; + case FLIP_VERTICAL: + ImageFlipVertical(&imCopy); + break; + case FLIP_HORIZONTAL: + ImageFlipHorizontal(&imCopy); + break; + default: + break; + } + + Color* pixels = LoadImageColors( + imCopy); // Load pixel data from image (RGBA 32bit) + UpdateTexture(texture, + pixels); // Update texture with new image data + UnloadImageColors(pixels); // Unload pixels data from RAM + + textureReload = false; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + + ClearBackground(RAYWHITE); + + DrawText("IMAGE PROCESSING:", 40, 30, 10, DARKGRAY); + + // Draw rectangles + for (int i = 0; i < NUM_PROCESSES; i++) { + DrawRectangleRec(toggleRecs[i], + ((i == currentProcess) || (i == mouseHoverRec)) + ? SKYBLUE + : LIGHTGRAY); + DrawRectangleLines( + (int)toggleRecs[i].x, (int)toggleRecs[i].y, + (int)toggleRecs[i].width, (int)toggleRecs[i].height, + ((i == currentProcess) || (i == mouseHoverRec)) ? BLUE : GRAY); + DrawText(processText[i], + (int)(toggleRecs[i].x + toggleRecs[i].width / 2 - + MeasureText(processText[i], 10) / 2), + (int)toggleRecs[i].y + 11, 10, + ((i == currentProcess) || (i == mouseHoverRec)) + ? DARKBLUE + : DARKGRAY); + } + + DrawTexture(texture, screenWidth - texture.width - 60, + screenHeight / 2 - texture.height / 2, WHITE); + DrawRectangleLines(screenWidth - texture.width - 60, + screenHeight / 2 - texture.height / 2, texture.width, + texture.height, BLACK); + + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadTexture(texture); // Unload texture from VRAM + UnloadImage(imOrigin); // Unload image-origin from RAM + UnloadImage(imCopy); // Unload image-copy from RAM + + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} diff --git a/src/nix.tup b/src/nix.tup new file mode 100644 index 0000000..4e0a42a --- /dev/null +++ b/src/nix.tup @@ -0,0 +1,23 @@ +export IN_NIX_SHELL +export NIX_BINTOOLS_FOR_TARGET +export NIX_BINTOOLS +export NIX_BINTOOLS_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +export NIX_BINTOOLS_WRAPPER_TARGET_TARGET_x86_64_unknown_linux_gnu +export NIX_BUILD_CORES +export NIX_BUILD_TOP +export NIX_CC_FOR_TARGET +export NIX_CC +export NIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu +export NIX_CC_WRAPPER_TARGET_TARGET_x86_64_unknown_linux_gnu +export NIX_CFLAGS_COMPILE_FOR_TARGET +export NIX_CFLAGS_COMPILE +export NIX_ENFORCE_NO_NATIVE +export NIX_HARDENING_ENABLE +export NIX_INDENT_MAKE +export NIX_LDFLAGS_FOR_TARGET +export NIX_LDFLAGS +export NIX_LOG_FD +export NIX_PATH +export NIX_PROFILES +export NIX_SSL_CERT_FILE +export NIX_STORE diff --git a/src/png.cpp b/src/png.cpp index f507c91..e87e154 100644 --- a/src/png.cpp +++ b/src/png.cpp @@ -3,7 +3,6 @@ #include #include -#define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" std::optional load_png(const std::filesystem::path& in) { diff --git a/src/png_impl.cpp b/src/png_impl.cpp new file mode 100644 index 0000000..8ddfd1f --- /dev/null +++ b/src/png_impl.cpp @@ -0,0 +1,2 @@ +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h"