Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWade Brainerd <wadetb@gmail.com>2008-03-06 19:28:10 (GMT)
committer Wade Brainerd <wadetb@gmail.com>2008-03-06 19:28:10 (GMT)
commit4d4bd15b36cf9aa4a696d19fbe246f470d86c71c (patch)
tree04065f604ccee191b826753209fdbb58c129ed56
parent17d20662e8fbd801cea01bd19dfdd78a60b7f5c1 (diff)
Single player mostly shaped up, performance is still decent on XO.
Something inside libpython is taking forever though.
-rw-r--r--pong.py262
-rw-r--r--src/pongc.cpp221
-rw-r--r--src/pongc.h3
3 files changed, 337 insertions, 149 deletions
diff --git a/pong.py b/pong.py
index 71032d6..5b26f04 100644
--- a/pong.py
+++ b/pong.py
@@ -136,43 +136,64 @@ def project_y(x, y, z):
# game.cairo.move_to(x - width/2 - x_bearing, y - height/2 - y_bearing)
# game.cairo.show_text(text)
-cur_color = 31
-
-PRIM_LINE = 0
-PRIM_FILL = 1
-
-def flush_prim ():
- pass
-
-def begin_prim (prim):
- pass
-
-def set_color (color):
- pass
-
def line3d(x0, y0, z0, x1, y1, z1, c):
- draw_line_2x(
- game.drawimage,
- project_x(x0, y0, z0), project_y(x0, y0, z0),
- project_x(x1, y1, z1), project_y(x1, y1, z1),
- int(c*255.0))
+ x0 = project_x(x0, y0, z0)/2
+ y0 = project_y(x0, y0, z0)/2
+ x1 = project_x(x1, y1, z1)/2
+ y1 = project_y(x1, y1, z1)/2
+
+ draw_line_2x(game.drawimage, x0, y0, x1, y1, int(c*255.0))
def rect3d(rect, depth, c):
- x0 = project_x(rect.left, rect.top, depth) + 1
- y0 = project_y(rect.left, rect.top, depth) + 1
- x1 = project_x(rect.right, rect.bottom, depth) - 1
- y1 = project_y(rect.right, rect.bottom, depth) - 1
+ x0 = (project_x(rect.left, rect.top, depth) + 1)/2
+ y0 = (project_y(rect.left, rect.top, depth) + 1)/2
+ x1 = (project_x(rect.right, rect.bottom, depth) - 1)/2
+ y1 = (project_y(rect.right, rect.bottom, depth) - 1)/2
draw_line_2x(game.drawimage, x0, y0, x1, y0, int(c*255.0))
draw_line_2x(game.drawimage, x1, y0, x1, y1, int(c*255.0))
draw_line_2x(game.drawimage, x1, y1, x0, y1, int(c*255.0))
draw_line_2x(game.drawimage, x0, y1, x0, y0, int(c*255.0))
-def circle3d(x, y, z, radius, c):
- pass
+def draw_circle_3d(x, y, z, radius, c):
+ r = (project_x(x+radius, y, z)-project_x(x, y, z))/2
+ if r < 1: return
+
+ x = project_x(x, y, z)/2
+ y = project_y(x, y, z)/2
+
+ draw_ellipse_2x(game.drawimage, x, y, r, r, int(c*255.0))
+
+def fill_circle_3d(x, y, z, radius, c):
+ r = (project_x(x+radius, y, z)-project_x(x, y, z))/2
+ if r < 1: return
+
+ x = project_x(x, y, z)/2
+ y = project_y(x, y, z)/2
+
+ fill_ellipse_2x(game.drawimage, x, y, r, r, int(c*255.0))
+
+def draw_ellipse_3d(x, y, z, rx, ry, c):
+ rx = (project_x(x+rx, y, z)-project_x(x, y, z))/2
+ ry = (project_y(x, y+ry, z)-project_y(x, y, z))/2
+ if rx < 1 or ry < 1: return
+
+ x = project_x(x, y, z)/2
+ y = project_y(x, y, z)/2
+
+ draw_ellipse_2x(game.drawimage, x, y, rx, ry, int(c*255.0))
+
+def text_cairo (text, x, y, size, c):
+ game.cairo.set_source_rgb(c, c, c)
+
+ game.cairo.set_font_size(size)
+ x_bearing, y_bearing, width, height = game.cairo.text_extents(text)[:4]
+
+ if x == -1: x = actual_screen_width/2
+ if y == -1: y = actual_screen_height/2
-def draw_text (text, x, y, size):
- pass
+ game.cairo.move_to(x - width/2 - x_bearing, y - height/2 - y_bearing)
+ game.cairo.show_text(text)
class Ball:
def __init__(self):
@@ -192,10 +213,13 @@ class Ball:
def draw_3d (self, stage):
# Draw the ball.
- circle3d(self.pos.x, self.pos.y, self.pos.z, self.size, game.brightness/100.0)
-
- # Draw the shadow.
- #DrawEllipse3D(Ball.pos.x, Stage.window.bottom, Ball.pos.z, self.size*2, self.size, (64, 64, 64))
+ fill_circle_3d(self.pos.x, self.pos.y, self.pos.z, self.size, game.brightness/100.0)
+
+ # Draw the shadows.
+ draw_ellipse_3d(self.pos.x, stage.window.bottom, self.pos.z, self.size*2, self.size, game.brightness/2/100.0)
+ draw_ellipse_3d(self.pos.x, stage.window.top, self.pos.z, self.size*2, self.size, game.brightness/2/100.0)
+ draw_ellipse_3d(stage.window.left, self.pos.y, self.pos.z, self.size, self.size*2, game.brightness/2/100.0)
+ draw_ellipse_3d(stage.window.right, self.pos.y, self.pos.z, self.size, self.size*2, game.brightness/2/100.0)
# 0 if nobody scored, 1 if Paddle1 scored, 2 if Paddle2 scored.
def update (self, paddle1, paddle2, stage):
@@ -628,8 +652,9 @@ class IntroSequence:
game.draw_3d()
def draw_cairo (self):
- set_color(Color(self.timer0/100.0*255.0, self.timer0/100.0*255.0, self.timer0/100.0*255.0))
- draw_text(_("3 d p o n g"), -1, -1, 100)
+ if (self.timer1 == 1):
+ game.draw_cairo()
+ text_cairo(_("3 d p o n g"), -1, -1, 100, self.timer0/100.0)
def update (self):
if (self.timer1 == 0):
@@ -645,6 +670,11 @@ class IntroSequence:
game.set_sequence(BallReleaseSequence())
class NewStageSequence:
+ def __init__ (self, nextlevel):
+ if nextlevel >= len(game.stage_descs):
+ nextlevel = 0
+ self.nextlevel = nextlevel
+
def enter (self):
self.timer0 = 0
self.timer1 = 0
@@ -656,8 +686,8 @@ class NewStageSequence:
game.draw_3d()
def draw_cairo (self):
- set_color(Color(self.timer0/100.0*255.0, self.timer0/100.0*255.0, self.timer0/100.0*255.0))
- draw_text(game.stage_descs[game.curlevel]['Name'], -1, -1, 100)
+ game.draw_cairo()
+ text_cairo(game.stage_descs[self.nextlevel]['Name'], -1, -1, 100, self.timer0/100.0)
def update (self):
if (self.timer1 == 0):
@@ -665,7 +695,7 @@ class NewStageSequence:
self.timer0 += 2
if (self.timer0 >= 100):
self.timer1 = 1
- game.set_level(game.curlevel+1)
+ game.set_level(self.nextlevel)
elif (self.timer1 == 1):
if (game.brightness < 100): game.brightness += 1
self.timer0 -= 2
@@ -685,9 +715,8 @@ class BallReleaseSequence:
game.draw_3d()
def draw_cairo (self):
- v = math.sin(3.14159*self.timer0/30.0)
- set_color(Color(v*255.0, v*255.0, v*255.0))
- draw_text(str(3-self.timer1), -1, -1, 20)
+ game.draw_cairo()
+ text_cairo(str(3-self.timer1), -1, -1, 20, math.sin(math.pi*self.timer0/30))
def update (self):
if (game.brightness < 100): game.brightness += 1
@@ -712,34 +741,20 @@ class PlaySequence:
game.draw_3d()
def draw_cairo (self):
- pass
+ game.draw_cairo()
def update (self):
# Process player input and AI.
game.paddle1.update_player(game.stage)
game.paddle2.update_ai(game.ball, game.stage)
-
+
# Run the ball simulation.
- game.lastscore = game.ball.update(game.paddle1, game.paddle2, game.stage)
- if ( game.lastscore == 1 ):
+ score = game.ball.update(game.paddle1, game.paddle2, game.stage)
+ if game.mousedown:
+ score = 1
+ game.paddle1.score += 1
+ if score == 1 or score == 2:
game.set_sequence(ScoreSequence())
- if ( game.lastscore == 2 ):
- game.set_sequence(ScoreSequence())
-
- # Check for end of game conditions.
- if ( game.paddle1.score == 5 or game.paddle2.score == 5 ):
- self.endtimeout += 1
- if ( self.endtimeout >= 5 ):
- game.stage_descs[game.curlevel]['PlayerScore'] = game.paddle1.score
- game.stage_descs[game.curlevel]['AIScore'] = game.paddle2.score
- if ( game.paddle2.score == 5 ):
- game.set_sequence(LoseSequence())
- if ( game.paddle1.score == 5 ):
- game.curlevel += 1
- if (game.curlevel == len(game.stage_descs)):
- game.set_sequence(WinSequence())
- else:
- game.set_sequence(NewStageSequence())
class ScoreSequence:
def enter (self):
@@ -760,19 +775,31 @@ class ScoreSequence:
v = (1.0-float(self.step)/self.num_steps)
- circle3d(game.ball.lastpos.x+game.ball.lastvel.x*self.step/2, game.ball.lastpos.y+game.ball.lastvel.y*self.step/2, game.ball.lastpos.z+game.ball.lastvel.z*self.step/2, game.ball.size, v)
+ fill_circle_3d(game.ball.lastpos.x+game.ball.lastvel.x*self.step/2, game.ball.lastpos.y+game.ball.lastvel.y*self.step/2, game.ball.lastpos.z+game.ball.lastvel.z*self.step/2, game.ball.size, v)
random.seed(12345678)
for ring in range(0, num_rings):
- b = 255*(1.0-float(self.step)/self.num_steps)*(0.5+0.5*math.cos(math.pi*float(ring)/num_rings))
- circle3d(game.ball.lastpos.x+game.ball.lastvel.x*ring, game.ball.lastpos.y+game.ball.lastvel.y*ring, game.ball.lastpos.z+game.ball.lastvel.z*ring, (-ring+1)*ring_spacing + ring_speed*self.step, v)
+ b = (1.0-float(self.step)/self.num_steps)*(0.5+0.5*math.cos(math.pi*float(ring)/num_rings))
+ draw_circle_3d(game.ball.lastpos.x+game.ball.lastvel.x*ring, game.ball.lastpos.y+game.ball.lastvel.y*ring, game.ball.lastpos.z+game.ball.lastvel.z*ring, (-ring+1)*ring_spacing + ring_speed*self.step, b)
def draw_cairo (self):
- pass
+ game.draw_cairo()
def update (self):
self.step += 1
if self.step >= self.num_steps:
- game.set_sequence(PlaySequence())
+ # Record the scores.
+ game.stage_descs[game.curlevel]['PlayerScore'] = game.paddle1.score
+ game.stage_descs[game.curlevel]['AIScore'] = game.paddle2.score
+ # Win, Lose or Keep Playing.
+ if game.paddle1.score == 5:
+ if (game.curlevel == len(game.stage_descs)-1):
+ game.set_sequence(WinSequence())
+ else:
+ game.set_sequence(NewStageSequence(game.curlevel+1))
+ elif game.paddle2.score == 5:
+ game.set_sequence(LoseSequence())
+ else:
+ game.set_sequence(PlaySequence())
class LoseSequence:
def enter (self):
@@ -786,8 +813,8 @@ class LoseSequence:
game.draw_3d()
def draw_cairo (self):
- set_color(Color(self.timer0/100.0, self.timer0/100.0, self.timer0/100.0))
- draw_text("; - {", -1, -1, 24)
+ game.draw_cairo()
+ text_cairo("; - {", -1, -1, 24, self.timer0/100.0)
def update (self):
if (self.timer1 == 0):
@@ -817,10 +844,9 @@ class WinSequence:
if (game.brightness <= 0):
self.timer0 = 0
self.timer1 = 1
- DrawGame()
elif (self.timer1 == 1):
self.timer0 += 1
- if (self.timer0 >= 1000 or game.mousedown):
+ if self.timer0 >= 1000 or game.mousedown:
self.timer1 = 2
self.timer0 = len(game.stage_descs)*30
elif (self.timer1 == 2):
@@ -832,29 +858,32 @@ class WinSequence:
self.timer1 = 0
def draw_3d (self):
- pass
+ game.draw_3d()
def draw_cairo (self):
+ game.draw_cairo()
+
starty = 250
total_score = 0
for i in range(0, len(game.stage_descs)):
- v = clamp(255*self.timer0/60.0 - i*60, 0, 255)
- set_color(Color(v,v,v))
+ v = clamp(255*self.timer0/60.0 - i*60, 0, 255)/255.0
- player_score = game.stage_descs[i]['player_score']
- ai_score = game.stage_descs[i]['ai_score']
+ player_score = game.stage_descs[i]['PlayerScore']
+ ai_score = game.stage_descs[i]['AIScore']
diff_score = player_score - ai_score
- game.draw_score(250, starty + i*50, player_score, 0)
- draw_text('-', 475, starty + i*50, 20)
- game.draw_score(550, starty + i*50, ai_score, 1)
- draw_text('=', 775, starty + i*50, 20)
- game.draw_score(850, starty + i*50, diff_score, 0)
+ game.draw_score_cairo(250, starty + i*50, player_score, 1, v)
+ text_cairo('-', 475, starty + i*50, 20, v)
+ game.draw_score_cairo(550, starty + i*50, ai_score, 2, v)
+ text_cairo('=', 775, starty + i*50, 20, v)
+ game.draw_score_cairo(850, starty + i*50, diff_score, 1, v)
- draw_text(game.stage_descs[i]['Name'], 125, starty + i*50, 24)
+ text_cairo(game.stage_descs[i]['Name'], 125, starty + i*50, 24, v)
total_score += diff_score
+ v = self.timer0/60.0
+ game.cairo.set_source_rgb(v, v, v)
game.cairo.move_to(250, starty + len(game.stage_descs)*50)
game.cairo.line_to(950, starty + len(game.stage_descs)*50)
game.cairo.stroke()
@@ -883,7 +912,7 @@ class WinSequence:
text = "; - )"
elif (total_score >= 2*len(game.stage_descs)):
text = "; - }"
- draw_text(text, -1, 150, 24)
+ text_cairo(text, -1, 150, 24, v)
class EditSequence:
def enter (self):
@@ -896,7 +925,7 @@ class EditSequence:
game.draw_3d()
def draw_cairo (self):
- pass
+ game.draw_cairo()
def update (self):
pass
@@ -912,9 +941,6 @@ class Game:
self.paddle1 = Paddle()
self.paddle2 = Paddle()
- # Score variable from last frame, to see if we need to erase the scoring graphic.
- self.lastscore = 0
-
# Current stage.
self.curlevel = 0
@@ -959,14 +985,9 @@ class Game:
def new_game(self):
self.set_level(0)
- def draw_score(self, x, y, score, player):
- return
+ def draw_score_cairo(self, x, y, score, player, c):
+ game.cairo.set_source_rgb(c,c,c)
for j in range(0, 5):
- if j < score:
- begin_prim(PRIM_FILL)
- else:
- begin_prim(PRIM_LINE)
-
px = x + j*30
py = y
@@ -979,6 +1000,11 @@ class Game:
game.cairo.move_to(px + 10, py)
game.cairo.arc(px, py, 10, 0, 2*math.pi)
+ if j < score:
+ game.cairo.fill()
+ else:
+ game.cairo.stroke()
+
def draw_3d(self):
self.stage.draw_3d()
self.paddle1.draw_3d(self.stage)
@@ -986,13 +1012,12 @@ class Game:
self.ball.draw_3d(self.stage)
def draw_cairo (self):
- v = 255*self.brightness/100.0
- set_color(Color(v,v,v))
- self.draw_score(actual_screen_width*1/4-75, 30, self.paddle1.score, 1)
- self.draw_score(actual_screen_width*3/4-75, 30, self.paddle2.score, 2)
+ v = self.brightness/100.0
+ self.draw_score_cairo(actual_screen_width*1/4-75, 30, self.paddle1.score, 1, v)
+ self.draw_score_cairo(actual_screen_width*3/4-75, 30, self.paddle2.score, 2, v)
#game.cairo.set_source_rgb(color[0]/255.0, color[1]/255.0, color[2]/255.0)
- #draw_text(game.stage_descs[game.curlevel]['Name'], -1, 30, 24)
+ #text_cairo(game.stage_descs[game.curlevel]['Name'], -1, 30, 24, v)
# Global game instance.
game = Game()
@@ -1215,9 +1240,9 @@ class PongActivity(activity.Activity):
self.editor.set_size_request(self.width, 80)
self.drawarea.put(self.editor, 0, 0)
- # Turn off double buffering.
+ # Turn off double buffering except for the drawarea, which mixes cairo and custom drawing.
self.set_double_buffered(False)
- self.drawarea.set_double_buffered(False)
+ self.drawarea.set_double_buffered(True)
# Get the mainloop ready to run.
gobject.timeout_add(50, self.mainloop)
@@ -1247,18 +1272,8 @@ class PongActivity(activity.Activity):
self.drawimage = gtk.gdk.Image(gtk.gdk.IMAGE_FASTEST, gtk.gdk.visual_get_system(), self.width, self.height)
game.drawimage = self.drawimage
- #self.drawarea.grab_add()
- self.cursor_visible = True
-
self.set_canvas(self.drawarea)
-# def build_cairo (self):
-# game.cairosurf = cairo.ImageSurface(cairo.FORMAT_RGB24, self.width, self.height)
-# game.cairo = cairo.Context(game.cairosurf)
-# game.cairo.set_antialias(cairo.ANTIALIAS_NONE)
-# #game.cairo.set_line_cap(cairo.LINE_CAP_BUTT)
-# #game.cairo.set_line_width(1.0)
-
def build_toolbox (self):
self.pausebtn = toolbutton.ToolButton('media-playback-pause')
self.pausebtn.set_tooltip(_("Pause Game"))
@@ -1315,6 +1330,7 @@ class PongActivity(activity.Activity):
self.set_toolbox(self.tbox)
+ # Activity modes
def set_mode (self, mode):
self.mode = mode
@@ -1392,21 +1408,17 @@ class PongActivity(activity.Activity):
actual_screen_width = self.drawarea.get_allocation()[2]
actual_screen_height = self.drawarea.get_allocation()[3]
- # Clear the offscreen surface.
+ # Perform 3D rendering to the offscreen image and draw it to the screen.
clear_image(self.drawimage)
-
- # Set up cairo rendering.
- game.cairo = self.drawarea.bin_window.cairo_create()
-
- # Render the current game state.
game.sequence.draw_3d()
- game.sequence.draw_cairo()
- flush_prim()
-
- # Draw palette image.
gc = self.drawarea.get_style().fg_gc[gtk.STATE_NORMAL]
self.drawarea.bin_window.draw_image(gc, self.drawimage, 0, 0, 0, 0, -1, -1)
+ # Perform Cairo rendering over the top.
+ game.cairo = self.drawarea.bin_window.cairo_create()
+ game.sequence.draw_cairo()
+ game.cairo = None
+
# Hack to fix toolbox refresh.
#self.tbox.queue_draw()
@@ -1414,22 +1426,10 @@ class PongActivity(activity.Activity):
def pause_game (self, p):
self.paused = p
if self.paused:
- self.show_cursor(True)
self.pausebtn.set_icon('media-playback-start')
else:
- self.show_cursor(False)
self.pausebtn.set_icon('media-playback-pause')
- def show_cursor (self, show):
- if self.cursor_visible and not show:
- pixmap = gtk.gdk.Pixmap(None, 1, 1, 1)
- color = gtk.gdk.Color()
- cursor = gtk.gdk.Cursor(pixmap, pixmap, color, color, 0, 0)
- self.drawarea.bin_window.set_cursor(cursor)
- if not self.cursor_visible and show:
- self.drawarea.bin_window.set_cursor(None)
- self.cursor_visible = show
-
def on_mouse (self, widget, event):
game.mousex = int(event.x)
game.mousey = int(event.y)
diff --git a/src/pongc.cpp b/src/pongc.cpp
index 6114bc9..9c52d6c 100644
--- a/src/pongc.cpp
+++ b/src/pongc.cpp
@@ -17,15 +17,18 @@
*/
#include "pongc.h"
-#include <algorithm>
-
-float frac(float x)
+void clear_image(GdkImage* img)
{
- return x-int(x);
+ unsigned short* pixels = (unsigned short*)img->mem;
+ int pitch = img->bpl/sizeof(unsigned short);
+ for (int y = 0; y < img->height; y++)
+ memset(pixels + pitch*y, 0, img->bpl);
}
void draw_point_2x(GdkImage* img, int x, int y, uint16_t c)
{
+ if (x < 0 || y < 0 || x >= img->width/2-1 || y >= img->height/2-1)
+ return;
c >>= 3;
unsigned short* pixels = (unsigned short*)img->mem;
int pitch = img->bpl/sizeof(unsigned short);
@@ -37,22 +40,8 @@ void draw_point_2x(GdkImage* img, int x, int y, uint16_t c)
pixels[ofs+pitch+1] = pix;
}
-void clear_image(GdkImage* img)
-{
- unsigned short* pixels = (unsigned short*)img->mem;
- int pitch = img->bpl/sizeof(unsigned short);
- for (int y = 0; y < img->height; y++)
- memset(pixels + pitch*y, 0, img->bpl);
-}
-
void draw_line_2x(GdkImage* img, int x0, int y0, int x1, int y1, int color)
{
- // Convert to scaled coordinates.
- x0 >>= 1;
- x1 >>= 1;
- y0 >>= 1;
- y1 >>= 1;
-
// Make sure the line runs top to bottom.
if (y0 > y1)
{
@@ -166,3 +155,199 @@ void draw_line_2x(GdkImage* img, int x0, int y0, int x1, int y1, int color)
}
}
+void draw_ellipse_2x(GdkImage* img, int x, int y, int rx, int ry, int color)
+{
+ if (rx==0 && ry==0) // Special case - draw a single pixel
+ {
+ draw_point_2x(img, x, y, color);
+ return;
+ }
+ if (rx==0) // Special case for rx=0 - draw a vline
+ {
+ draw_line_2x(img, x, y-ry, x, y+ry, color);
+ return;
+ }
+ if (ry==0) // Special case for ry=0 - draw a hline
+ {
+ draw_line_2x(img, x-rx, y, x+rx, y, color);
+ return;
+ }
+
+ // Draw
+ int oh = 0xffff;
+ int oi = 0xffff;
+ int oj = 0xffff;
+ int ok = 0xffff;
+
+ if (rx >= ry)
+ {
+ int ix = 0;
+ int iy = rx * 64;
+ int i, h;
+ do
+ {
+ h = (ix + 8) >> 6;
+ i = (iy + 8) >> 6;
+ int j = (h * ry) / rx;
+ int k = (i * ry) / rx;
+ if (((ok != k) && (oj != k)) || ((oj != j) && (ok != j)) || (k != j))
+ {
+ int xph = x+h-1;
+ int xmh = x-h;
+ if (k > 0)
+ {
+ int ypk=y+k-1;
+ int ymk=y-k;
+ if (h > 0)
+ {
+ draw_point_2x(img, xmh, ypk, color);
+ draw_point_2x(img, xmh, ymk, color);
+ }
+ draw_point_2x(img, xph, ypk, color);
+ draw_point_2x(img, xph, ymk, color);
+ }
+ ok = k;
+ int xpi = x+i-1;
+ int xmi = x-i;
+ if (j > 0)
+ {
+ int ypj = y+j-1;
+ int ymj = y-j;
+ draw_point_2x(img, xmi, ypj, color);
+ draw_point_2x(img, xpi, ypj, color);
+ draw_point_2x(img, xmi, ymj, color);
+ draw_point_2x(img, xpi, ymj, color);
+ }
+ oj = j;
+ }
+ ix = ix + iy / rx;
+ iy = iy - ix / rx;
+ } while (i > h);
+ }
+ else
+ {
+ int ix = 0;
+ int iy = ry * 64;
+ int i, h;
+ do
+ {
+ h = (ix + 8) >> 6;
+ i = (iy + 8) >> 6;
+ int j = (h * rx) / ry;
+ int k = (i * rx) / ry;
+ if (((oi != i) && (oh != i)) || ((oh != h) && (oi != h) && (i != h)))
+ {
+ int xmj = x-j;
+ int xpj = x+j-1;
+ if (i > 0)
+ {
+ int ypi = y+i-1;
+ int ymi = y-i;
+ if (j > 0)
+ {
+ draw_point_2x(img, xmj, ypi, color);
+ draw_point_2x(img, xmj, ymi, color);
+ }
+ draw_point_2x(img, xpj, ypi, color);
+ draw_point_2x(img, xpj, ymi, color);
+ }
+ oi = i;
+ int xmk = x-k;
+ int xpk = x+k-1;
+ if (h > 0)
+ {
+ int yph = y+h-1;
+ int ymh = y-h;
+ draw_point_2x(img, xmk, yph, color);
+ draw_point_2x(img, xpk, yph, color);
+ draw_point_2x(img, xmk, ymh, color);
+ draw_point_2x(img, xpk, ymh, color);
+ }
+ oh = h;
+ }
+ ix = ix + iy / ry;
+ iy = iy - ix / ry;
+ } while (i > h);
+ }
+}
+
+void fill_ellipse_2x(GdkImage* img, int x, int y, int rx, int ry, int color)
+{
+ if (rx==0 && ry==0) // Special case - draw a single pixel
+ {
+ draw_point_2x(img, x, y, color);
+ return;
+ }
+ if (rx==0) // Special case for rx=0 - draw a vline
+ {
+ draw_line_2x(img, x, y-ry, x, y+ry, color);
+ return;
+ }
+ if (ry==0) // Special case for ry=0 - draw a hline
+ {
+ draw_line_2x(img, x-rx, y, x+rx, y, color);
+ return;
+ }
+
+ // Draw
+ int oh = 0xffff;
+ int oi = 0xffff;
+ int oj = 0xffff;
+ int ok = 0xffff;
+
+ if (rx >= ry)
+ {
+ int ix = 0;
+ int iy = rx * 64;
+ int i, h;
+ do
+ {
+ h = (ix + 8) >> 6;
+ i = (iy + 8) >> 6;
+ int j = (h * ry) / rx;
+ int k = (i * ry) / rx;
+ if ((ok != k) && (oj != k) && (k < ry))
+ {
+ draw_line_2x(img, x-h, y-k-1, x+h-1, y-k-1, color);
+ draw_line_2x(img, x-h, y+k, x+h-1, y+k, color);
+ ok = k;
+ }
+ if ((oj != j) && (ok != j) && (k != j))
+ {
+ draw_line_2x(img, x-i, y+j, x+i-1, y+j, color);
+ draw_line_2x(img, x-i, y-j-1, x+i-1, y-j-1, color);
+ oj = j;
+ }
+ ix = ix + iy / rx;
+ iy = iy - ix / rx;
+ } while (i > h);
+ }
+ else
+ {
+ int ix = 0;
+ int iy = ry * 64;
+ int i, h;
+ do
+ {
+ h = (ix + 8) >> 6;
+ i = (iy + 8) >> 6;
+ int j = (h * rx) / ry;
+ int k = (i * rx) / ry;
+ if ((oi != i) && (oh != i) && (i < ry))
+ {
+ draw_line_2x(img, x-j, y+i, x+j-1, y+i, color);
+ draw_line_2x(img, x-j, y-i-1, x+j-1, y-i-1, color);
+ oi = i;
+ }
+ if ((oh != h) && (oi != h) && (i != h))
+ {
+ draw_line_2x(img, x-k, y+h, x+k-1, y+h, color);
+ draw_line_2x(img, x-k, y-h-1, x+k-1, y-h-1, color);
+ oh = h;
+ }
+ ix = ix + iy / ry;
+ iy = iy - ix / ry;
+ } while (i > h);
+ }
+}
+
diff --git a/src/pongc.h b/src/pongc.h
index 45fe460..a054b18 100644
--- a/src/pongc.h
+++ b/src/pongc.h
@@ -27,5 +27,8 @@ void clear_image(GdkImage* img);
void draw_line_2x(GdkImage* img, int x0, int y0, int x1, int y1, int color);
+void draw_ellipse_2x(GdkImage* img, int x, int y, int rx, int ry, int color);
+void fill_ellipse_2x(GdkImage* img, int x, int y, int rx, int ry, int color);
+
#endif