Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to draw to bigger circles in 0.90 #1510

Closed
potato25 opened this issue Jul 22, 2021 · 7 comments
Closed

Unable to draw to bigger circles in 0.90 #1510

potato25 opened this issue Jul 22, 2021 · 7 comments
Assignees

Comments

@potato25
Copy link

potato25 commented Jul 22, 2021

It doesn't draw properly when i draw circ ( 120+512 , 68 , 512 ,color ) or circ ( 120 , 68+512 , 512 , color ) , Same goes for circb as well

4 four of my carts got effected : https://tic80.com/play?cart=1976 , https://tic80.com/play?cart=1977

These carts worked fine in 0.80

@nesbox nesbox self-assigned this Jul 22, 2021
nesbox added a commit that referenced this issue Jul 22, 2021
nesbox added a commit that referenced this issue Jul 22, 2021
@nesbox
Copy link
Owner

nesbox commented Jul 22, 2021

Big circles fixed here 84c4259 2d5a15e
But the problem with ellipses still exists

@nesbox nesbox closed this as completed Jul 22, 2021
@ddelemeny
Copy link

Here'a a test cart for bresenham ellipses

-- title: Test bresenham ellipsis
-- author: ddelemeny
-- desc: algorithm based on : https://dai.fmph.uniba.sk/upload/0/01/Ellipse.pdf 
-- script: moon

fixed_ellib = (x,y,a,b,c)-> 
  plot = (x,y,_x,_y) ->
    pix(x+_x,y+_y,c)
    pix(x+_x,y-_y,c)
    pix(x-_x,y+_y,c)
    pix(x-_x,y-_y,c)

  local _x, _y, dx, dy, sx, sy, e, two_a_sq, _two_b_sq

  two_a_sq = 2*a*a
  two_b_sq = 2*b*b
  _x = a
  _y = 0
  dx = b*b*(1-(2*a))
  dy = a*a
  e = 0
  sx = two_b_sq*a
  sy = 0

  while sx>=sy do
    plot(x,y,_x,_y,c)

    _y += 1
    sy += two_a_sq
    e += dy
    dy += two_a_sq
    if (2*e +dx >0 )
      _x -= 1
      sx -= two_b_sq
      e += dx
      dx += two_b_sq

  _x = 0
  _y = b
  dx = b*b
  dy = a*a*(1-(2*b))
  e = 0
  sx = 0
  sy = two_a_sq*b

  while sy>=sx do
    plot(x,y,_x,_y,c)

    _x += 1
    sx += two_b_sq
    e += dx
    dx += two_b_sq
    if (2*e +dy >0 )
      _y -= 1
      sy -= two_a_sq
      e += dy
      dy += two_a_sq

r = 1
export TIC=->
  cls 0
  if (btn 4) and (r < 512) then r+=1
  if (btn 5) and (r > 1) then r-=1
  ellib(100+r,68,r,r,2)
  fixed_ellib(120+r,68,r,r,8)
  print('a to grow, b to shrink')
  print("r = #{r}", 0, 10)

    
-- <PALETTE>
-- 000:1a1c2c5d275db13e53ef7d57ffcd75a7f07038b76425717929366f3b5dc941a6f673eff7f4f4f494b0c2566c86333c57
-- </PALETTE>

And here's a patch :

diff --git a/src/core/draw.c b/src/core/draw.c
index de6b30b..d9b26f1 100644
--- a/src/core/draw.c
+++ b/src/core/draw.c
@@ -477,34 +477,43 @@ static void setSideTexPixel(s32 x, s32 y, float u, float v)
     }
 }
 
-static void drawEllipse(tic_mem* memory, s32 x0, s32 y0, s32 x1, s32 y1, u8 color, PixelFunc pix)
+static void drawEllipse(tic_mem* memory, s32 x0, s32 y0, s32 a, s32 b, u8 color, PixelFunc pix)
 {
-    s32 a = abs(x1-x0), b = abs(y1-y0), b1 = b&1; /* values of diameter */
-    s32 dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
-    s32 err = dx+dy+b1*a*a, e2; /* error of 1.step */
+    s32 aa2 = a*a*2, bb2 = b*b*2; 
+    {
+        s32 x = a, y = 0;
+        s32 dx = (1-2*a)*b*b, dy = a*a;
+        s32 sx = bb2*a, sy=0;
+        s32 e = 0;
+
+        while (sx >= sy)
+        {
 
-    if (x0 > x1) { x0 = x1; x1 += a; } /* if called with swapped pos32s */  
-    if (y0 > y1) y0 = y1; /* .. exchange them */
-    y0 += (b+1)/2; y1 = y0-b1;   /* starting pixel */
-    a *= 8*a; b1 = 8*b*b;
+            pix(memory, x0+x, y0+y, color); /*   I. Quadrant */
+            pix(memory, x0+x, y0-y, color); /*  II. Quadrant */
+            pix(memory, x0-x, y0+y, color); /* III. Quadrant */
+            pix(memory, x0-x, y0-y, color); /*  IV. Quadrant */
 
-    do 
+            y++; sy += aa2; e += dy; dy += aa2;
+            if(2*e+dx >0) { x--; sx -= bb2; e  += dx; dx += bb2; }
+        }
+    }
     {
-        pix(memory, x1, y0, color); /*   I. Quadrant */
-        pix(memory, x0, y0, color); /*  II. Quadrant */
-        pix(memory, x0, y1, color); /* III. Quadrant */
-        pix(memory, x1, y1, color); /*  IV. Quadrant */
-        e2 = 2*err;
-        if (e2 <= dy) { y0++; y1--; err += dy += a; }  /* y step */ 
-        if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */
-    } while (x0 <= x1);
-
-    while (y0-y1 < b) 
-    {  /* too early stop of flat ellipses a=1 */
-        pix(memory, x0-1, y0,    color); /* -> finish tip of ellipse */
-        pix(memory, x1+1, y0++,  color); 
-        pix(memory, x0-1, y1,    color);
-        pix(memory, x1+1, y1--,  color); 
+        s32 x = 0, y = b;
+        s32 dx = b*b, dy = (1-2*b)*a*a;
+        s32 sx = 0, sy=aa2*b;
+        s32 e = 0;
+
+        while (sy >= sx)
+        {
+            pix(memory, x0+x, y0+y, color); /*   I. Quadrant */
+            pix(memory, x0+x, y0-y, color); /*  II. Quadrant */
+            pix(memory, x0-x, y0+y, color); /* III. Quadrant */
+            pix(memory, x0-x, y0-y, color); /*  IV. Quadrant */
+
+            x++; sx += bb2; e += dx; dx += bb2;
+            if(2*e+dy >0) { y--; sy -= aa2; e  += dy; dy += aa2; }
+        }
     }
 }
 
@@ -537,7 +546,7 @@ void tic_api_circ(tic_mem* memory, s32 x, s32 y, s32 r, u8 color)
     if(r < 0) return;
 
     initSidesBuffer();
-    drawEllipse(memory, x - r, y - r, x + r, y + r, 0, setElliSide);
+    drawEllipse(memory, x , y , r, r, 0, setElliSide);
     drawSidesBuffer(memory, y - r, y + r + 1, color);
 }
 
@@ -545,7 +554,7 @@ void tic_api_circb(tic_mem* memory, s32 x, s32 y, s32 r, u8 color)
 {
     if(r < 0) return;
 
-    drawEllipse(memory, x - r, y - r, x + r, y + r, mapColor(memory, color), setElliPixel);
+    drawEllipse(memory, x , y , r, r, mapColor(memory, color), setElliPixel);
 }
 
 void tic_api_elli(tic_mem* memory, s32 x, s32 y, s32 a, s32 b, u8 color)
@@ -553,7 +562,7 @@ void tic_api_elli(tic_mem* memory, s32 x, s32 y, s32 a, s32 b, u8 color)
     if(a < 0 || b < 0) return;
 
     initSidesBuffer();
-    drawEllipse(memory, x - a, y - b, x + a, y + b, 0, setElliSide);
+    drawEllipse(memory, x , y, a,  b, 0, setElliSide);
     drawSidesBuffer(memory, y - b, y + b + 1, color);
 }
 
@@ -561,7 +570,7 @@ void tic_api_ellib(tic_mem* memory, s32 x, s32 y, s32 a, s32 b, u8 color)
 {
     if(a < 0 || b < 0) return;
 
-    drawEllipse(memory, x - a, y - b, x + a, y + b, mapColor(memory, color), setElliPixel);
+    drawEllipse(memory, x, y , a, b, mapColor(memory, color), setElliPixel);
 }
 
 static void ticLine(tic_mem* memory, s32 x0, s32 y0, s32 x1, s32 y1, u8 color, PixelFunc func)

@nesbox
Copy link
Owner

nesbox commented Jul 22, 2021

@ddelemeny
Thanks for the quick fix, it works most of the time, but I see some glitches in this demo
ezgif-3-0da10b05a400
https://tic80.com/play?cart=1976

@nesbox
Copy link
Owner

nesbox commented Jul 22, 2021

It reproduces on radius > 800, but the moon version is ok
image

@nesbox
Copy link
Owner

nesbox commented Jul 22, 2021

All is ok if we will use s64 instead s32

nesbox added a commit that referenced this issue Jul 22, 2021
nesbox added a commit that referenced this issue Jul 22, 2021
@nesbox
Copy link
Owner

nesbox commented Jul 22, 2021

Thank you @ddelemeny for the better fix
stable:7187c19 master:5ead2af

@ddelemeny
Copy link

Indeed, the error and stop points being cubes of the radius, they overflow quite fast.
I was trying to tinker with the algorithm to wind a solution that would fit in s32, but hey.. dropping constraints work too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants