PDA

View Full Version : Where's the bottleneck



anubis79
11-01-2006, 07:08 PM
I try to develop a paint algorithm via SDL_GFX unit. Some codes where I started to do this below. But I've got some problem with this code. When I started to move mouse faster , my algorithm is become slow and don't paint some pixels. I think this effect is for not detecting to faster mouse movements. At the end, I used a good timer from DelphiX and set its interval to 1 for increasing drawing speed and detecting fast mouse movements but nothing has changed. Her is my code:




unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, SDL, sdl_gfx, DXClass, SDLUtils, StdCtrls, gl;
type
TForm1 = class(TForm)
Panel1: TPanel;
DXTimer1: TDXTimer;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure DXTimer1Timer(Sender: TObject; LagCount: Integer);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Screen : PSDL_Surface;
Pushed: boolean;
time1: cardinal;
Frames, TO2: GLInt;
seconds, fps : GLFloat;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
SDL_putenv('SDL_VIDEODRIVER=windib');
SDL_putenv(PChar('SDL_WINDOWID=' + inttostr(Integer(Panel1.Handle))));
SDL_Init(SDL_INIT_VIDEO);
Screen := SDL_SetVideoMode(Panel1.ClientWidth, Panel1.ClientHeight, 32,
SDL_SWSURFACE or SDL_DOUBLEBUF);
end;

procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
var
event: TSDL_Event;
RECT: TSDL_Rect;
begin

//Let's Paint
if (SDL_PollEvent(@event) > 0 ) then
begin
case event.type_ of
SDL_MOUSEBUTTONDOWN: pushed := true;

SDL_MOUSEBUTTONUP: pushed := false;

SDL_MOUSEMOTION:
if pushed then
begin
RECT := SDLRect(event.Motion.x - 5, event.Motion.y - 5, event.motion.x + 5, event.motion.y + 5);
SDL_Gfx.filledCircleRGBA(Screen, event.Motion.x, event.Motion.y, 5, 255,0,0,255);
SDL.SDL_UpdateRects(Screen, 1, @RECT);
end;
end;

//Lets calc to FPS
Inc( Frames );
time1 := SDL_GetTicks;
if ( time1 - TO2 >= 1000 ) then
begin
seconds := ( time1 - TO2 ) / 1000.0;
fps := Frames / seconds;
Self.Caption := IntToStr(frames) + ' frames in ' + FloatToStr(seconds) + ' seconds = ' + FloatToStr(FPS) + ' FPS';
TO2 := time1;
Frames := 0;
end;
end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
SDL.SDL_FreeSurface(Screen);
SDL_Quit;
end;

end.


Any idea about it? Why is some pixels don't paint when I move mouse fastly and what's the solution?

Note: I try other SDL painting algorithms except "SDL_Gfx.filledCircleRGBA" but the problem is continue.

Clootie
11-01-2006, 09:03 PM
Because mouse coordinates are changed discretly (IIRC: 100Hz by default for USB in WinXP). And moving mouse too fast produces adjacent samples to be distant enought in screen space...

anubis79
11-01-2006, 09:56 PM
Hımm. So what can I do for fluently and perfect painting? Also I know a program which can make some good paintings and of course it uses SDL. But it is written by C. Here: http://www.newbreedsoftware.com/tuxpaint/ and it's ok on my machine.

And can you look at http://www.icculus.org/~lucasw/prog/paintwin.exe
This is a native SDL example. How does it do this kind of drawing fluently and catching all mouse movements?

JSoftware
11-01-2006, 10:04 PM
you have to use a line painting algorithm. paint a line from the old mousecoordinate to the new one

User137
12-01-2006, 02:00 AM
Have you checked your fps? (DXTimer.Framerate) If it's over 100 there wouldn't be much problems.

But you can't achieve fluent drawing using a timer! Either use onMouseMove event or directly handle mouse message using Winapi, both are equally fast and very smooth solutions. Plot lines on those mouse events but flip screen on timer. Or if you don't have animation on your program, then timer is not needed anywhere but you can draw on mouse events...

anubis79
12-01-2006, 07:36 PM
OK. Well. First, Thanks everybody who send a reply for my topic. As JSoftware mentioned, I looked for a line drawing algo then found some theoretic concepts. For example about famous "bresenham line drawing algorithm" or "Digital Differential Analyzer" and of course practical solution SDL_GFX.lineRGBA.
Have you ever been use GDI's or Canvas's LineTo(X, Y) method? If you use you probably notice it's useful for painting and this function's main concept is to take advantage of relative coordinates (xrel, yrel) for drawing from one point to another. So I transfer this logic for SDL and here is my simple code and efficient result:


unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, SDL, sdl_gfx, DXClass, SDLUtils, StdCtrls, gl, Sdl_Draw;
type
TForm1 = class(TForm)
Panel1: TPanel;
DXTimer1: TDXTimer;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure DXTimer1Timer(Sender: TObject; LagCount: Integer);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Screen : PSDL_Surface;
Pushed: boolean;
time1: cardinal;
Frames, TO2: GLInt;
seconds, fps : GLFloat;
X, Y: integer;
implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
SDL_putenv('SDL_VIDEODRIVER=windib');
SDL_putenv(PChar('SDL_WINDOWID=' + inttostr(Integer(Panel1.Handle))));
SDL_Init(SDL_INIT_VIDEO);
Screen := SDL_SetVideoMode(Panel1.ClientWidth, Panel1.ClientHeight, 32,
SDL_SWSURFACE or SDL_DOUBLEBUF);
end;

procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
var
event: TSDL_Event;
RECT: TSDL_Rect;
begin
//Let's Paint
if (SDL_PollEvent(@event) > 0 ) then
begin
case event.type_ of
SDL_MOUSEBUTTONDOWN:
begin
X := event.motion.x;
Y := event.motion.y;
pushed := true;
end;

SDL_MOUSEBUTTONUP: pushed := false;

SDL_MOUSEMOTION:
if pushed then
begin
RECT := SDLRect(0, 0, Panel1.ClientWidth, Panel1.ClientWidth);
// SDL_Gfx.filledCircleRGBA(Screen, event.Motion.x, event.Motion.y, 5, 255,0,0,255);
event.Motion.xrel := X;
event.Motion.yrel := Y;
SDL_Gfx.lineRGBA(screen, event.Motion.xrel, event.Motion.yrel, event.Motion.x, event.Motion.y, 255,0,0,255);
SDL_UpdateRects(Screen, 1, @RECT);
X := event.Motion.x;
Y := event.Motion.y;
end;
end;

//Lets calc to FPS
Inc( Frames );
time1 := SDL_GetTicks;
if ( time1 - TO2 >= 1000 ) then
begin
seconds := ( time1 - TO2 ) / 1000.0;
fps := Frames / seconds;
Self.Caption := IntToStr(frames) + ' frames in ' + FloatToStr(seconds) + ' seconds = ' + FloatToStr(FPS) + ' FPS';
TO2 := time1;
Frames := 0;
end;
end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
SDL.SDL_FreeSurface(Screen);
SDL_Quit;
end;

end.