Results 1 to 6 of 6

Thread: Where's the bottleneck

  1. #1

    Where's the bottleneck

    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:

    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.

  2. #2

    Where's the bottleneck

    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...
    There are only 10 types of people in this world; those who understand binary and those who don't.

  3. #3

    Where's the bottleneck

    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?

  4. #4

    Where's the bottleneck

    you have to use a line painting algorithm. paint a line from the old mousecoordinate to the new one
    Peregrinus, expectavi pedes meos in cymbalis
    Nullus norvegicorum sole urinat

  5. #5

    Where's the bottleneck

    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...

  6. #6

    Where's the bottleneck

    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:


    [pascal]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.[/pascal]

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •