Advertisement
Guest User

Untitled

a guest
Aug 25th, 2019
126
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.04 KB | None | 0 0
  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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement