Created
April 24, 2026 16:42
-
-
Save rsms/331e72a7421799e89aa1844772615db0 to your computer and use it in GitHub Desktop.
Run it with: pb run pixel-studio.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <playbit/playbit.h> | |
| #define CANVAS_MAX 64 | |
| #define PALETTE_COUNT 16 | |
| typedef enum { | |
| Tool_Brush, | |
| Tool_Rectangle, | |
| Tool_Circle, | |
| } Tool; | |
| typedef struct { | |
| int width; | |
| int height; | |
| u32 pixels[CANVAS_MAX * CANVAS_MAX]; | |
| } Canvas; | |
| typedef struct { | |
| Canvas canvas; | |
| u32 brushColor; | |
| int brushSize; | |
| Tool tool; | |
| bool eraseMode; | |
| bool gridVisible; | |
| bool pointerDown; | |
| bool pointerErasing; | |
| PBVector2 lastPoint; | |
| int dragStartX; | |
| int dragStartY; | |
| int dragEndX; | |
| int dragEndY; | |
| PBRectangle canvasRect; | |
| f32 displayScale; | |
| f32 cellSize; | |
| int cellPixels; | |
| int canvasXpx; | |
| int canvasYpx; | |
| int canvasSizePx; | |
| int hoverX; | |
| int hoverY; | |
| } State; | |
| static State g = { 0 }; | |
| static const u32 kPalette[PALETTE_COUNT] = { | |
| 0x1a1c2cff, 0x5d275dff, 0xb13e53ff, 0xef7d57ff, | |
| 0xffcd75ff, 0xa7f070ff, 0x38b764ff, 0x257179ff, | |
| 0x29366fff, 0x3b5dc9ff, 0x41a6f6ff, 0x73eff7ff, | |
| 0xf4f4f4ff, 0x94b0c2ff, 0x566c86ff, 0x333c57ff, | |
| }; | |
| static PBColor color(u32 rgba) { | |
| return PBColorFromRGBAHex(rgba); | |
| } | |
| static bool rgba_is_visible(u32 rgba) { | |
| return (rgba & 0xff) != 0; | |
| } | |
| static bool point_in_rect(PBVector2 p, PBRectangle r) { | |
| return p.x >= r.x0 && p.x < r.x1 && p.y >= r.y0 && p.y < r.y1; | |
| } | |
| static int min_int(int a, int b) { | |
| return a < b ? a : b; | |
| } | |
| static int max_int(int a, int b) { | |
| return a > b ? a : b; | |
| } | |
| static int abs_int(int x) { | |
| return x < 0 ? -x : x; | |
| } | |
| static const char* tool_name(void) { | |
| switch (g.tool) { | |
| case Tool_Rectangle: | |
| return "rect"; | |
| case Tool_Circle: | |
| return "circle"; | |
| case Tool_Brush: | |
| default: | |
| return "brush"; | |
| } | |
| } | |
| static PBRectangle rect(f32 x, f32 y, f32 w, f32 h) { | |
| return PBRectangleMake(x, y, x + w, y + h); | |
| } | |
| static int round_to_px(f32 x) { | |
| return (int)PBRoundF32(x * g.displayScale); | |
| } | |
| static f32 px_to_dp(int x) { | |
| return (f32)x / g.displayScale; | |
| } | |
| static PBRectangle rect_px(int x, int y, int w, int h) { | |
| return PBRectangleMake(px_to_dp(x), px_to_dp(y), px_to_dp(x + w), px_to_dp(y + h)); | |
| } | |
| static void draw_outline_px(int x, int y, int w, int h, int thickness, PBColor c) { | |
| PBDrawRect(rect_px(x, y, w, thickness), c); | |
| PBDrawRect(rect_px(x, y + h - thickness, w, thickness), c); | |
| PBDrawRect(rect_px(x, y, thickness, h), c); | |
| PBDrawRect(rect_px(x + w - thickness, y, thickness, h), c); | |
| } | |
| static void fit_canvas(PBVector2 windowSize) { | |
| PBWindow window = PBWindowMain(); | |
| g.displayScale = PBWindowGetScale(window); | |
| if (g.displayScale <= 0) { | |
| g.displayScale = 1; | |
| } | |
| int windowWpx = round_to_px(windowSize.x); | |
| int windowHpx = round_to_px(windowSize.y); | |
| int leftPx = round_to_px(232); | |
| int topPx = round_to_px(24); | |
| int rightPx = round_to_px(24); | |
| int bottomPx = round_to_px(48); | |
| int maxWpx = windowWpx - leftPx - rightPx; | |
| int maxHpx = windowHpx - topPx - bottomPx; | |
| int maxSizePx = min_int(maxWpx, maxHpx); | |
| g.cellPixels = maxSizePx / g.canvas.width; | |
| if (g.cellPixels < 1) { | |
| g.cellPixels = 1; | |
| } | |
| g.canvasSizePx = g.cellPixels * g.canvas.width; | |
| g.canvasXpx = leftPx + max_int(0, (maxWpx - g.canvasSizePx) / 2); | |
| g.canvasYpx = topPx + max_int(0, (maxHpx - g.canvasSizePx) / 2); | |
| g.cellSize = px_to_dp(g.cellPixels); | |
| g.canvasRect = rect_px(g.canvasXpx, g.canvasYpx, g.canvasSizePx, g.canvasSizePx); | |
| } | |
| static void update_layout(void) { | |
| PBVector2 windowSize = PBWindowGetSize(PBWindowMain()); | |
| fit_canvas(windowSize); | |
| } | |
| static void reset_canvas(int size) { | |
| if (size < 8) { | |
| size = 8; | |
| } | |
| if (size > CANVAS_MAX) { | |
| size = CANVAS_MAX; | |
| } | |
| g.canvas.width = size; | |
| g.canvas.height = size; | |
| for (int i = 0; i < CANVAS_MAX * CANVAS_MAX; i += 1) { | |
| g.canvas.pixels[i] = 0x00000000; | |
| } | |
| update_layout(); | |
| } | |
| static int pixel_index(int x, int y) { | |
| return y * g.canvas.width + x; | |
| } | |
| static PBRectangle cell_rect(int x, int y) { | |
| return rect_px( | |
| g.canvasXpx + x * g.cellPixels, | |
| g.canvasYpx + y * g.cellPixels, | |
| g.cellPixels, | |
| g.cellPixels); | |
| } | |
| static void paint_pixel(int x, int y, bool erase) { | |
| int half = g.brushSize / 2; | |
| for (int yy = y - half; yy <= y + half; yy += 1) { | |
| for (int xx = x - half; xx <= x + half; xx += 1) { | |
| if (xx >= 0 && xx < g.canvas.width && yy >= 0 && yy < g.canvas.height) { | |
| g.canvas.pixels[pixel_index(xx, yy)] = erase ? 0x00000000 : g.brushColor; | |
| } | |
| } | |
| } | |
| } | |
| static void draw_preview_pixel(int x, int y, bool erase) { | |
| u32 previewColor = erase ? 0x111111aa : ((g.brushColor & 0xffffff00) | 0xaa); | |
| int half = g.brushSize / 2; | |
| for (int yy = y - half; yy <= y + half; yy += 1) { | |
| for (int xx = x - half; xx <= x + half; xx += 1) { | |
| if (xx >= 0 && xx < g.canvas.width && yy >= 0 && yy < g.canvas.height) { | |
| PBDrawRect(cell_rect(xx, yy), color(previewColor)); | |
| } | |
| } | |
| } | |
| } | |
| static void plot_pixel(int x, int y, bool erase, bool preview) { | |
| if (preview) { | |
| draw_preview_pixel(x, y, erase); | |
| } else { | |
| paint_pixel(x, y, erase); | |
| } | |
| } | |
| static bool point_to_pixel(PBVector2 point, int* outX, int* outY) { | |
| if (!point_in_rect(point, g.canvasRect)) { | |
| return false; | |
| } | |
| int x = ((int)(point.x * g.displayScale) - g.canvasXpx) / g.cellPixels; | |
| int y = ((int)(point.y * g.displayScale) - g.canvasYpx) / g.cellPixels; | |
| if (x < 0 || x >= g.canvas.width || y < 0 || y >= g.canvas.height) { | |
| return false; | |
| } | |
| *outX = x; | |
| *outY = y; | |
| return true; | |
| } | |
| static void paint_line_pixels(int x0, int y0, int x1, int y1, bool erase, bool preview) { | |
| int dx = (int)PBAbsF32((f32)(x1 - x0)); | |
| int dy = -(int)PBAbsF32((f32)(y1 - y0)); | |
| int sx = x0 < x1 ? 1 : -1; | |
| int sy = y0 < y1 ? 1 : -1; | |
| int err = dx + dy; | |
| for (;;) { | |
| plot_pixel(x0, y0, erase, preview); | |
| if (x0 == x1 && y0 == y1) { | |
| break; | |
| } | |
| int e2 = 2 * err; | |
| if (e2 >= dy) { | |
| err += dy; | |
| x0 += sx; | |
| } | |
| if (e2 <= dx) { | |
| err += dx; | |
| y0 += sy; | |
| } | |
| } | |
| } | |
| static void paint_line(PBVector2 from, PBVector2 to, bool erase) { | |
| int x0 = 0; | |
| int y0 = 0; | |
| int x1 = 0; | |
| int y1 = 0; | |
| if (!point_to_pixel(from, &x0, &y0)) { | |
| if (!point_to_pixel(to, &x0, &y0)) { | |
| return; | |
| } | |
| } | |
| if (!point_to_pixel(to, &x1, &y1)) { | |
| return; | |
| } | |
| paint_line_pixels(x0, y0, x1, y1, erase, false); | |
| } | |
| static void paint_rect_shape(int x0, int y0, int x1, int y1, bool erase, bool preview) { | |
| int left = min_int(x0, x1); | |
| int right = max_int(x0, x1); | |
| int top = min_int(y0, y1); | |
| int bottom = max_int(y0, y1); | |
| paint_line_pixels(left, top, right, top, erase, preview); | |
| paint_line_pixels(right, top, right, bottom, erase, preview); | |
| paint_line_pixels(right, bottom, left, bottom, erase, preview); | |
| paint_line_pixels(left, bottom, left, top, erase, preview); | |
| } | |
| static void plot_circle_points(int cx, int cy, int x, int y, bool erase, bool preview) { | |
| plot_pixel(cx + x, cy + y, erase, preview); | |
| plot_pixel(cx + y, cy + x, erase, preview); | |
| plot_pixel(cx - y, cy + x, erase, preview); | |
| plot_pixel(cx - x, cy + y, erase, preview); | |
| plot_pixel(cx - x, cy - y, erase, preview); | |
| plot_pixel(cx - y, cy - x, erase, preview); | |
| plot_pixel(cx + y, cy - x, erase, preview); | |
| plot_pixel(cx + x, cy - y, erase, preview); | |
| } | |
| static void paint_circle_shape(int x0, int y0, int x1, int y1, bool erase, bool preview) { | |
| int radius = max_int(abs_int(x1 - x0), abs_int(y1 - y0)); | |
| int x = radius; | |
| int y = 0; | |
| int err = 0; | |
| if (radius == 0) { | |
| plot_pixel(x0, y0, erase, preview); | |
| return; | |
| } | |
| while (x >= y) { | |
| plot_circle_points(x0, y0, x, y, erase, preview); | |
| y += 1; | |
| if (err <= 0) { | |
| err += 2 * y + 1; | |
| } | |
| if (err > 0) { | |
| x -= 1; | |
| err -= 2 * x + 1; | |
| } | |
| } | |
| } | |
| static void paint_shape(bool preview) { | |
| bool erase = g.eraseMode || g.pointerErasing; | |
| if (g.tool == Tool_Rectangle) { | |
| paint_rect_shape(g.dragStartX, g.dragStartY, g.dragEndX, g.dragEndY, erase, preview); | |
| } else if (g.tool == Tool_Circle) { | |
| paint_circle_shape(g.dragStartX, g.dragStartY, g.dragEndX, g.dragEndY, erase, preview); | |
| } | |
| } | |
| static PBRectangle tool_button_rect(int col) { | |
| return rect(24 + (f32)col * 60, 248, 56, 32); | |
| } | |
| static PBRectangle panel_button_rect(int row) { | |
| return rect(24, 290 + (f32)row * 42, 176, 32); | |
| } | |
| static PBRectangle palette_rect(int index) { | |
| int col = index % 4; | |
| int row = index / 4; | |
| return rect(24 + (f32)col * 42, 74 + (f32)row * 42, 32, 32); | |
| } | |
| static bool button(PBRectangle bounds, PBStrSlice label, bool active) { | |
| PBColor fill = active ? color(0x2d6cdfef) : color(0x242936ff); | |
| PBColor stroke = active ? color(0x79a8ffff) : color(0x3d4355ff); | |
| PBDrawRect(bounds, fill); | |
| PBDrawRectInset(bounds, stroke, 1, PBV4(0, 0, 0, 0)); | |
| PBDrawText( | |
| PBUIFontMake(PB_STR("Inter"), 13, 600), | |
| label, | |
| color(0xf2f4f8ff), | |
| PBRectangleMake(bounds.x0 + 10, bounds.y0 + 8, bounds.x1 - 8, bounds.y1 - 4)); | |
| return false; | |
| } | |
| static void draw_panel(void) { | |
| PBVector2 windowSize = PBWindowGetSize(PBWindowMain()); | |
| PBDrawRect(rect(0, 0, windowSize.x, windowSize.y), color(0x151820ff)); | |
| PBDrawRect(rect(0, 0, 208, windowSize.y), color(0x1d222dff)); | |
| PBDrawText( | |
| PBUIFontMake(PB_STR("Inter"), 20, 700), | |
| PB_STR("Pixel Studio"), | |
| color(0xf6f7fbff), | |
| rect(24, 22, 170, 28)); | |
| for (int i = 0; i < PALETTE_COUNT; i += 1) { | |
| PBRectangle r = palette_rect(i); | |
| PBDrawRect(r, color(kPalette[i])); | |
| if (!g.eraseMode && g.brushColor == kPalette[i]) { | |
| PBDrawRectInset(PBRectangleMake(r.x0 - 3, r.y0 - 3, r.x1 + 3, r.y1 + 3), color(0xffffffff), 2, PBV4(0, 0, 0, 0)); | |
| } else { | |
| PBDrawRectInset(r, color(0x00000080), 1, PBV4(0, 0, 0, 0)); | |
| } | |
| } | |
| button(tool_button_rect(0), PB_STR("Brush"), g.tool == Tool_Brush); | |
| button(tool_button_rect(1), PB_STR("Rect"), g.tool == Tool_Rectangle); | |
| button(tool_button_rect(2), PB_STR("Circle"), g.tool == Tool_Circle); | |
| button(panel_button_rect(0), g.eraseMode ? PB_STR("Eraser") : PB_STR("Paint"), g.eraseMode); | |
| button(panel_button_rect(1), PB_STR("Clear"), false); | |
| PBRectangle brush1 = rect(24, 382, 52, 32); | |
| PBRectangle brush2 = rect(86, 382, 52, 32); | |
| PBRectangle brush3 = rect(148, 382, 52, 32); | |
| button(brush1, PB_STR("1"), g.brushSize == 1); | |
| button(brush2, PB_STR("3"), g.brushSize == 3); | |
| button(brush3, PB_STR("5"), g.brushSize == 5); | |
| PBRectangle size16 = rect(24, 436, 52, 32); | |
| PBRectangle size32 = rect(86, 436, 52, 32); | |
| PBRectangle size64 = rect(148, 436, 52, 32); | |
| button(size16, PB_STR("16"), g.canvas.width == 16); | |
| button(size32, PB_STR("32"), g.canvas.width == 32); | |
| button(size64, PB_STR("64"), g.canvas.width == 64); | |
| button(rect(24, 490, 176, 32), g.gridVisible ? PB_STR("Grid on") : PB_STR("Grid off"), g.gridVisible); | |
| PBDrawText( | |
| PBUIFontMake(PB_STR("Inter"), 13, 500), | |
| UIfmt("%s %dx%d b%d", tool_name(), g.canvas.width, g.canvas.height, g.brushSize), | |
| color(0xaeb6c4ff), | |
| rect(24, windowSize.y - 34, 176, 22)); | |
| } | |
| static void draw_canvas(void) { | |
| int padPx = round_to_px(12); | |
| int minBgXpx = round_to_px(208); | |
| int bgXpx = max_int(minBgXpx, g.canvasXpx - padPx); | |
| int bgYpx = max_int(0, g.canvasYpx - padPx); | |
| PBDrawRect( | |
| rect_px( | |
| bgXpx, | |
| bgYpx, | |
| g.canvasSizePx + padPx * 2 - (bgXpx - (g.canvasXpx - padPx)), | |
| g.canvasSizePx + padPx * 2 - (bgYpx - (g.canvasYpx - padPx))), | |
| color(0x0f1218ff)); | |
| for (int y = 0; y < g.canvas.height; y += 1) { | |
| for (int x = 0; x < g.canvas.width; x += 1) { | |
| PBRectangle cell = cell_rect(x, y); | |
| u32 checker = ((x + y) & 1) ? 0xd8dde5ff : 0xf3f5f8ff; | |
| PBDrawRect(cell, color(checker)); | |
| u32 pixel = g.canvas.pixels[pixel_index(x, y)]; | |
| if (rgba_is_visible(pixel)) { | |
| PBDrawRect(cell, color(pixel)); | |
| } | |
| } | |
| } | |
| if (g.gridVisible && g.cellPixels >= 8) { | |
| PBColor gridColor = color(0x00000030); | |
| for (int x = 1; x < g.canvas.width; x += 1) { | |
| int lineX = g.canvasXpx + x * g.cellPixels; | |
| PBDrawRect(rect_px(lineX, g.canvasYpx, 1, g.canvasSizePx), gridColor); | |
| } | |
| for (int y = 1; y < g.canvas.height; y += 1) { | |
| int lineY = g.canvasYpx + y * g.cellPixels; | |
| PBDrawRect(rect_px(g.canvasXpx, lineY, g.canvasSizePx, 1), gridColor); | |
| } | |
| } | |
| if (g.pointerDown && g.tool != Tool_Brush) { | |
| paint_shape(true); | |
| } | |
| draw_outline_px(g.canvasXpx, g.canvasYpx, g.canvasSizePx, g.canvasSizePx, 2, color(0xffffffff)); | |
| if (g.hoverX >= 0 && g.hoverY >= 0 && g.cellPixels >= 5) { | |
| int half = g.brushSize / 2; | |
| int x0 = g.hoverX - half; | |
| int y0 = g.hoverY - half; | |
| int x1 = g.hoverX + half + 1; | |
| int y1 = g.hoverY + half + 1; | |
| if (x0 < 0) { | |
| x0 = 0; | |
| } | |
| if (y0 < 0) { | |
| y0 = 0; | |
| } | |
| if (x1 > g.canvas.width) { | |
| x1 = g.canvas.width; | |
| } | |
| if (y1 > g.canvas.height) { | |
| y1 = g.canvas.height; | |
| } | |
| draw_outline_px( | |
| g.canvasXpx + x0 * g.cellPixels, | |
| g.canvasYpx + y0 * g.cellPixels, | |
| (x1 - x0) * g.cellPixels, | |
| (y1 - y0) * g.cellPixels, | |
| 2, | |
| (g.eraseMode || g.pointerErasing) ? color(0x111111dd) : color(0xffffffff)); | |
| } | |
| } | |
| static void handle_panel_click(PBVector2 p) { | |
| for (int i = 0; i < PALETTE_COUNT; i += 1) { | |
| if (point_in_rect(p, palette_rect(i))) { | |
| g.brushColor = kPalette[i]; | |
| g.eraseMode = false; | |
| return; | |
| } | |
| } | |
| if (point_in_rect(p, tool_button_rect(0))) { | |
| g.tool = Tool_Brush; | |
| } else if (point_in_rect(p, tool_button_rect(1))) { | |
| g.tool = Tool_Rectangle; | |
| } else if (point_in_rect(p, tool_button_rect(2))) { | |
| g.tool = Tool_Circle; | |
| } else if (point_in_rect(p, panel_button_rect(0))) { | |
| g.eraseMode = !g.eraseMode; | |
| } else if (point_in_rect(p, panel_button_rect(1))) { | |
| for (int i = 0; i < CANVAS_MAX * CANVAS_MAX; i += 1) { | |
| g.canvas.pixels[i] = 0x00000000; | |
| } | |
| } else if (point_in_rect(p, rect(24, 382, 52, 32))) { | |
| g.brushSize = 1; | |
| } else if (point_in_rect(p, rect(86, 382, 52, 32))) { | |
| g.brushSize = 3; | |
| } else if (point_in_rect(p, rect(148, 382, 52, 32))) { | |
| g.brushSize = 5; | |
| } else if (point_in_rect(p, rect(24, 436, 52, 32))) { | |
| reset_canvas(16); | |
| } else if (point_in_rect(p, rect(86, 436, 52, 32))) { | |
| reset_canvas(32); | |
| } else if (point_in_rect(p, rect(148, 436, 52, 32))) { | |
| reset_canvas(64); | |
| } else if (point_in_rect(p, rect(24, 490, 176, 32))) { | |
| g.gridVisible = !g.gridVisible; | |
| } | |
| } | |
| static bool pointer_event_erases(PBPointerEvent* event) { | |
| return event->button == PBMouseButton_Right || (event->buttons & (1u << PBMouseButton_Right)); | |
| } | |
| static void on_pointer(PBPointerEvent* event, PBEventType type) { | |
| PBVector2 point = PBV2(event->x, event->y); | |
| int px = -1; | |
| int py = -1; | |
| if (point_to_pixel(point, &px, &py)) { | |
| g.hoverX = px; | |
| g.hoverY = py; | |
| } else { | |
| g.hoverX = -1; | |
| g.hoverY = -1; | |
| } | |
| if (type == PBEventType_POINTER_DOWN) { | |
| if (point_in_rect(point, g.canvasRect)) { | |
| g.pointerDown = true; | |
| g.pointerErasing = pointer_event_erases(event); | |
| g.lastPoint = point; | |
| point_to_pixel(point, &g.dragStartX, &g.dragStartY); | |
| g.dragEndX = g.dragStartX; | |
| g.dragEndY = g.dragStartY; | |
| if (g.tool == Tool_Brush) { | |
| paint_line(point, point, g.eraseMode || g.pointerErasing); | |
| } | |
| } else { | |
| g.pointerDown = false; | |
| g.pointerErasing = false; | |
| handle_panel_click(point); | |
| } | |
| } else if (type == PBEventType_POINTER_UP) { | |
| if (g.pointerDown && g.tool != Tool_Brush && point_to_pixel(point, &px, &py)) { | |
| g.dragEndX = px; | |
| g.dragEndY = py; | |
| paint_shape(false); | |
| } | |
| g.pointerDown = false; | |
| g.pointerErasing = false; | |
| } else if (type == PBEventType_POINTER_MOVE && g.pointerDown) { | |
| if (pointer_event_erases(event)) { | |
| g.pointerErasing = true; | |
| } | |
| if (g.tool == Tool_Brush) { | |
| paint_line(g.lastPoint, point, g.eraseMode || g.pointerErasing); | |
| } else if (px >= 0 && py >= 0) { | |
| g.dragEndX = px; | |
| g.dragEndY = py; | |
| } | |
| g.lastPoint = point; | |
| } | |
| } | |
| static void on_event(const PBEvent* ev) { | |
| if (ev->type == PBEventType_POINTER_DOWN || ev->type == PBEventType_POINTER_UP | |
| || ev->type == PBEventType_POINTER_MOVE) | |
| { | |
| on_pointer((PBPointerEvent*)ev, ev->type); | |
| } else if (ev->type == PBEventType_KEY_DOWN) { | |
| PBKeyboardEvent* event = (PBKeyboardEvent*)ev; | |
| if (event->keyCode == PBKeyboardKey_E) { | |
| g.eraseMode = !g.eraseMode; | |
| } else if (event->keyCode == PBKeyboardKey_G) { | |
| g.gridVisible = !g.gridVisible; | |
| } else if (event->keyCode == PBKeyboardKey_B) { | |
| g.tool = Tool_Brush; | |
| } else if (event->keyCode == PBKeyboardKey_R) { | |
| g.tool = Tool_Rectangle; | |
| } else if (event->keyCode == PBKeyboardKey_C) { | |
| g.tool = Tool_Circle; | |
| } else if (event->keyCode == PBKeyboardKey_1) { | |
| g.brushSize = 1; | |
| } else if (event->keyCode == PBKeyboardKey_2) { | |
| g.brushSize = 3; | |
| } else if (event->keyCode == PBKeyboardKey_3) { | |
| g.brushSize = 5; | |
| } | |
| } else if (ev->type == PBEventType_SIGNAL) { | |
| PBSignalEvent* event = (PBSignalEvent*)ev; | |
| if (event->signals & PBSysWindowSignal_RESIZE) { | |
| update_layout(); | |
| } | |
| } | |
| } | |
| static void render(void) { | |
| update_layout(); | |
| draw_panel(); | |
| draw_canvas(); | |
| } | |
| void main(void) { | |
| PBWindow window = PBWindowMain(); | |
| PBWindowSetTitle(window, PB_STR("Pixel Studio")); | |
| g.brushColor = kPalette[0]; | |
| g.brushSize = 1; | |
| g.tool = Tool_Brush; | |
| g.gridVisible = true; | |
| g.hoverX = -1; | |
| g.hoverY = -1; | |
| reset_canvas(32); | |
| PBApp.onEvent = on_event; | |
| PBApp.onRender = render; | |
| PBAppMain(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment