SHARE
TWEET

Untitled

a guest Aug 25th, 2019 77 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // compile in ubuntu:
  2. // $ zig build-exe paint.zig --library SDL2 --library SDL2main --library c -isystem "/usr/include" --library-path "/usr/lib/x86_64-linux-gnu"
  3.  
  4. const std = @import("std");
  5. const warn = std.debug.warn;
  6. const fmt = std.fmt;
  7.  
  8. const c = @cImport({
  9.     @cInclude("SDL2/SDL.h");
  10. });
  11. const assert = @import("std").debug.assert;
  12.  
  13. const SDL_WINDOWPOS_UNDEFINED = @bitCast(c_int, c.SDL_WINDOWPOS_UNDEFINED_MASK);
  14. const SDL_INIT_EVERYTHING =
  15.     c.SDL_INIT_TIMER |
  16.     c.SDL_INIT_AUDIO |
  17.     c.SDL_INIT_VIDEO |
  18.     c.SDL_INIT_EVENTS |
  19.     c.SDL_INIT_JOYSTICK |
  20.     c.SDL_INIT_HAPTIC |
  21.     c.SDL_INIT_GAMECONTROLLER;
  22.  
  23. extern fn SDL_PollEvent(event: *c.SDL_Event) c_int;
  24.  
  25. var W : usize = 600;
  26. var H : usize = 600;
  27.  
  28. const Color = struct {
  29.     color : [4]u8 = [4]u8{0, 0, 0, 0},
  30.  
  31.     pub fn r(self : Color) u8
  32.         { return self.colorc[0]; }
  33.     pub fn g(self : Color) u8
  34.         { return self.color[1]; }
  35.     pub fn b(self : Color) u8
  36.         { return self.color[2]; }
  37.     pub fn a(self : Color) u8
  38.         { return self.color[3]; }
  39.     pub fn setR(self : Color, val : u8) void
  40.         { self.color[0] = val; }
  41.     pub fn setG(self : Color, val : u8) void
  42.         { self.color[1] = val; }
  43.     pub fn setB(self : Color, val : u8) void
  44.         { self.color[2] = val; }
  45.     pub fn setA(self : Color, val : u8) void
  46.         { self.color[3] = val; }
  47.  
  48.     pub fn white() Color {
  49.         var color = Color{.color = [4]u8{255, 255, 255, 255}};
  50.         return color;
  51.     }
  52.  
  53.     pub fn black() Color {
  54.         var color = Color{.color = [4]u8{0, 0, 0, 255}};
  55.         return color;
  56.     }
  57. };
  58.  
  59. const Vec2 = struct {
  60.     x : f64,
  61.     y : f64,
  62. };
  63.  
  64. pub fn dot(a: Vec2, b: Vec2) f64 {
  65.     return a.x * b.x + a.y * b.y;
  66. }
  67.  
  68. pub fn norm(a: Vec2) Vec2 {
  69.     const len = @sqrt(f64, dot(a, a));
  70.     return Vec2{
  71.         .x = a.x / len,
  72.         .y = a.y / len
  73.     };
  74. }
  75.  
  76. pub fn scale(a: Vec2, b: f64) Vec2 {
  77.     return Vec2 {
  78.         .x = a.x * b,
  79.         .y = a.y * b
  80.     };
  81. }
  82.  
  83. const PixelBuffers = struct {
  84.     const pixelsCapacity = 4000*4000;
  85.     buffers : [2][pixelsCapacity]Color,
  86.     frontIndex : usize,
  87.     w : usize,
  88.     h : usize,
  89.  
  90.     pub fn init(self : *PixelBuffers, nW : usize, nH : usize) void {
  91.         self.*.frontIndex = 1;
  92.         self.*.w = nW;
  93.         self.*.h = nH;
  94.         var y : usize = 0;
  95.         while(y < nH) {
  96.             var x : usize = 0;
  97.             while(x < nW) {
  98.                 self.*.buffers[0][x + nW * y] = Color.black();
  99.                 self.*.buffers[1][x + nW * y] = Color.black();
  100.                 x += 1;
  101.             }
  102.             y += 1;
  103.         }
  104.     }
  105.  
  106.     pub fn write(self : *PixelBuffers, x : c_int, y : c_int, color : Color) void {
  107.         if(x >= 0 and y >= 0 and x < @intCast(c_int, W) and y < @intCast(c_int, H)) {
  108.             const ux = @intCast(usize, x);
  109.             const uy = @intCast(usize, y);
  110.             self.*.buffers[self.frontIndex][ux + self.*.w * uy] = color;
  111.         }
  112.     }
  113.  
  114.     pub fn drawThickLine(self : *PixelBuffers,
  115.         xFrom : c_int, yFrom : c_int, xTo : c_int, yTo : c_int,
  116.         color : Color, thickness : f64) void
  117.     {
  118.         const thickness2 = thickness * thickness;
  119.         var x0 : c_int = undefined;
  120.         var x1 : c_int = undefined;
  121.         var y0 : c_int = undefined;
  122.         var y1 : c_int = undefined;
  123.         if(xFrom < xTo) {
  124.             x0 = xFrom;
  125.             x1 = xTo;
  126.         }
  127.         else {
  128.             x0 = xTo;
  129.             x1 = xFrom;
  130.         }
  131.         if(yFrom < yTo) {
  132.             y0 = yFrom;
  133.             y1 = yTo;
  134.         }
  135.         else {
  136.             y0 = yTo;
  137.             y1 = yFrom;
  138.         }
  139.  
  140.         if(x0 == x1 and y0 == y1) {
  141.             return;
  142.         }
  143.  
  144.         const intThickness = @floatToInt(c_int, @ceil(f64, thickness));
  145.         const X0 = x0 - intThickness;
  146.         const Y0 = y0 - intThickness;
  147.         const X1 = x1 + intThickness;
  148.         const Y1 = y1 + intThickness;
  149.  
  150.         const v01 = Vec2 {
  151.             .x = @intToFloat(f64, xTo - xFrom),
  152.             .y = @intToFloat(f64, yTo - yFrom)
  153.         };
  154.  
  155.         var iy : c_int = Y0;
  156.         while(iy <= Y1) {
  157.             const y : f64 = @intToFloat(f64, iy);
  158.             var ix : c_int = X0;
  159.             while(ix <= X1) {
  160.                 const x : f64 = @intToFloat(f64, ix);
  161.                 const v = Vec2 {
  162.                     .x = x - @intToFloat(f64, xFrom),
  163.                     .y = y - @intToFloat(f64, yFrom)
  164.                 };
  165.                 const h1 = dot(v, v);
  166.                 const c1 = dot(norm(v01), v) * dot(norm(v01), v);
  167.                 const distToLine2 : f64 = h1 - c1;
  168.                 assert(distToLine2 > -0.001);
  169.                 if(distToLine2 < thickness2) {
  170.                     self.write(ix, iy, color);
  171.                 }
  172.                 ix += 1;
  173.             }
  174.             iy += 1;
  175.         }
  176.     }
  177.  
  178.     pub fn drawLine(self : *PixelBuffers,
  179.         xFrom : c_int, yFrom : c_int, xTo : c_int, yTo : c_int,
  180.         color : Color) void
  181.     {
  182.         if(xFrom == xTo and yFrom == yTo) {
  183.             self.write(xFrom, yFrom, color);
  184.         }
  185.         var x0 : c_int = undefined;
  186.         var x1 : c_int = undefined;
  187.         var y0 : c_int = undefined;
  188.         var y1 : c_int = undefined;
  189.         var invX : bool = undefined;
  190.         var invY : bool = undefined;
  191.         if(xFrom < xTo) {
  192.             x0 = xFrom;
  193.             x1 = xTo;
  194.             invX = false;
  195.         }
  196.         else {
  197.             x0 = xTo;
  198.             x1 = xFrom;
  199.             invX = true;
  200.         }
  201.         if(yFrom < yTo) {
  202.             y0 = yFrom;
  203.             y1 = yTo;
  204.             invY = false;
  205.         }
  206.         else {
  207.             y0 = yTo;
  208.             y1 = yFrom;
  209.             invY = true;
  210.         }
  211.         if(x1 - x0 < y1 - y0) {
  212.             var y : c_int = y0;
  213.             while(y <= y1) {
  214.                 const inc = @divFloor((x1 - x0 + 1) * (y - y0), y1 - y0 + 1);
  215.                 const x = block: {
  216.                     if(invX == invY) {
  217.                         break :block x0 + inc;
  218.                     }
  219.                     else {
  220.                         break :block x1 - inc;
  221.                     }
  222.                 };
  223.                 write(self, x, y, color);
  224.                 y += 1;
  225.             }
  226.         }
  227.         else {
  228.             var x : c_int = x0;
  229.             while(x <= x1) {
  230.                 const inc = @divFloor((y1 - y0 + 1) * (x - x0), x1 - x0 + 1);
  231.                 const y = block: {
  232.                     if(invX == invY) {
  233.                         break :block y0 + inc;
  234.                     }
  235.                     else {
  236.                         break :block y1 - inc;
  237.                     }
  238.                 };
  239.                 write(self, x, y, color);
  240.                 x += 1;
  241.             }
  242.         }
  243.     }
  244.  
  245.     pub fn resize(self : *PixelBuffers, nW : usize, nH : usize) void {
  246.         const front = self.*.frontIndex;
  247.         const back = front ^ 1;
  248.         var y : usize = 0;
  249.         while(y < nH) {
  250.             var x : usize = 0;
  251.             while(x < nW) {
  252.                 self.*.buffers[back][x + nW * y] = Color.black();
  253.                 x += 1;
  254.             }
  255.             y += 1;
  256.         }
  257.  
  258.         y = 0;
  259.         while(y < std.math.min(self.*.h, nH)) {
  260.             var x : usize = 0;
  261.             while(x < std.math.min(self.*.w, nW)) {
  262.                 self.*.buffers[back][x + nW * y] = self.*.buffers[front][x + self.*.w * y];
  263.                 x += 1;
  264.             }
  265.             y += 1;
  266.         }
  267.  
  268.         self.*.w = nW;
  269.         self.*.h = nH;
  270.  
  271.         self.swapBuffers();
  272.     }
  273.  
  274.     fn swapBuffers(self: *PixelBuffers) void {
  275.         self.*.frontIndex = self.*.frontIndex ^ 1;
  276.     }
  277.  
  278.     pub fn updateTexture(self : *PixelBuffers, texture : *c.SDL_Texture) void {
  279.         var pixelsPtr = @ptrCast(*c_void, &self.*.buffers[self.frontIndex][0]);
  280.         _= c.SDL_UpdateTexture(texture,
  281.             0, pixelsPtr,
  282.             @intCast(c_int, self.w * @sizeOf(u32))
  283.         );
  284.     }
  285.  
  286. };
  287.  
  288. pub fn getMousePos(window: *c.SDL_Window, mx : *c_int, my : *c_int) void
  289. {
  290.     _= c.SDL_GetGlobalMouseState(mx, my);
  291.     var wx : c_int = undefined;
  292.     var wy : c_int = undefined;
  293.     c.SDL_GetWindowPosition(window, &wx, &wy);
  294.     mx.* = mx.* - wx;
  295.     my.* = my.*- wy;
  296. }
  297.  
  298. var pixels : PixelBuffers = undefined;
  299.  
  300. pub fn main() !void
  301. {
  302.     if (c.SDL_Init(SDL_INIT_EVERYTHING) != 0) {
  303.         c.SDL_Log(c"Unable to initialize SDL: %s", c.SDL_GetError());
  304.         return error.SDLInitializationFailed;
  305.     }
  306.     defer c.SDL_Quit();
  307.  
  308.     const window = c.SDL_CreateWindow(c"Paint",
  309.         SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
  310.         @intCast(c_int, W), @intCast(c_int, H),
  311.         c.SDL_WINDOW_OPENGL | c.SDL_WINDOW_RESIZABLE) orelse
  312.     {
  313.         c.SDL_Log(c"Unable to create window: %s", c.SDL_GetError());
  314.         return error.SDLInitializationFailed;
  315.     };
  316.     defer c.SDL_DestroyWindow(window);
  317.  
  318.     const renderer = c.SDL_CreateRenderer(window, -1, 0) orelse {
  319.         c.SDL_Log(c"Unable to create renderer: %s", c.SDL_GetError());
  320.         return error.SDLInitializationFailed;
  321.     };
  322.     defer c.SDL_DestroyRenderer(renderer);
  323.  
  324.     pixels.init(W, H);
  325.  
  326.     var texture = c.SDL_CreateTexture(
  327.         renderer,
  328.         c.SDL_PIXELFORMAT_ABGR8888, c.SDL_TEXTUREACCESS_STATIC,
  329.         @intCast(c_int, W), @intCast(c_int, H));
  330.  
  331.     if(texture != null) {
  332.         pixels.updateTexture(@ptrCast(*c.SDL_Texture, texture));
  333.         _= c.SDL_RenderClear(renderer);
  334.         _= c.SDL_RenderCopy(renderer, texture, 0, 0);
  335.     }
  336.  
  337.     var mouseLeftPressed = false;
  338.     var mouseRightPressed = false;
  339.     var prevMouseX : c_int = undefined;
  340.     var prevMouseY : c_int = undefined;
  341.  
  342.     var quit = false;
  343.     while (!quit) {
  344.        
  345.         var cx : c_int = undefined;
  346.         var cy : c_int = undefined;
  347.         _= getMousePos(window, &cx, &cy);
  348.  
  349.         var event: c.SDL_Event = undefined;
  350.         while (SDL_PollEvent(&event) != 0) {
  351.             switch (event.@"type") {
  352.                 c.SDL_QUIT => {
  353.                     quit = true;
  354.                 },
  355.                 c.SDL_MOUSEBUTTONUP => {
  356.                     if(event.button.button == c.SDL_BUTTON_LEFT) {
  357.                         mouseLeftPressed = false;
  358.                     }
  359.                     else if(event.button.button == c.SDL_BUTTON_RIGHT) {
  360.                         mouseRightPressed = false;
  361.                     }
  362.                 },
  363.                 c.SDL_MOUSEBUTTONDOWN => {
  364.                     if(event.button.button == c.SDL_BUTTON_LEFT) {
  365.                         if(!mouseLeftPressed) {
  366.                             prevMouseX = cx;
  367.                             prevMouseY = cy;
  368.                         }
  369.                         mouseLeftPressed = true;
  370.                     }
  371.                     else if(event.button.button == c.SDL_BUTTON_RIGHT) {
  372.                         if(!mouseRightPressed) {
  373.                             prevMouseX = cx;
  374.                             prevMouseY = cy;
  375.                         }
  376.                         mouseRightPressed = true;
  377.                     }
  378.                 },
  379.                 c.SDL_WINDOWEVENT => {
  380.                     if(event.window.event == @intCast(u32, c.SDL_WINDOWEVENT_RESIZED)) {
  381.                         W = @intCast(usize, event.window.data1);
  382.                         H = @intCast(usize, event.window.data2);
  383.                         pixels.resize(W, H);
  384.                         c.SDL_DestroyTexture(texture);
  385.                         texture = c.SDL_CreateTexture(
  386.                             renderer,
  387.                             c.SDL_PIXELFORMAT_ABGR8888, c.SDL_TEXTUREACCESS_STATIC,
  388.                             @intCast(c_int, W), @intCast(c_int, H));
  389.                     }
  390.                 },
  391.                 else => {},
  392.             }
  393.         }
  394.  
  395.         if(mouseLeftPressed or mouseRightPressed) {
  396.             if(mouseLeftPressed) {
  397.                 pixels.drawLine(prevMouseX, prevMouseY, cx, cy, Color.white());
  398.             }
  399.             else if(mouseRightPressed) {
  400.                 pixels.drawThickLine(prevMouseX, prevMouseY, cx, cy, Color.black(), 6);
  401.             }
  402.             prevMouseX = cx;
  403.             prevMouseY = cy;
  404.         }
  405.        
  406.         if(texture != null) {
  407.             pixels.updateTexture(@ptrCast(*c.SDL_Texture, texture));
  408.             _= c.SDL_RenderClear(renderer);
  409.             _= c.SDL_RenderCopy(renderer, texture, 0, 0);
  410.         }
  411.  
  412.         _= c.SDL_RenderPresent(renderer);
  413.  
  414.         c.SDL_Delay(1);
  415.     }
  416. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top