Jump to content

Josh

Staff
  • Posts

    23,392
  • Joined

  • Last visited

Blog Entries posted by Josh

  1. Josh
    I figured out how to make our GUI resolution-independent so that the existing editor code will correctly create items with the same proportions. This was very difficult, and it works really well! Some images aren't scaled here, but the important thing is the existing code is working the same, with no changes.
     
    When the GUI is scaled to 200%, the buttons are bigger and indented further in from the right / bottom edges. The code that creates them just calls the parent ClientWidth() minus 74 or so, and without changing that code it now scales the button as you would expect. This was very difficult to figure out and I wasn't sure it was even possible.
     
    100%

     
    200%

     
    50%

     
    This means Leadwerks will scale right for 4k monitors, or any other resolution.
  2. Josh
    A new build is available on the beta branch on Steam. This updates everything, C++ and Linux included.
     
    A bug where the editor skipped navmesh calculation on brushes is fixed.
     
    We're updated to the latest version of the Steamworks SDK, which may fix some Workshop upload and download issues.
     
    Animation now calculates more than twice as fast as previously. This was achieved by optimizing the animation code, implementing some inline functions, and by changing the way the matrix updating works. The UnlockMatrix() command will now accept a single integer parameter for the update type. Zero will perform no updating. This should only be used if the entity's 4x4 matrix has been manually set. (So really, it should never be used by you.) 1 is the default setting which updates the entity's bounding boxes, octree node, etc. 2 is used to only update the entity's 4x4 matrix, which is much faster.
     
    The animation manager script is modified to use the fastest method on bones:

    --Unlock entity matrix if any animations were applied if doanimation==true then self.entity:UnlockMatrix(2) end
     
    If you are using large numbers of animated characters, another easy way to make things even faster is to only animate them every Nth frame. If you have a large number of characters the lack of continuous motion each frame won't really be noticeable.
     
    Update your project to get the latest Steamworks DLL.
  3. Josh
    We're up to 81 games in Steam Workshop now, and I expect we'll see quite a few more released before the end of the tournament. Some of the stuff this tournament especially is really good, so it's not too soon to start thinking about the final release of game launcher on Steam. At that point the application will no longer be marked "Early Preview" and will get a big increase in downloads on Steam since its visibility will be much higher.
     
    I want to launch with at least 100 total games. This seemed like a tough task back when I first came up with this idea, but we're nearly there now. 15-20 games will be marked as a "staff pick" and be displayed with a badge recommending players try those games first. By default, those will probably be the first ones displayed when the user opens the application. Any games that aren't working at launch time will be hidden. (Fortunately, 95% of the stuff uploaded keeps working with the current build of the engine, even after a year.)
     
    To get ready for launch, I recommend you make sure your game's window creation code is working correctly. You can copy and paste the window creation code from main.lua to make sure your game is created with the resolution the user specifies, and the right fullscreen setting.
     
    We might or might not support VR on launch. Although these games are not built with VR in mind, it is possible to make them work with sit-down VR without any changes. On one hand that might not be a good user experience, but on the other hand some of them could be really fun and it might attract a lot of players who want to try 100 new VR experiences. We'll see.
     
    There may be a possibility to sell your games through game launcher, using the same system that is in use right now for the Workshop Store, but I am not sure yet if this is something we will do. The first thing to do is just make sure the launcher's user experience and the games are good, get a bunch of free players, and then see what we want to do with it.
  4. Josh
    So I've been using Valve's VR technology quite a while before the HTC Vive was released, but I only recently picked up the final consumer version. Here are my thoughts on VR games.
     
    First, VR games are completely different from non-VR games. Motion in the virtual world should never contradict motion in the real world. All the early Oculus demos are examples of what not to do.
     
    "The Lab" by Valve really shows the depth of interaction VR opens up. You interactions with the virtual world are so much deeper than you can achieve with a mouse and keyboard, looking through a pane of glass into the world.
     
    The problem of limited movement has been solved by adding a teleportation mechanic. You aim where you want to go, the screen fades out and back in, and you're in the new location. I found it very easy to understand and convenient.
     
    Being able to walk around in VR is critical. You can crouch down and look on shelves to find items, and it feels very natural. A good VR game will have "focal points" where the user tends to stay in one spot. In reality, we tend to do that as well. Right now I am sitting at my desk, and although I am not walking around, I can sit here and move within a limited space.
     
    Tactile feedback is possible, and extremely compelling. When you strike an object with a sword and feel a slight bump in your controller, it is incredibly convincing. One of the most surreal moments I had was when I walked up to a door and simply grabbed the doorknob. It was locked, but I felt a slight movement as I tried to turn it.
     
    There are no good full VR games right now. Valve's demos show the incredible depth of interaction that is possible, and the only things out right now are some unpolished lightweight indie games. When I was in "The Shop" I realized how incredible it would be to play a game like Amnesia: The Dark Descent in VR. There isn't anything out there like that right now, but the possibility is wide open.
     
    Finally, the approach and technology for making a VR game is a little different. Textures and models should be very high-resolution. At the same time, the best VR games focus on small areas instead of huge expanses, so your view range can be as little as ten feet. Framerates have to be consistently high, and I would only recommend C++ for a VR game. Finally, post-processing effects are pretty much a thing of the past since they work on a flat image and not in a real 3D world. The next major iteration of Leadwerks is going to be engineered specifically with these parameters in mind.
  5. Josh
    As described previously, I decided to create a custom widget script to replace the game launcher's HTML panel. The results are already looking awesome! The UI looks really slick. It's great to see this idea come to life in such a striking and attractive manner.
     
    What's really cool is the OS drawing commands are being used, so the games grid uses cleartype subpixel antialiasing, and the UI is completely solid with no flashes or little visual glitches.
     

     
    Oh, and except for the window titlebar and frame, this will look exactly the same on Linux.
  6. Josh
    When the new Window::Embedded style is used in the window creation function, the window will appear as a panel, as part of the parent window. The black region here is an embedded window parented to the main window. (The tabber and other panels and controls are all just Leadwerks objects; Windows doesn't recognize them or know they're there, as they are just created by Leadwerks structures and drawing commands.)
     

     
    Why is this special?
     
    The embedded child window uses single-buffer drawing mode and can be used to create a rendering context, just like you do now. In Leadwerks Editor, this is used for viewports you can interact with. In Leadwerks Game Launcher, this is used for our HTML renderer which displays a grid of available games, by using Chromium Embedded Framework to render an HTML page to a texture and display it in 3D. (The Workshop browser in Leadwerks Editor works the same way).
     
    As you can see, it takes a lot of work to make something appear simple!
  7. Josh
    The combobox and listbox widget scripts are now updated. The combobox is presently using a more game-like style that jus shows the currently selected item. You can change the selection by clicking on the widget with the mouse, pressing keyboard keys, or scrolling the mouse wheel.
     
    The listbox includes a slider that automatically appears when needed. In order to make rendering faster, the draw function calculates the first and last visible items, and only iterates through those items while drawing. That means that whether the list contains ten items or 1000, it will render at the exact same speed.
     
    I have not yet figured out how to handle holding the mouse to continue scrolling the slider, since there is no MouseRepeat event in Windows (and probably not in Linux either).
     


     
    You can get this update now on the beta branch on Steam.
  8. Josh
    MaxGUI is an abstracted GUI system for the BlitzMax programming language. This allows Windows, Mac, and Linux native UIs to be created using the same code. The LeadwerksMaxGUIDriver module integrates Leadwerks GUI so that existing programs can be recompiled using our new UI system. Here's the first shot of it working in an actual existing program:
     

  9. Josh
    The text area widget is now available on the beta branch on Steam, for Windows and Lua only at this time.
     
    The text area is a read-only widget at this time. However, the text is all selectable, and in the future will be able to be copied to the clipboard. This widget creates two scroll bars which appear only when needed, for horizontal and vertical scrolling. The multiline text selection and scrolling was pretty difficult to implement, but the results are really nice.
     

     
    I'm not going to turn this into a full text editor unless I decide to implement everything a modern code editor needs; autocomplete, code folding, and syntax highlighting. Scintilla does a good job of this, so there is no need at this time for me to duplicate that work. However, it is nice to know we could do that with a little more work if needed at some point in the future.
     
    In Leadwerks Editor, this will be used for the script output log and the program log.
     
    At this point, I have all the pieces I need to utilize Leadwerks GUI into Leadwerks Game Launcher and get this released for Windows and Linux. I'm going to try to find a way to detect big picture mode so the game launcher will launch in fullscreen mode without a titlebar when this happens.
  10. Josh
    It took most of the weekend, but I've got Leadwerks GUI running on Linux, rendering directly to an X11 window. This is the fastest possible rendering method on Linux, and I think you'll agree the results are worth it. You can try a demo here:
    http://www.leadwerks.com/werkspace/topic/14867-gui-demo/#entry100912
     

     
    Just like the Windows implementation, I found it necessary to implement double-buffering. In X11 this is accomplished with the use of an extension called "xdbe". The documentation for usage of this feature is quite extensive and it's difficult to track down any working examples. Digging into reference material from 1995 really made me feel like an archaeologist, but ultimately I finally got it working and you can see the results. There's absolutely no flickering and because Leadwerks GUI is extremely good at rendering only the part of the screen that requires updating, it's super fast.
     
    This library could be extremely helpful to developers making cross-platform desktop applications, especially for Linux. None of the existing GUI libraries are very good for writing modern applications. QT has a complicated build process that is difficult to integrate into existing software, and GTK has an asynchronous design that makes development very difficult. The system I am implementing provides fast performance, resolution-independent rendering, and best of all creating a new widget just involves modifying a simple Lua script.
  11. Josh
    In Leadwerks GUI, any widget can be the child of another widget. If the child goes outside of the parent widget's area it will be clipped for both rendering and mouse events. Below you can see the button in the upper-left corner and the progress bar and slider on the right are clipped by the parent tabber.
     

     
    A parent widget can also have a padding value which indents the area. The tabber uses padding on the top to display the tabs and make sure children don't appear on top of the tabs.
     
    Leadwerks also allows you to set an edge mode for each each of each widget (left, right, top, and bottom). This controls how the widgets scale when the window is resized. Here you can see a slider and a listbox have been locked to the right and bottom edges, respectively, and are being stretched out when the window is made larger.
     

     
    I am also interested in bringing LeadwerksGUI to Linux as a standalone library to replace GTK, QT, etc. It's MUCH easier to skin and add new widgets to this system, and it provides resolution independence for any DPI display. Here it is at 75% scaling:
     

     
    And at 400%:
     

  12. Josh
    The slider widget is used for scrollbars, trackbars, and steppers. It has a lot of style options, so it's really six different widgets packed into one. (In Leadwerks Editor, a slider and textfield widget are combined to make the numerical entries you use to adjust positions and other values.)
     

     
    To create a new slider you just create a widget and set the slider script:

    local slider = Widget:Create(230+40,140,20,20,panel) slider:SetScript("Scripts/GUI/Slider.lua")
     
    You can then set the style. The style should be set after the script is assigned. This is because the style flags are initialized in the slider script, so if it hasn't been run already those values will be nil:

    slider:SetStyle(Style.Slider.Stepper + Style.Slider.Horizontal)
     
    The slider can be any of these styles:
    Style.Slider.Scrollbar
    Style.Slider.Trackbar
    Style.Slider.Stepper

     
    And can be combined with the following to be either horizontal or vertical:
    Style.Slider.Horizontal
    Style.Slider.Vertical

     
    The default appearance is a vertical scrollbar.
     
    When a slider is moved either by clicking and dragging it with the mouse, clicking on the trackbar, moving the mouse wheel when the widget is focused or pressing the arrow keys when the widget is focused, the widget will emit a WidgetAction event, with the slider value stored in the event.data member.
     
    So far none of the widgets are using any images. The arrows and slider knob are using DrawPolygon() to render the shape.
     
    This is available now on the beta branch on Steam, for Lua on Windows only at this time.
  13. Josh
    I've added a textfield widget script to the beta branch, and a new build, for (Lua interpreter, Windows only, at this time). The textfield widget allows editing of a single line of text. It's actually one of the more difficult widgets to implement due to all the user interaction features. Text is entered from the keyboard and may be selected with arrow keys or by clicking the mouse. A range of text can be selected by clicking and dragging the mouse, or by pressing an arrow key while the shift key is pressed.
     

     
    I had to implement an additional keyboard event. KeyDown and KeyEvents work for all keys, but KeyChar events are called when typing results in an actual character. The ASCII code of the typed character is sent in the data parameter of the event function:

    function Script:KeyChar( charcode ) end
     
    Making the caret indicator flash on an off goes against the event-driven nature of this system, but I think it's an important visual indicator and I wanted to include it. I went through a few ideas including a really over-engineered timer system. Finally I just decided to make the GUI call a function on the focused widget every 500 milliseconds (if the function is present in the widget's script):

    --Blink the caret cursor on and off function Script:CursorBlink() if self.cursorblinkmode == nil then self.cursorblinkmode = false end self.cursorblinkmode = not self.cursorblinkmode self.widget:Redraw() end
     
    All in all, the script weighs in at 270 lines of code. It does not handle cut, copy, and paste yet, and double-clicking to select the entire text does not yet consider spaces in the clicked word. The drawing function is actually quite simple, so you could easily skin this to get a different appearance and keep the same behavior.
     

    Script.caretposition=0 Script.sellen=0 Script.doubleclickrange = 1 Script.doubleclicktime = 500 function Script:Draw(x,y,width,height) local gui = self.widget:GetGUI() local pos = self.widget:GetPosition(true) local sz = self.widget:GetSize(true) local scale = gui:GetScale() local item = self.widget:GetSelectedItem() local text = self.widget:GetText() --Draw the widget background gui:SetColor(0.2,0.2,0.2) gui:DrawRect(pos.x,pos.y,sz.width,sz.height,0) --Draw the widget outline if self.hovered==true then gui:SetColor(51/255/4,151/255/4,1/4) else gui:SetColor(0,0,0) end gui:DrawRect(pos.x,pos.y,sz.width,sz.height,1) --Draw text selection background if self.sellen~=0 then local n local w local x = gui:GetScale()*8 local px = x local c1 = math.min(self.caretposition,self.caretposition+self.sellen) local c2 = math.max(self.caretposition,self.caretposition+self.sellen) for n=0,c2-1 do if n==c1 then px = x end c = String:Mid(text,n,1) x = x + gui:GetTextWidth(c) if n==c2-1 then w = x-px end end gui:SetColor(0.4,0.4,0.4) gui:DrawRect(pos.x + px,pos.y+2*scale,w,sz.height-4*scale,0) end --Draw text gui:SetColor(0.75,0.75,0.75) if text~="" then gui:DrawText(text,scale*8+pos.x,pos.y,sz.width,sz.height,Text.Left+Text.VCenter) end --Draw the caret if self.cursorblinkmode then if self.focused then local x = self:GetCaretCoord(text) gui:DrawLine(scale*8+pos.x + x,pos.y+2*scale,scale*8+pos.x + x,pos.y + sz.height-4*scale) end end end --Find the character position for the given x coordinate function Script:GetCharAtPosition(pos) local text = self.widget:GetText() local gui = self.widget:GetGUI() local n local c local x = gui:GetScale()*8 local count = String:Length(text) local lastcharwidth=0 for n=0,count-1 do c = String:Mid(text,n,1) lastcharwidth = gui:GetTextWidth(c) if x >= pos - lastcharwidth/2 then return n end x = x + lastcharwidth end return count end --Get the x coordinate of the current caret position function Script:GetCaretCoord() local text = self.widget:GetText() local gui = self.widget:GetGUI() local n local c local x=0 local count = math.min(self.caretposition-1,(String:Length(text)-1)) for n=0,count do c = String:Mid(text,n,1) x = x + gui:GetTextWidth(c) end return x end --Blink the caret cursor on and off function Script:CursorBlink() if self.cursorblinkmode == nil then self.cursorblinkmode = false end self.cursorblinkmode = not self.cursorblinkmode self.widget:Redraw() end function Script:MouseDown(button,x,y) self.focused=true if button==Mouse.Left then --Detect double-click and select entire text local currenttime = Time:Millisecs() if self.lastmousehittime~=nil then if math.abs(self.lastmouseposition.x-x)<=self.doubleclickrange and math.abs(self.lastmouseposition.y-y)<=self.doubleclickrange then if currenttime - self.lastmousehittime < self.doubleclicktime then self.lastmousehittime = currenttime local l = String:Length(self.widget:GetText()) self.caretposition = l self.sellen = -l self.widget:GetGUI():ResetCursorBlink() self.cursorblinkmode=true self.pressed=false self.widget:Redraw() return end end end self.lastmouseposition = {} self.lastmouseposition.x = x self.lastmouseposition.y = y self.lastmousehittime = currenttime --Position caret under mouse click self.cursorblinkmode=true self.caretposition = self:GetCharAtPosition(x) self.widget:GetGUI():ResetCursorBlink() self.cursorblinkmode=true self.pressed=true self.sellen=0 self.widget:Redraw() end end function Script:MouseUp(button,x,y) if button==Mouse.Left then self.pressed=false end end function Script:MouseMove(x,y) if self.pressed then --Select range of characters local currentcaretpos = self.caretposition local prevcaretpos = self.caretposition + self.sellen self.cursorblinkmode=true self.caretposition = self:GetCharAtPosition(x) if self.caretposition ~= currentcaretpos then self.widget:GetGUI():ResetCursorBlink() self.cursorblinkmode=true self.sellen = prevcaretpos - self.caretposition self.widget:Redraw() end end end function Script:LoseFocus() self.focused=false self.widget:Redraw() end function Script:MouseEnter(x,y) self.hovered = true self.widget:Redraw() end function Script:MouseLeave(x,y) self.hovered = false self.widget:Redraw() end function Script:KeyUp(keycode) if keycode==Key.Shift then self.shiftpressed=false end end function Script:KeyDown(keycode) if keycode==Key.Shift then self.shiftpressed=true end if keycode==Key.Up or keycode==Key.Left then --Move the caret one character left local text = self.widget:GetText() if self.caretposition>0 then self.caretposition = self.caretposition - 1 self.widget:GetGUI():ResetCursorBlink() self.cursorblinkmode=true if self.shiftpressed then self.sellen = self.sellen + 1 else self.sellen = 0 end self.widget:Redraw() end elseif keycode==Key.Down or keycode==Key.Right then --Move the caret one character right local text = self.widget:GetText() if self.caretposition<String:Length(text) then self.caretposition = self.caretposition + 1 self.widget:GetGUI():ResetCursorBlink() self.cursorblinkmode=true if self.shiftpressed then self.sellen = self.sellen - 1 else self.sellen = 0 end self.widget:Redraw() end end end function Script:KeyChar(charcode) local s = self.widget:GetText() local c = String:Chr(charcode) if c=="\b" then --Backspace if String:Length(s)>0 then if self.sellen==0 then if self.caretposition==String:Length(s) then s = String:Left(s,String:Length(s)-1) elseif self.caretposition>0 then s = String:Left(s,self.caretposition-1)..String:Right(s,String:Length(s)-self.caretposition) end self.caretposition = self.caretposition - 1 self.caretposition = math.max(0,self.caretposition) else local c1 = math.min(self.caretposition,self.caretposition+self.sellen) local c2 = math.max(self.caretposition,self.caretposition+self.sellen) s = String:Left(s,c1)..String:Right(s,String:Length(s) - c2) self.caretposition = c1 self.sellen = 0 end self.widget:GetGUI():ResetCursorBlink() self.cursorblinkmode=true self.widget:SetText(s) EventQueue:Emit(Event.WidgetAction,self.widget) end elseif c~="\r" and c~="" then --Insert a new character local c1 = math.min(self.caretposition,self.caretposition+self.sellen) local c2 = math.max(self.caretposition,self.caretposition+self.sellen) s = String:Left(s,c1)..c..String:Right(s,String:Length(s) - c2) self.caretposition = self.caretposition + 1 if self.sellen<0 then self.caretposition = self.caretposition + self.sellen end self.sellen=0 self.widget:GetGUI():ResetCursorBlink() self.cursorblinkmode=true self.widget:SetText(s) EventQueue:Emit(Event.WidgetAction,self.widget) end end
  14. Josh
    I've updated the beta branch (Lua on Windows only) with a new build that solves the DPI scaling issues I previously described. Widget creation still works the same, using the same coordinate system regardless of GUI scale. Widget scripts must use global coordinates in the drawing commands, which means calling Widget:GetPosition(true) and Widget:GetSize(true). Here's the very simple panel script, which simply draws a solid block on the screen to frame child widgets within:

    function Script:Draw(x,y,width,height) local gui = self.widget:GetGUI() local pos = self.widget:GetPosition(true) local sz = self.widget:GetSize(true) gui:SetColor(0.25,0.25,0.25,1) gui:DrawRect(pos.x,pos.y,sz.width,sz.height) end
     
    I've included this script and a simple button to help get you started.
     
    Raster images can be drawn and scaled in a manner that makes them resolution-independent. The idea of loading SVG vector images at any resolution has been floated, and I think it's a good one, though I have no experience with this format. I think it would work similarly to how we treat fonts right now, a vector format that can be loaded into a raster image at any resolution. So this is something I am interested in exploring.
     
    This would give you three tools to perform drawing in the Widget scripts: Leadwerks drawing commands, raster images, and vector images that would be resolution-independent.
     

     
    I've also added the ability to add Widget items. These would be like entries in a list view or a tabbed panel:

    virtual int AddItem(const std::string& text);//lua virtual std::string GetItemText(const int index);//lua
    virtual int CountItems();//lua
    virtual void ClearItems();//lua
  15. Josh
    I've implemented DPI scaling into Leadwerks GUI (beta branch, Lua on Windows only).
     
    To set the GUI scale you just call gui:SetScale(scalefactor). A scale factor greater than one will make it bigger, a scale factor less than one will make it smaller. There is no limit to the range you can set, but negative numbers are probably not good.
     
    Scaling causes the GUI to be drawn at a different size, but widget dimensions and mouse events are still interpreted as though they were at their original size. For example, the mouse move script function will always indicate a coordinate of (510,510) when you move the mouse into the lower-left corner of a 500x500 widget positioned at 10,10, no matter how big or small the GUI is scaled onscreen. Widget::GetWidth() will return the widget's unscaled dimensions, not the actual size it appears at. To get the actual size, you would multiply the dimensions by the GUI scale factor and round off. However, you should never need to calculate this yourself, as all numbers are made uniform for you.
     
    Scaled widget positions are still rounded to integers in order to make them appears precisely on the screen pixels. We don't want sub-pixel blurring with widgets that line up in between pixels, we want sharp clear pixel-aligned rendering. Interestingly, the mouse script functions are now receiving floating point coordinates instead of integers. For example, if you move the mouse across a widget with the GUI scaled to 200% (2.0) you will see the mouse coordinates change in 0.5 increments like 150, 150.5, 151, 151.5, 152, etc.
     
    Scaling presently does not affect text rendering, as this will take more work to figure out how to manage.
     
    Below is a simple GUI scaled at 100%:

     
    Now at 200%. Note that text scaling is not yet implemented. When it is, the text will appear bigger, proportional to the widget. However lines still appear exactly one pixel thick, as they should:

     
    And finally made smaller, at 50%: Notice that although the lines are still one pixel thick, we have lost the space between the inner and outer rectangles. This is being drawn properly, but it is possible you might run into small issues like this in various resolutions, so it's something to keep in mind.

     
    Of course images cannot be upsampled without losing precision, so any images your GUI uses should originally be at the maximum scale your GUI may use.
  16. Josh
    At 100% scaling this image appears correctly:

     
    At 200% scaling it falls apart. The line points are in fact scaled correctly, but they are not surrounding the shape as intended:

     
    So I think instead of converting the coordinate system back and forth between scaled and non-scaled coordinates, the creation function needs to multiply the coordinates by the scaling factor. That means if you create a 70x30 pixel widget and the GUI is using a 200% scaling factor, it will actually create a 140x60 pixel widget instead. However, the little issues like what is pictured above will go away.
     
    This sucks though because if you do this, you will get wrong results:

    gui:SetScale(2) local widgetA = Widget:Create(0,0,200,20,gui) local widgetB = Widget:Create(0,0,200, widgetA:GetPosition().y + widgetA:GetHeight(),gui )
     
    widgetB would be created at a Y position of 80 (20 * 2 * 2)
     
    I fear whatever I implement will simply get ignored by script programmers and they will never test against different DPI scales.
  17. Josh
    To provide support for advanced GUI rendering, some of the features I implemented in the refactored window class are being brought into the 2D drawing command set. This includes a lot of text rendering features like word wrap, multiline, horizontal and vertical centering, and viewport clipping.
     
    A new text drawing function includes additional parameters for better control:

    Context::DrawText(std::string text, int x, int y, int width, int height, int style)
     
    The style parameter can be a combination of the following options:

    Text::Left Text::Center Text::Right Text::VCenter Text::WordWrap Text::Multiline
     
    Context-based GUIs are now rendered to a texture first, and then the texture is drawn onscreen. This allows GUIs to be partially drawn (only invalidated parts of the GUI are re-rendered). That means if you move the mouse over a button or something, only that button re-renders, and the rest of the UI is just cached in the texture and doesn't have to be redrawn. This makes the GUI performance fast, even when lots of text is shown onscreen. This is perfect for dialog boxes or help screens.
     
    The alpha blend drawing mode has also been changed to use a separate blend function for the alpha values. When a primitive is rendered with alpha blending, the maximum alpha value will be left in the rasterizer. This makes it so the resulting GUI rendered image blends correctly when drawn on top of the screen with alpha blending enabled.
     

  18. Josh
    This code creates a GUI directly on a window, with no OpenGL rendering context created at all. The same scripts can be used for widgets created on a window, a rendering context, or a texture:

    --Initialize Steamworks (optional) Steamworks:Initialize() --Set the application title title="$PROJECT_TITLE" --Create a window local windowstyle = window.Titlebar + window.Resizable + window.Hidden if System:GetProperty("fullscreen")=="1" then windowstyle=windowstyle+window.FullScreen end window=Window:Create(title,0,0,System:GetProperty("screenwidth","1024"),System:GetProperty("screenheight","768"),windowstyle) local gui = GUI:Create(window) gui:GetBase():SetScript("Scripts/GUI/Panel.lua") local widget = Widget:Create(20,20,75,30,gui:GetBase()) widget:SetScript("Scripts/GUI/Button.lua") window:Show() while window:KeyDown(Key.Escape)==false do --If window has been closed, end the program if window:Closed() then break end end
     
    You can try the attached executable to see it working. Notice the zip file contains no textures, shaders, etc. because no rendering context is ever initialized.
  19. Josh
    The beta branch on Steam is updated with a new build. This uses the refactored Window class, on Windows and Linux. The GUI and Widget class are also added, although they are highly experimental and still in development. Both the engine and editor are using the refactored Window class, so please report any erroneous behavior your detect.
     
    Leadwerks is now using GDI+ for some GUI drawing commands, on Windows. You need to update your existing project by modifying the "Linker \ Input \ Additional Dependencies" property in Visual Studio and adding the "msimg32.lib" library.
     
    If you want to play around with the GUI system, check out GUI.h and Widget.h, in the Pro edition.
     

  20. Josh
    Our ranking on Steam is 185 ratings with 75% positive, which Steam categorizes as "Mostly positive". This is great. Over the last couple of years the reviews have gotten more positive as more features and better documentation has been added. So at this point, the more reviews we get the higher our rating goes, since our average rating today is better than when we started on Steam.
     
    From what I gather looking at other products on Steam, we're only 5% away from a "Very positive" rating at 80%. The categorization isn't based on a strict percentage, but I think once you have a high number of reviews it's pretty close. With the developments I have planned for the rest of the year, I think we'll have no problem hitting that number.
     
    If you haven't done so, you can add your review on the store page for Leadwerks Game Engine or in the Steam client. Thanks!
  21. Josh
    This code added to main.lua actually works:

    --Create a window local windowstyle = window.Titlebar if System:GetProperty("fullscreen")=="1" then windowstyle=windowstyle+window.FullScreen end window=Window:Create(title,0,0,System:GetProperty("screenwidth","1024"),System:GetProperty("screenheight","768"),windowstyle) window:HideMouse() --Create the graphics context context=Context:Create(window,0) if context==nil then return end --Create a GUI local gui = GUI:Create(context) local widget = Widget:Create(20,20,75,30,gui:GetBase()) widget:SetScript("Scripts/GUI/Button.lua")
     
    And then "Button.lua" is super simple:

    function Script:Draw() self.widget.gui:SetColor(64,64,64)
    self.widget.gui:DrawRect(self.widget.position.x,self.widget.position.y,self.widget.size.width,self.widget.size.height)
    end
     
    I'll probably be around RTX this weekend, just because I watched RvB back in the day, and it's only a few blocks away at the Austin convention center. Here's what started it all:
     


  22. Josh
    GUI* GUI::Create(window); GUI* GUI::Create(context);
    GUI* GUI::Create(texture);
     
    A GUI created on a window would draw to the window, with no graphics context, and would be used for making 3D applications (like Leadwerks Editor). A GUI created on a context would use OpenGL drawing to render the GUI onto the context. A GUI created on a texture would require the user to manually input events and would be used for interfaces that appear in the 3D world, like a computer panel you can interact with in the game.
  23. Josh
    An update is available on the beta branch. This only updates the editor, only on Windows.
     
    The environment probe entity should now be available to create in the editor, for all users.
     
    When shaders are compiled with the "Debug" button (F5) they will now be run through the GLSlang reference compiler first. This can help to catch errors that more permissive hardware lets slide by (Nvidia). The goal of this is to prevent games from not working on AMD and Intel hardware when they use third-party shaders. GLSlang does not catch deprecated functions like texture2D() but it may catch some other errors Nvidia cards ignore.
×
×
  • Create New...