Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // compile in ubuntu:
- // $ zig build-exe paint.zig --library SDL2 --library SDL2main --library c -isystem "/usr/include" --library-path "/usr/lib/x86_64-linux-gnu"
- const std = @import("std");
- const warn = std.debug.warn;
- const fmt = std.fmt;
- const c = @cImport({
- @cInclude("SDL2/SDL.h");
- });
- const assert = @import("std").debug.assert;
- const SDL_WINDOWPOS_UNDEFINED = @bitCast(c_int, c.SDL_WINDOWPOS_UNDEFINED_MASK);
- const SDL_INIT_EVERYTHING =
- c.SDL_INIT_TIMER |
- c.SDL_INIT_AUDIO |
- c.SDL_INIT_VIDEO |
- c.SDL_INIT_EVENTS |
- c.SDL_INIT_JOYSTICK |
- c.SDL_INIT_HAPTIC |
- c.SDL_INIT_GAMECONTROLLER;
- extern fn SDL_PollEvent(event: *c.SDL_Event) c_int;
- var W : usize = 600;
- var H : usize = 600;
- const Color = struct {
- color : [4]u8 = [4]u8{0, 0, 0, 0},
- pub fn r(self : Color) u8
- { return self.colorc[0]; }
- pub fn g(self : Color) u8
- { return self.color[1]; }
- pub fn b(self : Color) u8
- { return self.color[2]; }
- pub fn a(self : Color) u8
- { return self.color[3]; }
- pub fn setR(self : Color, val : u8) void
- { self.color[0] = val; }
- pub fn setG(self : Color, val : u8) void
- { self.color[1] = val; }
- pub fn setB(self : Color, val : u8) void
- { self.color[2] = val; }
- pub fn setA(self : Color, val : u8) void
- { self.color[3] = val; }
- pub fn white() Color {
- var color = Color{.color = [4]u8{255, 255, 255, 255}};
- return color;
- }
- pub fn black() Color {
- var color = Color{.color = [4]u8{0, 0, 0, 255}};
- return color;
- }
- };
- const Vec2 = struct {
- x : f64,
- y : f64,
- };
- pub fn dot(a: Vec2, b: Vec2) f64 {
- return a.x * b.x + a.y * b.y;
- }
- pub fn norm(a: Vec2) Vec2 {
- const len = @sqrt(f64, dot(a, a));
- return Vec2{
- .x = a.x / len,
- .y = a.y / len
- };
- }
- pub fn scale(a: Vec2, b: f64) Vec2 {
- return Vec2 {
- .x = a.x * b,
- .y = a.y * b
- };
- }
- const PixelBuffers = struct {
- const pixelsCapacity = 4000*4000;
- buffers : [2][pixelsCapacity]Color,
- frontIndex : usize,
- w : usize,
- h : usize,
- pub fn init(self : *PixelBuffers, nW : usize, nH : usize) void {
- self.*.frontIndex = 1;
- self.*.w = nW;
- self.*.h = nH;
- var y : usize = 0;
- while(y < nH) {
- var x : usize = 0;
- while(x < nW) {
- self.*.buffers[0][x + nW * y] = Color.black();
- self.*.buffers[1][x + nW * y] = Color.black();
- x += 1;
- }
- y += 1;
- }
- }
- pub fn write(self : *PixelBuffers, x : c_int, y : c_int, color : Color) void {
- if(x >= 0 and y >= 0 and x < @intCast(c_int, W) and y < @intCast(c_int, H)) {
- const ux = @intCast(usize, x);
- const uy = @intCast(usize, y);
- self.*.buffers[self.frontIndex][ux + self.*.w * uy] = color;
- }
- }
- pub fn drawThickLine(self : *PixelBuffers,
- xFrom : c_int, yFrom : c_int, xTo : c_int, yTo : c_int,
- color : Color, thickness : f64) void
- {
- const thickness2 = thickness * thickness;
- var x0 : c_int = undefined;
- var x1 : c_int = undefined;
- var y0 : c_int = undefined;
- var y1 : c_int = undefined;
- if(xFrom < xTo) {
- x0 = xFrom;
- x1 = xTo;
- }
- else {
- x0 = xTo;
- x1 = xFrom;
- }
- if(yFrom < yTo) {
- y0 = yFrom;
- y1 = yTo;
- }
- else {
- y0 = yTo;
- y1 = yFrom;
- }
- if(x0 == x1 and y0 == y1) {
- return;
- }
- const intThickness = @floatToInt(c_int, @ceil(f64, thickness));
- const X0 = x0 - intThickness;
- const Y0 = y0 - intThickness;
- const X1 = x1 + intThickness;
- const Y1 = y1 + intThickness;
- const v01 = Vec2 {
- .x = @intToFloat(f64, xTo - xFrom),
- .y = @intToFloat(f64, yTo - yFrom)
- };
- var iy : c_int = Y0;
- while(iy <= Y1) {
- const y : f64 = @intToFloat(f64, iy);
- var ix : c_int = X0;
- while(ix <= X1) {
- const x : f64 = @intToFloat(f64, ix);
- const v = Vec2 {
- .x = x - @intToFloat(f64, xFrom),
- .y = y - @intToFloat(f64, yFrom)
- };
- const h1 = dot(v, v);
- const c1 = dot(norm(v01), v) * dot(norm(v01), v);
- const distToLine2 : f64 = h1 - c1;
- assert(distToLine2 > -0.001);
- if(distToLine2 < thickness2) {
- self.write(ix, iy, color);
- }
- ix += 1;
- }
- iy += 1;
- }
- }
- pub fn drawLine(self : *PixelBuffers,
- xFrom : c_int, yFrom : c_int, xTo : c_int, yTo : c_int,
- color : Color) void
- {
- if(xFrom == xTo and yFrom == yTo) {
- self.write(xFrom, yFrom, color);
- }
- var x0 : c_int = undefined;
- var x1 : c_int = undefined;
- var y0 : c_int = undefined;
- var y1 : c_int = undefined;
- var invX : bool = undefined;
- var invY : bool = undefined;
- if(xFrom < xTo) {
- x0 = xFrom;
- x1 = xTo;
- invX = false;
- }
- else {
- x0 = xTo;
- x1 = xFrom;
- invX = true;
- }
- if(yFrom < yTo) {
- y0 = yFrom;
- y1 = yTo;
- invY = false;
- }
- else {
- y0 = yTo;
- y1 = yFrom;
- invY = true;
- }
- if(x1 - x0 < y1 - y0) {
- var y : c_int = y0;
- while(y <= y1) {
- const inc = @divFloor((x1 - x0 + 1) * (y - y0), y1 - y0 + 1);
- const x = block: {
- if(invX == invY) {
- break :block x0 + inc;
- }
- else {
- break :block x1 - inc;
- }
- };
- write(self, x, y, color);
- y += 1;
- }
- }
- else {
- var x : c_int = x0;
- while(x <= x1) {
- const inc = @divFloor((y1 - y0 + 1) * (x - x0), x1 - x0 + 1);
- const y = block: {
- if(invX == invY) {
- break :block y0 + inc;
- }
- else {
- break :block y1 - inc;
- }
- };
- write(self, x, y, color);
- x += 1;
- }
- }
- }
- pub fn resize(self : *PixelBuffers, nW : usize, nH : usize) void {
- const front = self.*.frontIndex;
- const back = front ^ 1;
- var y : usize = 0;
- while(y < nH) {
- var x : usize = 0;
- while(x < nW) {
- self.*.buffers[back][x + nW * y] = Color.black();
- x += 1;
- }
- y += 1;
- }
- y = 0;
- while(y < std.math.min(self.*.h, nH)) {
- var x : usize = 0;
- while(x < std.math.min(self.*.w, nW)) {
- self.*.buffers[back][x + nW * y] = self.*.buffers[front][x + self.*.w * y];
- x += 1;
- }
- y += 1;
- }
- self.*.w = nW;
- self.*.h = nH;
- self.swapBuffers();
- }
- fn swapBuffers(self: *PixelBuffers) void {
- self.*.frontIndex = self.*.frontIndex ^ 1;
- }
- pub fn updateTexture(self : *PixelBuffers, texture : *c.SDL_Texture) void {
- var pixelsPtr = @ptrCast(*c_void, &self.*.buffers[self.frontIndex][0]);
- _= c.SDL_UpdateTexture(texture,
- 0, pixelsPtr,
- @intCast(c_int, self.w * @sizeOf(u32))
- );
- }
- };
- pub fn getMousePos(window: *c.SDL_Window, mx : *c_int, my : *c_int) void
- {
- _= c.SDL_GetGlobalMouseState(mx, my);
- var wx : c_int = undefined;
- var wy : c_int = undefined;
- c.SDL_GetWindowPosition(window, &wx, &wy);
- mx.* = mx.* - wx;
- my.* = my.*- wy;
- }
- var pixels : PixelBuffers = undefined;
- pub fn main() !void
- {
- if (c.SDL_Init(SDL_INIT_EVERYTHING) != 0) {
- c.SDL_Log(c"Unable to initialize SDL: %s", c.SDL_GetError());
- return error.SDLInitializationFailed;
- }
- defer c.SDL_Quit();
- const window = c.SDL_CreateWindow(c"Paint",
- SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
- @intCast(c_int, W), @intCast(c_int, H),
- c.SDL_WINDOW_OPENGL | c.SDL_WINDOW_RESIZABLE) orelse
- {
- c.SDL_Log(c"Unable to create window: %s", c.SDL_GetError());
- return error.SDLInitializationFailed;
- };
- defer c.SDL_DestroyWindow(window);
- const renderer = c.SDL_CreateRenderer(window, -1, 0) orelse {
- c.SDL_Log(c"Unable to create renderer: %s", c.SDL_GetError());
- return error.SDLInitializationFailed;
- };
- defer c.SDL_DestroyRenderer(renderer);
- pixels.init(W, H);
- var texture = c.SDL_CreateTexture(
- renderer,
- c.SDL_PIXELFORMAT_ABGR8888, c.SDL_TEXTUREACCESS_STATIC,
- @intCast(c_int, W), @intCast(c_int, H));
- if(texture != null) {
- pixels.updateTexture(@ptrCast(*c.SDL_Texture, texture));
- _= c.SDL_RenderClear(renderer);
- _= c.SDL_RenderCopy(renderer, texture, 0, 0);
- }
- var mouseLeftPressed = false;
- var mouseRightPressed = false;
- var prevMouseX : c_int = undefined;
- var prevMouseY : c_int = undefined;
- var quit = false;
- while (!quit) {
- var cx : c_int = undefined;
- var cy : c_int = undefined;
- _= getMousePos(window, &cx, &cy);
- var event: c.SDL_Event = undefined;
- while (SDL_PollEvent(&event) != 0) {
- switch (event.@"type") {
- c.SDL_QUIT => {
- quit = true;
- },
- c.SDL_MOUSEBUTTONUP => {
- if(event.button.button == c.SDL_BUTTON_LEFT) {
- mouseLeftPressed = false;
- }
- else if(event.button.button == c.SDL_BUTTON_RIGHT) {
- mouseRightPressed = false;
- }
- },
- c.SDL_MOUSEBUTTONDOWN => {
- if(event.button.button == c.SDL_BUTTON_LEFT) {
- if(!mouseLeftPressed) {
- prevMouseX = cx;
- prevMouseY = cy;
- }
- mouseLeftPressed = true;
- }
- else if(event.button.button == c.SDL_BUTTON_RIGHT) {
- if(!mouseRightPressed) {
- prevMouseX = cx;
- prevMouseY = cy;
- }
- mouseRightPressed = true;
- }
- },
- c.SDL_WINDOWEVENT => {
- if(event.window.event == @intCast(u32, c.SDL_WINDOWEVENT_RESIZED)) {
- W = @intCast(usize, event.window.data1);
- H = @intCast(usize, event.window.data2);
- pixels.resize(W, H);
- c.SDL_DestroyTexture(texture);
- texture = c.SDL_CreateTexture(
- renderer,
- c.SDL_PIXELFORMAT_ABGR8888, c.SDL_TEXTUREACCESS_STATIC,
- @intCast(c_int, W), @intCast(c_int, H));
- }
- },
- else => {},
- }
- }
- if(mouseLeftPressed or mouseRightPressed) {
- if(mouseLeftPressed) {
- pixels.drawLine(prevMouseX, prevMouseY, cx, cy, Color.white());
- }
- else if(mouseRightPressed) {
- pixels.drawThickLine(prevMouseX, prevMouseY, cx, cy, Color.black(), 6);
- }
- prevMouseX = cx;
- prevMouseY = cy;
- }
- if(texture != null) {
- pixels.updateTexture(@ptrCast(*c.SDL_Texture, texture));
- _= c.SDL_RenderClear(renderer);
- _= c.SDL_RenderCopy(renderer, texture, 0, 0);
- }
- _= c.SDL_RenderPresent(renderer);
- c.SDL_Delay(1);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement