Results 1 to 10 of 15

Thread: JUI - Another GUI

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    PGD Staff / News Reporter phibermon's Avatar
    Join Date
    Sep 2009
    Location
    England
    Posts
    524

    Arrow JUI - Another GUI

    Hi peeps, bit of an update for you, I've now started work on the visual side of the window/widget manager JUI. This is a re-design/re-write of my old VFA Window manager.

    I've included screen shots of both the old VFA (craft2y.jpg) and the new JUI (CC_EARLY.JPG) so you can see where it currently stands in terms of matching the features of VFA.

    VFA was a single threaded, immediate mode GUI with no message sub system (everything was triggered in events filtering down through the windows/widgets). This worked but was quite slow and the design was around 20 years out of date.

    JUI is a multi-threaded, soon to be non-immediate, message driven window manager. Every single window and widget runs in it's own thread, able to deploy messages directly to any other component, including it's parent, in a lock free manner.

    Because each widget runs in it's own thread as opposed to only a window having a thread in conventional desktop OS's, it allows for a nice trick: E.g. you can write some code that looped to infinity and place it in the onclick event of a button. The button will lock but every other widget and window is still functional.

    The only issue with this design is thread overhead. if you have 100 widgets, you have 100 threads. This can become a problem as you move to several hundred widgets due to the memory allocation of each thread within the OS, basically your limited to around 2000 threads under posix systems, around 600 on Windows systems.

    Here is an example unit for creating a window, widgets assigning callbacks etc

    (Initialization of the Window manager and various other supporting functions is trivial so I won't display here)

    Code:
    unit cc_guimain;
    
    {$mode objfpc}{$H+}
    {$i jui.inc}
    {$i pin.inc}
    {$i cc.inc}
    
    interface
    
    uses
      Classes, sysutils, sdl, u_gl,
    
      j2d, j2d_poly, j2d_polygroup, j2d_tspline,
    
      jui_const, jui_log,  jui_screen, jui_textureman, jui_font,
      jui_mouse, jui_cursor,
    
      jui_global, jui_message, jui_messenger, jui_keyboard,
      jui_lockable, jui_theme, jui_element, jui_window,
      jui_windowman, jui_widget, jui_basetypes, jui_titlebar, jui_button,
      jui_colourwheel, jui_editbox, jui_listview, jui_scrollbar,
    
      pin_log, pin_lockable, pin_message, pin_messenger, pin_tcp,
    
      cc_global, cc_gamestate;
    
    
    type
        TCCGUIMain = class
        private
              WindowMan : TJUIWindowMan;
        public
              Window : TJUIWindow;
              TitleBar : TJUITitleBar;
              StartServerButton : TJUIButton;
              StartClientButton : TJUIButton;
              EditBox : TJUIEditBox;
              ListView : TJUIListView;
    
              constructor create(AWindowMan : TJUIWindowMan);
              destructor destroy;override;
              procedure StartServerClick(ButtonMessage : TMsgMouseButton);
              procedure StartClientClick(ButtonMessage : TMsgMouseButton);
    
    
        end;
    
    
    implementation
    
    
    constructor TCCGUIMain.create(AWindowMan : TJUIWindowMan);
    var
       TempButton : TJUIButton;
    begin
         WindowMan := AWindowMan;
         
         Window := WindowMan.CreateWindow;
         Window.LocalRect := J2DRect(10,10,360,360);
         Window.Caption := 'GUIMain - Testing Widgets';
         TJUIWidget(TitleBar) := Window.CreateWidget(TJUITitleBar);
         TitleBar.LocalRect := J2DRect(0,0,window.width,19);
         Titlebar.Caption := 'GUIMain';
    
         TJUIWidget(StartServerButton) := Window.CreateWidget(TJUIButton);
         StartServerButton.LocalRect := J2DRect(5,25,80,45);
         StartServerButton.Caption := 'Start Server';
         StartServerButton.OnMouseClick := @StartServerClick;
    
         TJUIWidget(StartClientButton) := Window.CreateWidget(TJUIButton);
         StartClientButton.LocalRect := J2DRect(95,25,170,45);
         StartClientButton.Caption := 'Start Client';
         StartClientButton.OnMouseClick := @StartClientClick;
    
         TJUIWidget(EditBox) := Window.CreateWidget(TJUIEditBox);
         EditBox.LocalRect := J2DRect(180,25,290,41);
    
    
         TJUIWidget(ListView) := Window.CreateWidget(TJUIListView);
         ListView.LocalRect := J2DRect(5,55,290,305);
         ListView.Anchor.Right := true;
         listview.anchor.bottom := true;
    
         listview.Columns[0].Caption := 'I love';
         listview.AddColumn('Fish');
         listview.AddColumn('Fingers');
    
    
         listview.AddItem('It''s all good');
         listview.Items[ListView.NumItems-1].SubItems[0].caption := 'This Is A SubItem';
    
    
    end;
    
    destructor TCCGUIMain.destroy;
    begin
         inherited;
    end;
    
    procedure TCCGUIMain.StartServerClick(ButtonMessage : TMsgMouseButton);
    begin
         if assigned(CCGlobal.PINServer) then
         begin
              CCGlobal.PINServer.OutBoundRelay := nil;
              freeandnil(CCGlobal.ServerState);
              freeandnil(CCGlobal.PINServer);
    
         end else
         begin
              CCGlobal.PINServer := TPINServer.Create('0.0.0.0',6969);
              CCGlobal.ServerState := TCCServerState.create;
    
              CCGlobal.ServerState.OutBoundRelay := CCGlobal.PINServer;
              CCGlobal.PINServer.OutBoundRelay := CCGlobal.ServerState;
    
              CCGlobal.PINServer.Listen;
         end;
    
    end;
    
    procedure TCCGUIMain.StartClientClick(ButtonMessage : TMsgMouseButton);
    begin
         if assigned(CCGlobal.PINClient) then
         begin
              CCGlobal.PINClient.OutBoundRelay := nil;
              freeandnil(CCGlobal.ClientState);
              freeandnil(CCGlobal.PINClient);
         end else
         begin
              CCGlobal.PINClient := TPINClient.Create('192.168.0.1',6969);
              CCGlobal.ClientState := TCCClientState.create;
    
              CCGlobal.ClientState.OutBoundRelay := CCGlobal.PINClient;
              CCGlobal.PINClient.OutBoundRelay := CCGlobal.ClientState;
    
              CCGlobal.PINClient.Connect;
         end;
    end;
    
    end.
    So yes, I shall be releasing this at some point but I'm looking for another developer to help me with the workload. There's still a number of widgets I need to re-code and I may need help on moving to a faster VBO rendering method (need new font units, is GLViewPort depreciated? EDIT : GLViewPort is *not* depreciated )

    The old VFA is usable in much the same manner, but the design stinks. if you really want it, let me know.

    and on a side note I've nearly finished PIN and I'm going to wrap up my hardware skinning lib from P3D, in my opinion the most modern skinning implementation in delphi (EDIT:FreePascal/Lazarus for me personally, all the way ) that I've seen so far, hence why I want to give it to the community.

    Peace.
    Attached Images Attached Images
    Last edited by phibermon; 13-10-2010 at 10:24 PM.
    When the moon hits your eye like a big pizza pie - that's an extinction level impact event.

  2. #2
    Impressive. I don't think this has been done before.

    Is it easy to use this for different projects, in terms of combining it with an existing engine?
    It also reminds me that I have to get into threading someday. That's still on my list.

    Looking forward to the release.
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

  3. #3
    PGD Staff / News Reporter phibermon's Avatar
    Join Date
    Sep 2009
    Location
    England
    Posts
    524
    I'm designing it specifically with other coders in mind. At the core of the system is the messenger object and message types, each messenger object is a thread that has a mutex protected object queue and functions for popping and pushing messages. The basic rule is that as messages move around, they are only within one messenger at a time so they don't have to be thread safe (which is good for performance). The thread as it spins around, checks the queue for messages, calls a virtual; abstract; function (domessage) for handling the message which returns if the message was passed on or not. if not, the message is destroyed.

    Most objects in the UI are sub-classes of this messenger object, the implemented domessage for each sub-class handles whatever logic you like for any message type you like, in JUI's case the messages are mouse movement, window close requests, keyboard etc

    this means that every thread can handle it's local messages without blocking the other threads, and only rarely blocking when there is simultaneous domessage popping and external pushing.

    At the moment the main application thread, by means of another thread has a locked-frame rate. it iterates through the tree of window manager, windows, widgets etc locking that element, calling render then unlocking the element.

    This is a problem, it needs to lock as other threads may very well manipulate the values used for rendering (position, colour theme etc). So with a high volume of elements, the rendering thread will have to wait on the occasional lock. I've minimized this best I can but unfortuantly very rarely this causes a visually identifiable 'pause' in events (mouse stalls). it's hardly noticable and as I'm running on a slow system (Atom 330), most people wouldn't notice at all. But I'm a perfectionist so I can't leave it like that

    I'm going to solve this by improving/rewriting the locking mechanisms in order to decrease/eliminate the potential for this to happen.
    Last edited by phibermon; 02-10-2010 at 04:26 PM.
    When the moon hits your eye like a big pizza pie - that's an extinction level impact event.

  4. #4
    PGD Staff / News Reporter phibermon's Avatar
    Join Date
    Sep 2009
    Location
    England
    Posts
    524
    oh I forgot to mention, it's tested on linux + windows as well as PIN and the P3D skinning stuff. I'm using SDL for my OS window creation, mouse/keyboard input but there's no reason you can't drop it into any framework that provides these things. The goal when it's all working is to abstract the rendering functions so I can support API's other than OpenGL. However at the moment there is no 'region invalidation' which means when one thing moves, everything needs to be drawn again. This is fine for hardware accelerated game setups as you're redrawing everything anyway, but a software render wouldn't match the performance as it would amount to a lot CPU time that you'd want to use for actual program code. Anyone with any experience with this?
    When the moon hits your eye like a big pizza pie - that's an extinction level impact event.

  5. #5
    Co-Founder / PGD Elder WILL's Avatar
    Join Date
    Apr 2003
    Location
    Canada
    Posts
    6,107
    Blog Entries
    25
    Wow this is quite impressive. Nice work.

    How lightweight can this be made? Also what are your plans for fonts and potential font file formats you'll be supporting. A good menuing and interface system can really make the difference for a game's polish and accessibility.
    Jason McMillen
    Pascal Game Development
    Co-Founder





  6. #6
    multithreaded UI is welcome !!
    I can't wait to see it released

  7. #7
    PGD Staff / News Reporter phibermon's Avatar
    Join Date
    Sep 2009
    Location
    England
    Posts
    524
    Quote Originally Posted by WILL View Post
    Wow this is quite impressive. Nice work.

    How lightweight can this be made? Also what are your plans for fonts and potential font file formats you'll be supporting. A good menuing and interface system can really make the difference for a game's polish and accessibility.
    Well at the moment I'm using bitmap fonts (generated using one of the many different tools), there is no texture filtering on the font and all alignment is centered in pixels which means you get pixel perfect, non blurry text. However, as long as font lib can return geometry/bitmaps and provide methods for obtaining character widths with kerning (opentype headers anyone?) Then it's good. Is there any existing font lib for pascal that you'd recommend? I know I can easily create outline fonts using the Win32 API and the X API under posix systems however I'd much prefer a cross platform lib that's supported on the 3 main platforms

    in terms of 'weight', there's around 150kb of source that you need for a functioning system but with a good smart-linker it works out quite well.

    All widgets live in their own units so obviously only linking the ones you use.
    Last edited by phibermon; 02-10-2010 at 11:21 PM.
    When the moon hits your eye like a big pizza pie - that's an extinction level impact event.

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
  •