{"id":18814309,"url":"https://github.com/diordany/tech-bresenham","last_synced_at":"2025-08-21T01:17:00.736Z","repository":{"id":225928971,"uuid":"767028354","full_name":"Diordany/tech-bresenham","owner":"Diordany","description":"A software line renderer written in C that uses the Bresenham algorithm.","archived":false,"fork":false,"pushed_at":"2024-05-21T03:18:31.000Z","size":34,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-30T00:47:56.915Z","etag":null,"topics":["algorithms","bresenham","c","drawing","example","gcc","graphics","image","learning","learning-by-doing","line","linear","make","mathematics","pixel","renderer","report","sdl2","software-rendering","tech"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Diordany.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-04T15:19:52.000Z","updated_at":"2024-05-21T03:18:35.000Z","dependencies_parsed_at":"2024-03-06T13:30:57.382Z","dependency_job_id":"6348de19-c3de-42a0-bde9-e425a999864c","html_url":"https://github.com/Diordany/tech-bresenham","commit_stats":null,"previous_names":["diordany/c-example-bresenham","diordany/tech-bresenham"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Diordany%2Ftech-bresenham","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Diordany%2Ftech-bresenham/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Diordany%2Ftech-bresenham/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Diordany%2Ftech-bresenham/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Diordany","download_url":"https://codeload.github.com/Diordany/tech-bresenham/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239750114,"owners_count":19690570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithms","bresenham","c","drawing","example","gcc","graphics","image","learning","learning-by-doing","line","linear","make","mathematics","pixel","renderer","report","sdl2","software-rendering","tech"],"created_at":"2024-11-07T23:40:07.891Z","updated_at":"2025-02-19T23:26:38.822Z","avatar_url":"https://github.com/Diordany.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Example: Bresenham Line Renderer (C)\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nI want to demonstrate the line renderer presented by Bresenham in [[1]](#1), therefore I've implemented the algorithm in C as a software renderer. The window management and drawing of individual pixels is handled by SDL2 in this demonstration.\n\n# Building \u0026 Running\n\n## Dependencies\n\n- SDL2\n\nTo install the dependencies on Arch Linux, run:\n```\nsudo pacman -S sdl2\n```\n\n## Building\n\nTo build the example, run:\n\n```\nmake\n```\n\nTo rebuild, run:\n\n```\nmake rebuild\n```\n\nTo remove the object files and the executable, run:\n\n```\nmake clean\n```\n\n## Running\n\nRun the example with:\n\n```\n./bin/bresenham\n```\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"800\" height=\"600\" src=\"https://github.com/Diordany/c-example-bresenham/assets/54911023/05dafb69-7ebb-444a-ae40-c2f266c18abb\"\u003e\n\u003c/p\u003e\n\nThe start and end of the line are marked with red and green respectively.\n\n# Framework\n\nBefore we delve into the implementation of the Bresenham renderer, I want to give a brief overview of the framework for this example.\n\nThe window management and drawing is handled by SDL2. First, an SDL window is created, which is accessed with a pointer of type `SDL_Window *`. With the window, an SDL renderer is created that can be accessed with a pointer of type `SDL_Renderer *`. The SDL renderer can actually render lines already with `SDL_RenderDrawLine()`, but for this example I'm going to use my own software implementation. The SDL renderer is only used to draw individual pixels and to render markers (to point out both ends of the line). SDL2 is also used to control the main loop of the example.\n\nAt the start of the run, two random points are generated to indicate the start and end of the line. This is done with the standard C library.\n\n# The Line Renderer\n\nThe renderer must first figure out in which octant with respect to $(x_1, y_1)$ it has to operate. To do so, the slope of the line must be taken into account [[1]](#1). When the octant is known, the renderer sets up a frame of reference to draw the line.\n\n## Calculating the Slope\nLet's consider the mathematical representation of a linear function:\n\n$$y = \\frac{\\Delta y}{\\Delta x}(x - x_0) + y_0 = \\frac{y_2 - y_1}{x_2 - x_1}(x - x_0) + y_0$$\n\nIn this case, we can see that the slope is $\\frac{\\Delta y}{\\Delta x}$, so we can start off by calculating the displacement $(\\Delta x, \\Delta y)$ from the starting point $(x_1, y_1)$ to the end of the line $(x_2, y_2)$:\n\n$$\\Delta x = x_2 - x_1$$\n\n$$\\Delta y = y_2 - y_1$$\n\n```c\nint xDiff = p_x2 - p_x1;\nint yDiff = p_y2 - p_y1;\n```\n\nThe absolute values $|\\Delta x|$ and $|\\Delta y|$ are then calculated, so we can determine the steepness of the slope [[1]](#1):\n\n```c\nint xDiffAbs = (xDiff \u003c 0) ? -xDiff : xDiff;\nint yDiffAbs = (yDiff \u003c 0) ? -yDiff : yDiff;\n```\n\n## Determining the Octant\n\nNow that we know the relevant details of the slope, we can figure out in which octant we should operate. We'll introduce the boolean variables $X$, $Y$ and $Z$ [[1]](#1).\n\nWe use $X$ to test whether the $x$ displacement is positive or not.\n\n$$X = (\\Delta x \\ge 0)$$\n\n```c\nbool posXDiff = xDiff \u003e= 0;\n```\n\nWe use $Y$ to test whether the $y$ displacement is positive or not.\n\n$$Y = (\\Delta y \\ge 0)$$\n\n```c\nbool posYDiff = yDiff \u003e= 0;\n```\n\nWe use $Z$ to test whether the slope is shallow or steep with respect to the x-axis (true if shallow and false if steep).\n\n$$Z = (|\\Delta x| - |\\Delta y| \\ge 0)$$\n\n```c\nbool shallow = xDiffAbs - yDiffAbs \u003e= 0;\n```\n\nWe can map $X$, $Y$ and $Z$ to the octant with the following table [[1]](#1):\n\n| X | Y | Z | Octant |\n|:-:|:-:|:-:|:------:|\n| 0 | 0 | 0 | 6      |\n| 0 | 0 | 1 | 5      |\n| 0 | 1 | 0 | 3      |\n| 0 | 1 | 1 | 4      |\n| 1 | 0 | 0 | 7      |\n| 1 | 0 | 1 | 8      |\n| 1 | 1 | 0 | 2      |\n| 1 | 1 | 1 | 1      |\n\n## Setting the Frame of Reference\n\nNow that we are able to determine the octant, we can set the frame of reference of the renderer accordingly. The frame of reference has an a- and b-axis, how this relates to the x- and y-axis depends on the octant.\n\nFirst, let's declare the relevant variables:\n\n```c\nint a, b;\nint *x, *y;\nint aDiff, bDiff;\nint aInc, bInc;\nint aTerm;\n```\n\nThe first pair (`a` and `b`) represents a point $(a_i, b_i)$ in the frame of reference. The initial point $(a_1, b_1)$ is determined by:\n\n$$a_1 = \\begin{cases}\n  x_1 \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\ge 0\\\\\n  y_1 \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\lt 0\\\\\n\\end{cases}$$\n\n$$b_1 =\n\\begin{cases}\n  y_1 \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\ge 0\\\\\n  x_1 \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\lt 0\\\\\n\\end{cases}$$\n\nThe important detail to note here is that the a- and b-axis fall along the x- and y-axis respectively if the slope is shallow. The axes are inverted if the slope is steep. All other variables are determined in a similar fashion.\n\nThe second pair variables (`*x` and `*y`) are pointers that are used to translate the point $(a_i, b_i)$ in the frame of reference to a point $(x_i, y_i)$ in the screenspace of SDL.\n\nThe third pair (`aDiff` and `bDiff`) represents the displacement $(\\Delta a, \\Delta b)$ in the frame of reference. In theory, the renderer only moves in the positive a and b directions, therefore we have to make sure that we use the absolute values of $\\Delta x$ and $\\Delta y$ for the assignment [[1]](#1). The values are determined with the following expressions:\n\n$$\\Delta a =\n\\begin{cases}\n  |\\Delta x| \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\ge 0\\\\\n  |\\Delta y| \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\lt 0\\\\\n\\end{cases}$$\n\n$$\\Delta b =\n\\begin{cases}\n  |\\Delta y| \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\ge 0\\\\\n  |\\Delta x| \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\lt 0\\\\\n\\end{cases}$$\n\nThe fourth pair (`aInc` and `bInc`) is used to make sure that the a- and b-axis point in the appropriate direction in the SDL screen space. Their values are determined by:\n\n$$a_{+} =\n\\begin{cases}\n  1 \u0026 \\quad\\text{if}\\quad (X \\cap Z) \\cup (Y \\cap \\overline{Z}) \\\\\n  -1 \u0026 \\quad\\text{otherwise}\n\\end{cases}$$\n\n$$b_{+} =\n\\begin{cases}\n  1 \u0026 \\quad\\text{if}\\quad (Y \\cap Z) \\cup (X \\cap \\overline{Z}) \\\\\n  -1 \u0026 \\quad\\text{otherwise}\n\\end{cases}$$\n\nEarlier I mentioned that the renderer only moves in the positive a and b directions in theory. You can see here that it's not necessarily true in practice, as the coordinates are prematurely converted to SDL screen space for convenience. The renderer still works according to the theory in [[1]](#1) however. In the end, the increments are still moving the points towards what are considered the positive a and b directions of the frame of reference.\n\nThe expression can be further simplified if the slope is tested beforehand, which is the case in my implementation. For shallow slopes, the expressions are:\n\n$$a_+ =\n\\begin{cases}\n  1 \u0026 \\quad\\text{if}\\quad \\Delta x \\ge 0\\\\\n  -1 \u0026 \\quad\\text{if}\\quad \\Delta x \\lt 0\n\\end{cases}$$\n\n$$b_+ =\n\\begin{cases}\n  1 \u0026 \\quad\\text{if}\\quad \\Delta y \\ge 0\\\\\n  -1 \u0026 \\quad\\text{if}\\quad \\Delta y \\lt 0\n\\end{cases}$$\n\nFor steep slopes, the expressions are:\n\n$$a_+ =\n\\begin{cases}\n  1 \u0026 \\quad\\text{if}\\quad \\Delta y \\ge 0\\\\\n  -1 \u0026 \\quad\\text{if}\\quad \\Delta y \\lt 0\n\\end{cases}$$\n\n$$b_+ =\n\\begin{cases}\n  1 \u0026 \\quad\\text{if}\\quad \\Delta x \\ge 0\\\\\n  -1 \u0026 \\quad\\text{if}\\quad \\Delta x \\lt 0\n\\end{cases}$$\n\nFinally the last variable `aTerm` is used to terminate the drawing procedure. It sits just outside the bounds of the line and is defined by:\n\n$$a_{n + 1} =\n\\begin{cases}\n  x_2 + a_+ \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\ge 0\\\\\n  y_2 + a_+ \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\lt 0\n\\end{cases}$$\n\nThe final value of `a` is given by:\n\n$$a_n =\n\\begin{cases}\n  x_2 \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\ge 0\\\\\n  y_2 \u0026 \\quad\\text{if}\\quad |\\Delta x| - |\\Delta y| \\lt 0\n\\end{cases}$$\n\nTo put all of this verbose nonsense into practice, I've written the following:\n\n```c\nif (shallow)\n{\n  a = p_x1;\n  b = p_y1;\n\n  x = \u0026a;\n  y = \u0026b;\n\n  aDiff = xDiffAbs;\n  bDiff = yDiffAbs;\n\n  aInc = (posXDiff) ? 1 : -1;\n  bInc = (posYDiff) ? 1 : -1;\n\n  aTerm = p_x2 + aInc;\n}\nelse\n{\n  a = p_y1;\n  b = p_x1;\n\n  x = \u0026b;\n  y = \u0026a;\n\n  aDiff = yDiffAbs;\n  bDiff = xDiffAbs;\n\n  aInc = (posYDiff) ? 1 : -1;\n  bInc = (posXDiff) ? 1 : -1;\n\n  aTerm = p_y2 + aInc;\n}\n```\n\n## The Rendering Procedure\n\nNow that the frame of reference is set, we can move on to the rendering procedure. Let's start with the $a_i$ variable, which really simple actually, because the procedure just iterates over the range of $[a_1, a_n]$.\n\nThe $b_i$ value requires more explanation. Bresenham [[1]](#1) presented a clever method to figure out the relation between $b_i$ and $a_i$ without floating point arithmetic and without multiplication or division. For every value of $a_i$, the algorithm should decide whether or not to increment the value of $b_i$ [[1]](#1). The decision is based on which point is closer to the ideal line. The distance between the ideal line and the points $(a_i, b_{i - 1})$ and $(a_i, b_{i - 1} + b_+)$ are given by $r$ and $q$ respectively. So the new value of $b_i$ is determined with:\n\n$$b_i =\n\\begin{cases}\n  b_{i - 1} + b_+ \u0026 \\quad\\text{if}\\quad r - q \\ge 0\\\\\n  b_{i - 1} \u0026 \\quad\\text{if}\\quad r - q \\lt 0\\\\\n\\end{cases}$$\n\nHowever, we're not going to figure out the values of $r$ and $q$, because Bresenham derived a more convenient way to test whether $r - q$ is positive or not [[1]](#1). Deriving the equation is beyond the scope of this example, but the paper does an excellent job at describing how to derive it. Bresenham expressed the sign of $r - q$ in terms of $\\Delta a$ and $\\Delta b$, which is convenient, because we already figured those out. The following recursive relation was presented in [[1]](#1):\n\n$$\\delta_{i + 1} =\n\\begin{cases}\n  \\delta_i + 2\\Delta b - 2\\Delta a \u0026 \\quad\\text{if}\\quad \\delta_i \\ge 0\\\\\n  \\delta_i + 2\\Delta b \u0026 \\quad\\text{if}\\quad \\delta_i \\lt 0\\\\\n\\end{cases}$$\n\nFor which the initial value is set with [[1]](#1):\n\n$$\\delta_1 = 2\\Delta b - \\Delta a$$\n\nUtilizing this expression, the value of $b_i$ can now be determined with:\n\n$$b_i =\n\\begin{cases}\n  b_{i - 1} + b_+ \u0026 \\quad\\text{if}\\quad \\delta_i \\ge 0\\\\\n  b_{i - 1} \u0026 \\quad\\text{if}\\quad \\delta_i \\lt 0\\\\\n\\end{cases}$$\n\nAfter closer examination, we can see that that the equations for $\\delta_1$ and $\\delta_{i + 1}$ are very similar to the edge function from [[2]](#2). Let's consider the mathematical representation of a linear function again, but this time for the frame of reference:\n\n$$b = \\frac{\\Delta b}{\\Delta a}(a - a_0) + b_0$$\n\nIf we rewrite this, we get a special case of the edge function from [[2]](#2), where the function is equal to 0:\n\n$$\\Delta b (a - a_0) - \\Delta a (b - b_0) = 0$$\n\nThe edge function detects how much the point $(a, b)$ deviates from the ideal line [[2]](#2). It therefore makes sense that the function would output 0 for every point in the linear function. So let's now consider a more general form of the edge function:\n\n$\\delta(a^\\prime,b^\\prime) = \\Delta b(a^\\prime - a_0) - \\Delta a(b^\\prime - b_0)$\n\nWe can now see the relation between $\\delta_1$ and $\\delta_{i + 1}$ and the edge function from [[2]](#2):\n\n$$\\delta_1 = \\delta(a_0 + 2, b_0 + 1) = 2\\Delta b - \\Delta a$$\n\n$$\\delta_{i + 1} =\n\\begin{cases}\n  \\delta_i + \\delta(a_0 + 2, b_0 + 2) = \\delta_i + 2\\Delta b - 2\\Delta a \u0026 \\quad\\text{if}\\quad \\delta_i \\ge 0\\\\\n  \\delta_i + \\delta(a_0 + 2, b_0) = \\delta_i + 2\\Delta b \u0026 \\quad\\text{if}\\quad \\delta_i \\lt 0\\\\\n\\end{cases}$$\n\nAs you can see, expression for $\\delta_{i + 1}$ compensates for incrementing the $a_i$ and $b_i$ variables, while $\\delta_1$ sets an initial offset.\n\nOkay, enough ramling for now, let's see the actual C implementation:\n\n```c\nint error = bDiff + bDiff - aDiff;\n\nwhile (a != aTerm)\n{\n  SDL_RenderDrawPoint(p_renderer, *x, *y);\n\n  a += aInc;\n  error += bDiff + bDiff;\n\n  if (error \u003e= 0)\n  {\n    b += bInc;\n    error -= aDiff + aDiff;\n  }\n}\n```\n\n# Conclusion\n\nFor such a simple concept as drawing a line, the Bresenham algorithm turned out to be more complex than I initially thought, and I learned a lot during the process of implementing it as a software renderer. Also, deriving the equations myself gave me an opportunity to dust off my mathematical skills. I'm fascinated with image and video rendering techniques, and I'd like to learn a lot more about them in the future by working on projects like this.\n\n# References\n\n\u003ca id=\"1\"\u003e[1]\u003c/a\u003e \n\u0026nbsp; J. E. Bresenham, \"Algorithm for computer control of a digital plotter\" *IBM Systems Journal*, 1965.\n\n\u003ca id=\"1\"\u003e[2]\u003c/a\u003e\n\u0026nbsp; J. Pineda, \"A Parallel Algorithm for Polygon Rasterization\" *Computer Graphics*, vol. 22, no. 4, Aug. 1988.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiordany%2Ftech-bresenham","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiordany%2Ftech-bresenham","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiordany%2Ftech-bresenham/lists"}