Jump to content

Josh

Staff
  • Posts

    23,307
  • Joined

  • Last visited

Blog Entries posted by Josh

  1. Josh
    Their prices are more than 250% the price of a comparable PC. Even their "most expensive" laptop is using a budget GPU! So for less than half the price, you can actually get a laptop with a much better GPU!
     
    $999:
    http://www.newegg.co...=laptop%209800m
     
    $2499:
    http://store.apple.c...mco=MTM3NDcyOTc
     
    Just for fun, I checked all the most expensive options. The grand total was $7305.35. Who spends $7000 on a laptop with a budget GPU???
     
    I can't believe how dense their management is. It's as if they don't want to succeed.
  2. Josh
    Leadwerks has historically had a small group of customers outside of the game industry who use our software for simulations, training, and visualization.  Customers using our software products include NASA, Lockheed Martin, Northrop Grumman, and the British Royal Navy.  Today I am happy to announce that in response to overwhelming demand we are now offering our services to build custom VR applications with Leadwerks.
     
     
    This puts us in head-to-head competition with other services firms who are mostly using the Unity3D engine to put out quick results.  However, longstanding design decisions going back years have put Leadwerks Software in a position that gives us very strong advantages in the VR market.  In this article I will explain how we are leveraging our unique competitive advantages to provide the most compelling results for your VR project.
    Leadwerks vs. Unity3D for Virtual Reality
    Most of our competitors have tried to take shortcuts by building on a platform with severe limitations, using the Unity 3D engine together with the C# programming language. This 3D engine is primarily used for mobile games, and the C# programming language was originally created for event-driven business applications.
    We on the other hand have built our own 3D development system that is specifically designed to capture the maximum capabilities of VR.  Our 3D engine is built specifically for high-end PCs, with graphical fidelity and performance as our overarching principles. We use the C++ programming language which is the standard for any computationally intensive code, including operating systems, device drivers, high-frequency trading software, and virtual reality applications, which must operate at a steady 90 frames per second to prevent nausea. Our development approach brings several significant competitive advantages we can now offer to you.
    C/C++ Interoperability
    Virtually all major scientific and engineering libraries like MATLAB, etc. are written in C or C++.  Because our VR development platform is written in pure C++ we can seamlessly integrate with all of your existing C and C++ code. For example, actual satellite control code could be compiled into a simulation and run seamlessly to test how the spacecraft would react to a variety of simulated conditions. All scientific and engineering code libraries are easily accessible from a Leadwerks project.
     
    Competitors using C# and the Unity 3D engine will encounter roadblocks when they attempt to interface with C/C++ code. An intermediate wrapper has to be written that converts object-oriented code into procedural commands. This process is time-intensive and prone to breakage when APIs change with new versions. Integration of C/C++ code with Leadwerks, on the other hand, is instantaneous and seamless.
    Performance
    Nausea is a serious consideration in VR. If a discrepancy exists between the inputs received by the operator’s ocular and vestibular systems, it will result in motion sickness. An engineering tool designed to be used for long periods of time must maintain a steady 90 frames per second, allowing only 11 milliseconds for each frame render. Unfortunately, C# is a memory-managed language meaning it suffers overall slower performance, as well as periodic pauses in program execution while garbage collection is performed. All of our code is written in C++ and will perform at the maximum speed allowed by the hardware. This allows us to create richer VR applications with expanded capabilities while our competitors will run into performance problems that cause unpleasant physiological symptoms.
     

    Benchmark showing execution time of C++ vs. C#.
    Source: https://www.codeproject.com/Articles/212856/Head-to-head-benchmark-Csharp-vs-NET
    Source Code Modification
    Because we developed our own 3D engine we have full access to the entire source code and can make modifications to expand its capabilities (5). For example, we learned that some aerospace clients were experiencing problems with 32-floating point precision in some applications, so we re-compiled our software using 64-bit floating points, raising the maximum area we can simulate up to one cubic light year with sub-millimeter precision. Because our competitors do not have source code access to the 3D engine they are using, their ability to elastically scale their capabilities and customize their 3D engine for your needs will be greatly impeded.
    Accuracy of Simulated Physics
    Our software features a fast and stable Newtonian physics system that provides the most realistic physics simulation possible at real-time speeds. As the video above demonstrates, this can be used to simulate robotic arms and other moving mechanical features with a high degree of realism.
     
    The Unity physics system was designed for games and runs on the graphical processing unit (GPU). GPUs are good at performing massive parallel processing computations but are not good at problems that involve a lot of data exchange. Unfortunately, colliding objects are a problem that involves a high degree of data exchange between threads, so the accuracy of the simulation is compromised. This has two significant consequences. First, physics in Unity tend to be much less stable than in Leadwerks, making it difficult to simulate complex jointed systems like a robotic arm. A video showing the difference can be seen here.
     

    Rigid body stacking test: Leadwerks physics (green) are stable while Unity physics (yellow) spontaneously collapse.
    Second, physics in Unity are non-deterministic. This means that each time a simulation is run, the result will be different, making it very difficult to predict outcomes. The Leadwerks physics system is deterministic and will provide the exact same result each time it is run, even if new objects are introduced into the simulation.
    The competitive advantages we can put to work for your VR project are summarized below.  Simply put, we can build applications that are bigger, faster, and have more capabilities.
     
      Other firms using Unity
    Leadwerks VR Services
    Primary platform of 3D engine
    Mobile phones
    High-end PCs
    C/C++ Interoperability
    Requires C# wrapper
    Seamless
    Performance
    Slower with GC pauses, results in nausea
    Fastest possible performance
    3D engine source code modification
    No
    Yes
    Physics simulation
    Unstable, non-deterministic
    Stable, deterministic
    Maximum range with sub-mm precision
    Eight kilometers
    One light year
    If you are interested in taking advantage of our capabilities to build VR applications send us an email, or catch me at I/ITSEC later this week.
  3. Josh
    The development of Leadwerks3D seemed like an impossible task at first. Not only did I need to write a new 3D engine entirely in C++ mostly by myself, but I had to make it run on four platforms (Android, iOS, Windows, and Mac), with a scalability all the way from the fixed-function pipeline up to the very latest hardware tessellation features. All logical sense told me this was impossible. Even large companies with 100 programmers or more haven't yet been able to put out a 3D engine with the range of platforms and scalability I am targeting. What makes me think I can do it?
     
    As we approach the initial release of Leadwerks3D, what I thought was impossible seems much more feasible now. During the course of development of Leadwerks3D, I've learned some important ideas that give a lot of hope to me and to indie game developers everywhere.
     

    Systemic Interdependence
    When managing complex tasks there's something called systemic interdependence. This refers to the idea that when you have many people working on one project, they are rarely isolated from one another. They often have to stop and wait for another person's job to be done before they can continue with their own, and programmers often end up stepping on each other's toes when they work together. 
    Even though only Aria and I are working on the source right now, we have experienced this. It's very important we keep busy with separate aspects of the engine. Aria works on platform implementation issues, I work on the core engine design, and we try our best to keep the source code repository in sync. So far this works well for us, but I could easily see a lot of problems arising if we had more people working on parts of the engine that aren't so easily compartmentalized.
     
    Think about your own game. What if I told you I was willing to give you as much money as you wanted to hire programmers, (as long as your final project gave me a big return on my money). Sound great, right? So you go out and hire ten programmers. They come in every weekday, 9 to 5. They're willing to work, but you have to instruct them and keep them busy and productive. Don't have anything for them to do at the moment while you finish one little part? Too bad, they're still on the clock and you still have to pay them.
     
    With ten programmers, would your game get done ten times faster? Almost certainly not. In fact, as you add programmers, your work output will probably look something like the graph below. With one programmer, we have an output of 100 arbitrary units. We gain efficiency with the first few programmers, but the effect lessens with each additional worker. They have to wait for another person to finish something. Now the code repository is conflicted, and you have to figure out how who added what code. You also have an increasing number of relationships and communication between individuals.
     

     
    Once we get past five programmers, additional programmers actually have a detrimental effect to our output. If we continue adding more workers, we can reach levels of output that are below even that of a single programmer. Imagine if 30 people were working on your game. It would be chaos, and that whole time you would be burning money as they came in every day. Meanwhile, your investors would be sitting impatiently, expecting you to get back a lot more money than they put in.
     
    My chart above isn't precise, and the number of programmers a project can support will vary based on its ease of compartmentalization, but the overall idea stands: Software development does not scale very well with additional manpower. This is why small companies are continually springing up and outmaneuvering larger ones. Android came from a small company. It was bought by Google, but only after a small team had built the foundation. Minecraft came from a very small company. Kinect originally came from a small company. Small companies with focused goals are able to compete with much larger companies because of the effect of diminishing returns.
     

    Performance and Motivation
    Another problem big companies have is motivation. In a professional software development environment, managers like to have measurable performance metrics to evaluate employee efficiency. These are used for performance evaluations, and are the basis for salary increases, promotions, and disciplinary actions. Managers set goals and milestones that can be easily measured after a period of time. Workers respond to this by doing exactly what management tells them because they get rewarded for it. If a worker has an idea for a new technique that might or might not work, they're not as likely to spend time on it in this environment. If it works, the company gets to keep their idea and they get nothing. If it fails, they've wasted time on something that doesn't fit into their manager's ideas of measurable performance. Now, a lot of tech companies do try to encourage innovation, but if a worker has an idea for something they really believe in, they are more likely to form their own company where they can be in complete control of their vision. The professional software development environment does not encourage risk-taking and innovation the same way small companies do, because they need easily measurable metrics to assess performance. They only get out of employees what they reward, and it's hard to measure the value of new ideas and attention to detail. 

    Conclusion
    These ideas I've learned during the development of Leadwerks3D are directly applicable to your own game projects. Don't get discouraged when you run into a tough problem. Even if you had more help, you would still have to figure out a solution, one way or another, and you wouldn't be able to shift that responsibility off onto employees. You can do it, just be wise about where you focus your efforts and plan carefully. 
    --Edit--
     
    I posted this article on GameDev.net and got a few interesting responses:
     
  4. 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
  5. Josh
    This is my opinion of Windows 7. When I tried Vista, I immediately disliked it, but used it for eight months. At the end of that period I still disliked it for all the same reasons.
     

     
    Source
  6. Josh
    With the Winter Sale wrapping up, I now have enough information to decide how to go forward with the business of Leadwerks.
     
    Sales on a day-to-day basis were remarkably consistent, and comparable to last year's data, within 5-10% either way. This is good because it indicates that Leadwerks will continue to sell well at a predictable level, which makes planning a lot easier.
     
    We did not get featured this year on the front page of Steam. Very few products did. The whole sale basically just showed the same games over and over, Mortal Kombat X, The Phantom Pain, and Talos Principle, ad nauseam. This sucks, but at least I know not to count on this in the future, and just consider it a nice bonus when it does happen. My income for the year was still more than I would make with a regular job, so I'm happy.
     
    I've recovered about half of the cost I spent to license the models in the nature model pack DLC, within a time period of two weeks. So it looks like it will break even in the near future and start turning a small profit after that. (The point of this pack was mostly just to get you guys the models you need for the new vegetation system.)
     
    The Game Launcher is still in Early Access mode, with about 3700 users. Less than 1% of polled users are using it with Linux, so it doesn't seem like the ability to deploy to Steam Machines is a big selling point at this time.
     
    For 2016, I expect sales to stay at the same level they've been for the last two years. This is good because it means the business of Leadwerks has stabilized and is predictable. We survived new competitors, a price war, and lots of new technologies, and Leadwerks is going strong while other products have failed to gain traction.
     
    I think Game Launcher is nearly ready to come out of Early Access mode, with just a few improvements to be made to the Windows build. The SteamOS version needs some pretty significant UI work, so I think this will be deferred to a later time. I plan to release Leadwerks Game Launcher at the conclusion of the next game tournament.
     
    I believe that perpetual growth is always the goal, so I have the following developments in mind for 2016:
    Release Game Launcher on Steam proper: This will give you a wider audience of players and bring more people to Leadwerks.
    Develop paid Workshop items: I believe this has huge potential for the community, both by giving us access to a wider range of content and by providing a way for you to sell items through Steam.
    More Features: I consider this a maintenance task, because it's just something you do to keep the software evolving. Added features don't translate into an increase in sales, it just maintains the same level and keep things fun and interesting. As long as you understand that a new feature won't have a fundamental transformative effect on your business, then this is a great thing to do. If you are thinking there is one magic feature that will suddenly make you successful, you will be very disappointed. I think this is a good general lesson that applies to all technology products.

  7. Josh
    You can now try out the new Workshop Browser by opting into the beta branch. This makes it simpler to install Workshop items, and allows you to browser, install, and uninstall items without having to switch to the Steam window.
     

  8. Josh
    The implementation of the Leadwerks Workshop has always been planned in two steps:
    Initial implementation using the Steam interface.
    Implementation of built-in interface in editor.

     
    I've been working on the second part for a couple days, and the results are pretty awesome so far. A built-in browser lets you view all items in the Workshop, search, and sort by rating or date uploaded.
     

     
    When you click on an item, you can view its detail view. Pressing the "Install" button will install the item into your current project. (If you aren't already subscribed to the item, you will be automatically.)
     

     
    This simplifies the process of acquiring items from the Workshop, since you no longer have to switch between Leadwerks and Steam, and you don't have to restart Leadwerks to get your item. I have always found the "subscribe" functionality a little confusing, and in the future I hope to make that part of it completely invisible to the end user.
     
    The fact that people are still using the old Downloads area sometimes tells me that the Workshop is not as easy as it could be. Basically, it's competing with zip file downloads. It needs to be easier than downloading and unzipping a zip file. I think we're getting there, because the new browser takes fewer steps.
     

  9. Josh
    The Workshop system is a great way to share content, but I've come across some limitations. Most of these have to do with the use a "virtual" file system (using Workshop package IDs).
    Scripts and shaders can't be debugged because these systems expect a file path. With Workshop files, there is a file name and an ID number. This makes Shadmar's cool effects difficult to access, among other things.
    Interdependent files are very difficult to work with, because when you upload them to the Workshop file associations are lost. For example, if you have a prefab that loads a model with the path "Models\Cars\car1.mdl" that file will not be present with the same path in the Workshop package. The engine does a lot of guessing to find the right file, but it's a ton of extra code and I still encounter situations where it's lost.
    In general, having two file systems means there is more inconsistency and opportunity for things to go wrong.

     
    The encryption is a really cool idea, but I think at this point it's impeding usage. Workshop should be easier to use than passing zip files around, and right now I think it's a little bit harder. In fact, the FPS Weapons pack needs to be delayed because it's pretty much impossible to deploy it reliably right now. I keep getting disappearing objects in the example map because file references are being lost due to the changing file paths.
     
    I've tested another method of handling files. Here's what I propose: When a Workshop package is downloaded, it gets extracted into a subfolder of a "Workshop" folder in each project. For example, if you have a project in "Documents\MyGame" and you subscribe to "Shadmar's post-effects pack", then a folder will be created at "Documents\MyGame\Workshop\Shadmar's post-effects pack" and all files are extracted there. Files will be updated automatically. Workshop files would no longer be "fake" files stored in encrypted zip files, they would just be regular old files the editor automatically extracts to your project folder. Keeping them neat and tidy in a "Workshop" folder in the project will prevent you from getting a mess of files all over your project.
     

     

     
    The downside is it loses the global identifier. Workshop dependencies would not be automatically subscribed to because maps would only store the regular old file path. My experience is more than one level of dependencies is a bad idea, so I think it's worth it just to have all the headaches go away.Workshop would be a more efficient way to distribute files to each other, instead of being an alternate virtual file system. The "fake" Workshop folder in the Asset Browser would go away, replaced by an actual folder in your project.
     
    Your existing Workshop items do not need to be changed. Of course, assets would be stored unencrypted on the user's hard drive. My view is that encryption is only good to the extent that it doesn't damage the system's usability, and right now I think it is causing problems.
     
    Encryption will still be supported in Workshop game deployment, and automatic encryption will be added to games published through the Publish dialog.
     
    This will not take place until after the Halloween game tournament finishes October 31.
  10. Josh
    I figured out why some Workshop items weren't installing correctly. There's a series of steps I need to go through to make a paid item ready for sale, and I omitted one button press in the Steamworks interface.
     
    If you experienced downloading problems with the nature model pack, zombies, or any of the scifi material packs, they should work now.
     
    Let me know if you still have any problems.
  11. Josh
    You've probably noticed a lot of new content and changes in the Workshop this week. Monday I plan to launch "paid items" in the Workshop. This is something I've wanted to do for several years, and it benefits everyone:
    More content will be available for you, ready to use with Leadwerks.
    I think content authors will make a lot more sales through Steam than they would through their own websites and even other stores. The top items will even get prime real estate and be shown right on the Leadwerks Game Engine store page where they will receive millions of views.
    It will hopefully smooth out my cash flows to make planning easier.

    Plus, it will give us a greater variety and quality of screenshots and games!
     
    Some of the content is also available on Arteria3D's website right now at a slightly lower price, which is totally fine with me because it gives us an indication of how well Workshop sales perform relative to web-based sales. From what I have seen in our DLC sales, this will do very well for everyone. Thanks to Arteria3D for their participation as the brave first seller. And thanks to the folks at Valve for their help and support in setting this up.
     
    These items will be available Monday in the Workshop interface in Leadwerks Editor, and through our website. Purchases will be made through Steam Wallet. You'll see, it's very easy to figure out. If you have any feedback on the items for sale, or if there are other kinds of content you want to see, just let me know!
  12. Josh
    After an extended period of testing, the Leadwerks Workshop on Steam is now available. I'm really happy about this because it fundamentally changes the way we work together. Content authors have more of a sense of "ownership" of their items, and it's easy for them to get feedback and update their subscribers. More features are always good, but for a long time I have had the feeling we needed to address other aspects of the game development process. I think the Leadwerks Workshop will harness the community's output in a way we haven't seen before and allow us all to benefit. I'm also looking forward to playing more mini-games on Steam with the Leadwerks game player.
     
    I'd like to thank everyone who contributed items for the launch, including:
    Aggror
    ChrisV
    Klepto2
    Pure3d.de
    Shadmar
    TJHeldna

     
    And thanks to Klepto2 for his help with some of the Steam API stuff.
     
    Congratulations to HaydenMango for publishing the first game on Steam through the Workshop.
     
    Also, thanks to Rich Digiovanni and his years of providing great artwork, much of which has made it into the Workshop.
     
    I'll follow up about the Steamworks initialization problem on Linux. I would have delayed this release so we can have the Workshop running on Linux, but there are external factors to consider (Steam summer sale).
  13. Josh
    The Workshop in Leadwerks Editor has been updated to use the same web interface as the game launcher. Page numbers have also been added to both. In the future, the Leadwerks Workshop interface will probably start to resemble the Game Launcher interface more.
     

  14. Josh
    Here's an example of something called "derivative works" which is something the Leadwerks Workshop on Steam allows us to do.
     
    Shadmar uploaded a model from Leadwerks 2 and added some special effects to it in the Workshop here:
    http://steamcommunity.com/sharedfiles/filedetails/?id=312811332

     
    I subscribed to the item, and used the model and sound to make my own Workshop item here:
    http://steamcommunity.com/sharedfiles/filedetails/?id=312846032

     
    When you load my item up in the editor, it will automatically subscribe to and pull the needed contents from Shadmar's original item. If he updates his item, the changes will automatically show up in mine.
  15. Josh
    It appears that items that were released within a certain time period, right when the Workshop was made public, received a lot of "spam" comments like below, from people who don't even own Leadwerks:
     

     
    I have nothing against TJHeldna's cola can, but I don't believe it is the top-rated item in the Workshop through genuine votes:
    http://steamcommunity.com/workshop/browse/?appid=251810&browsesort=toprated&section=readytouseitems&actualsort=toprated&p=1
     
    It's very obvious which items got spammed. They each have 30+ one-word comments. In order to fix this, the following items are going to be removed from the Workshop by banning, which is the only mechanism I have to do this:
    http://steamcommunity.com/sharedfiles/filedetails/?id=254432232&searchtext=
    http://steamcommunity.com/sharedfiles/filedetails/?id=281171208&searchtext=
    http://steamcommunity.com/sharedfiles/filedetails/?id=261126240&searchtext=
    http://steamcommunity.com/sharedfiles/filedetails/?id=304502026&searchtext=
     
    This does not mean I don't like your item, it just means your Workshop page got spammed and it messed up the ratings. I am downloading each item and will have it available for you if you wish to re-upload it.
  16. Josh
    Valve has delivered on their plan to add a new Steam browser protocol for paid Workshop items. The Leadwerks Game Engine beta branch on Steam has been updated so that Workshop Store purchases go through the Steam client instead of requiring you to log into a web browser. You must also opt into the Steam client beta for this functionality to work. At the moment, this feature is only available on Windows.
     

     
    This removes the biggest source of friction in the checkout process and makes the Workshop Store more convenient to use. I've also found the cause of and fixed some downloading problems that some users were experiencing earlier. Remember, all purchases are associated with your Steam account and can always be retrieved at a later time.
     
    The website has also been updated, although this also requires you to opt into the Steam beta update.
     
    This change was implemented by myself and Valve as a direct result of your feedback.
  17. Josh
    Over the recent months the Leadwerks Workshop Store has experienced a noticeable increase in sales, correlating to an increased number of products offered. Although Workshop Store sales are quite a bit lower than DLC sales, the Workshop Store is more scaleable because it allows third parties to submit a greater variety of products.
     
    We're also able to send out payments to Russia and other regions that other stores and websites may have trouble sending payments to, because our transaction system is built on Steam.
     

     
    I am meeting with Valve in October to make my recommendations on how we can maximize sales through this system for third-party authors. In the meantime, you can submit your items to the Workshop now:
    http://www.leadwerks.com/werkspace/page/tutorials/_/workshop-r11
  18. Josh
    The Workshop Store interface has been updated. These changes will go out to the in-editor store interface soon.
     

     
    Clicking on the "Buy" button now opens the item directly in the Steam client, so you no longer have to log into the Steam website. No credit card is needed if you already have one on file in your Steam account.
     

  19. Josh
    The Workshop interface is updated with new options to let you quickly find items to use in your games.
     

     
    When you buy an item, you will now be directed to the Steam purchase page in the editor interface itself, without having to sign into an external web browser.
     

  20. Josh
    I'm in DC this week helping the folks at NASA wrap up some projects. I'm going to move back to a supportive role and focus on development of Leadwerks 4.6 and the new engine, and I am helping them to hire some programmers to replace me. We found some very talented people who I am confident will do a fantastic job, and I can't wait to see what they create using Leadwerks Game Engine.
    I helped a team using Leadwerks at NASA get through some big milestones and expand. I hope that someday soon we will be able to tell the story of what happened, because it really has been an amazing experience with some really awesome people. I think it would make a nice movie.
    I will start working hard on Leadwerks 4.6 next Monday., and during March I will finish up my last projects so I can devote all my time to Leadwerks. I'm actually really looking forward to long days of doing nothing but engine coding. We're also going to hold a game tournament this Summer, with prizes. It was worth spending time to help NASA because we picked up a lot of new business customers and it helped focus development of the new engine in a direction everyone seems very happy about, but I need to get back to doing what I love best, which is building great software for you.
  21. Josh
    I've begun a Lua script for a Treeview widget. This is arguably one of the most complex widgets to implement, but after having done this in another language I have a design that I think is pretty simple. The script sorts all tree view nodes into a linear list-like table so that they can be drawn quickly. Like other widgets, the script will calculate where the starting point in the list is to display just the visible nodes. This is very important because it prevents the program from slowing down when the number of nodes gets really high and goes beyond the bounds of the scrollable area.
     

    Script.itemheight = 18 Script.itemindent = 20 function Script:Start() self.color = {} self.color.background = Vec4(0.2,0.2,0.2,1) self.color.foreground = Vec4(0.7,0.7,0.7,1) self.color.border = Vec4(0,0,0,1) end function Script:Draw() local gui = self.widget:GetGUI() local pos = self.widget:GetPosition(true) local sz = self.widget:GetSize(true) local scale = self.widget:GetGUI():GetScale() local style = self.widget:GetStyle() --Update table of visible nodes if self.visiblenodes==nil then self:UpdateNodes(self.widget) end --Draw background gui:SetColor(self.color.background.r,self.color.background.g,self.color.background.b,self.color.background.a) gui:DrawRect(pos.x,pos.y,sz.width,sz.height) --Draw nodes local n for n=1,#self.visiblenodes do gui:SetColor(self.color.foreground.r,self.color.foreground.g,self.color.foreground.b,self.color.foreground.a) gui:DrawText(self.visiblenodes[n].widget:GetText(),pos.x + 2*scale + self.visiblenodes[n].indent,pos.y + 2*scale + self.itemheight*(n-1),100,20) end --Draw border gui:SetColor(self.color.border.r,self.color.border.g,self.color.border.b,self.color.border.a) gui:DrawRect(pos.x,pos.y,sz.width,sz.height,1) end --Place nodes into a linear list function Script:UpdateNodes(node,indent) if indent==nil then indent=0 end if self.visiblenodes==nil then self.visiblenodes = {} end local n local count = node:CountChildren() local subnode local gui = self.widget:GetGUI() if node:Collapsed()==false then for n=0,count-1 do subnode = node:GetChild(n) self.visiblenodes[#self.visiblenodes+1] = {} self.visiblenodes[#self.visiblenodes].widget = subnode self.visiblenodes[#self.visiblenodes].indent = indent self:UpdateNodes(subnode,indent+self.itemindent) end end end
     
    The linear list also allows you to instantly calculate the node under a mouse coordinate, so you can figure out which node was clicked without iterating through hundreds of nodes. It's very similar to the design of the listview widget, but with the added complexity of a hierarchy that can be expanded and collapsed.
     

  22. Josh
    Last week I was researching the XBox and PS3 platforms. An XBox version of Leadwerks is technically feasible, and though the cost is considerable, it's not a barrier we can't cross. However, obtaining the development license from Microsoft will be much harder. Basically, they are unlikely to sell a development license until this engine has gained more users and had a couple of commercial games released. So we'll just keep improving and building momentum, with the eventual goal of expanding to the consoles. Even if you can afford the licensing fees for your own game, you're not going to get an XBox development license without having already published another successful game. So it seems we need to first focus on the PC, and then spread out when we are ready. There's still the MacOS version coming, and possibly a Linux one, if the demand is there. The editor and tools will work on all three operating systems with no code changes.
  23. Josh
    I've been getting good results storing documentation data in XML files. This allows me to make changes to the way documenation is displayed, without updating hundreds or thousands of pages. I can also write documentation without as much HTML markup. For example, bullets can automatically be inserted in line breaks for the syntax info. Javascript-based search engines usually require all page contents to be store in an array, so this gives us an easy way to collect that data.
     
    Since XML is a known standard, this makes it a bit easier to outsource the documentation content.
     
    Here is a sample file I am working with.

    <?xml version="1.0"?>
    <page>
    <title>SetPosition</title>
    <description>Sets the position of an entity in 3-dimensional space, using local or global coordinates.</description>
    <cppsyntax>
    void Entity::SetPosition(const float x, const float y, const float z, const bool global = false)
    void Entity::SetPosition(const Vec3& position, const bool global = false)
    </cppsyntax>
    <luasyntax>
    nil Entity:SetPosition(number x number y, number z, bool global = false)
    nil Entity:SetPosition(Vec3 position, bool global = false)
    </luasyntax>
    <parameters>
    x: X component of the specified position.
    y: Y component of the specified position.
    z: Z component of the specified position.
    position: the position to set.
    global: indicates whether the position should be set in global or local space.
    </parameters>
    <remarks>
    An entity can be positioned in local or global coordinates. Local coordinates are relative to the entity parent's space.
     
    If the entity does not have a parent, local and global coordinates are the same.
     
    <img src='img/552px-Space.png' />
     
    Leadwerks uses a left-handed coordinate system. This means that if you hold your left hand as shown below, your middle finger, index finger, and thumb will point in the directions of the X, Y, and Z axes, respectively.
    <img src='img/image2.jpg' />
    </remarks>
    <luaexample>
    --Create a window
    window = Window:Create()
    context = Context:Create(window)
    world = World:Create()
    local camera = Camera:Create()
    camera:SetRotation(35,0,0)
    camera:Move(0,0,-6)
    local light = DirectionalLight:Create()
    light:SetRotation(35,35,0)
    --Create a model
    model = Model:Box()
    while true do
    if window:Closed() or window:KeyHit(Key.Escape) then return false end
    model:SetPosition(Math:Sin(Time:GetCurrent()/10.0),0,0)
    Time:Update()
    world:Update()
    world:Render()
    context:Sync()
    end
    </luaexample>
    <cppexample>
    #include "Leadwerks.h"
    using namespace Leadwerks;
    int main(int argc, const char *argv[])
    {
    Leadwerks::Window* window = Window::Create();
    Context* context = Context::Create(window);
    World* world = World::Create();
    Camera* camera = Camera::Create();
    camera->SetRotation(35, 0, 0);
    camera->Move(0, 0, -4);
    Light* light = DirectionalLight::Create();
    light->SetRotation(35, 35, 0);
    //Create a model
    Model* model = Model::Box();
    while (true)
    {
    if (window->Closed() || window->KeyDown(Key::Escape)) return false;
    model->SetPosition(Math::Sin(Time::GetCurrent() / 10.0), 0, 0);
    Leadwerks::Time::Update();
    world->Update();
    world->Render();
    context->SetBlendMode(Blend::Alpha);
    context->DrawText(model->GetPosition().ToString(), 2, 2);
    context->Sync();
    }
    return 0;
    }
    </cppexample>
    </page>
     
    Even the table of contents can be store in XML, which provides a listing of all pages and a way to automatically create the search index and a list of all topics:

    <?xml version="1.0"?> <contents>
    <topics>
    <topic>
    <title>Tutorials</title>
    <openstate>true</openstate>
    <topics>
    <topic>
    <title>1. Editor</title>
    <openstate>true</openstate>
    <topics>
    <topic><title>1.1 Editor Interface</title><openstate>true</openstate></topic>
    <topic><title>1.2 Scene Panel</title></topic>
    <topic><title>1.3 Textures</title></topic>
    <topic><title>1.4 Materials</title></topic>
    <topic><title>1.5 Models</title></topic>
    <topic><title>1.6 Terrain</title></topic>
    </topics>
    </topic>
    <topic>
    <title>2. Games</title>
    <topics>
    <topic><title>2.1 Marble Platformer</title></topic>
    </topics>
    </topic>
    <topic>
    <title>3. Lua Programming</title>
    <topics>
    <topic><title>3.1 Introduction to Lua</title></topic>
    </topics>
    </topic>
    <topic>
    <title>4. C++ Programming</title>
    <topics>
    <topic><title>4.1 Introduction to C++</title></topic>
    </topics>
    </topic>
    </topics>
    </topic>
    <topic>
    <title>Script Reference</title>
    <topics>
    <topic><title>AI</title></topic>
    <topic><title>Analytics</title></topic>
    </topics>
    </topic>
    <topic>
    <title>API Reference</title>
    <topics>
    <topic>
    <title>Object</title>
    <openstate>true</openstate>
    <topics>
    <topic><title>Asset</title></topic>
    <topic><title>Analytics</title></topic>
    </topics>
    </topic>
    </topics>
    </topic>
    </topics>
    </contents>
  24. Josh
    How do you like that clickbait title?
     
    I implemented analytics into Leadwerks Editor using GameAnalytics.com last month, in order to answer questions I had about user activity. Here's what I have learned.
     
    The number of active users is what I was hoping for. A LOT of people ran Leadwerks in the last month, but people don't usually use it every day, as the number of daily users is lower. The numbers we have are good though.
     
    A lot of people use the Workshop to install models and other items for their projects. Unfortunately, paid Workshop items cannot be purchased right now, as I am working with Valve to change some company financial information. i will have this running again as soon as possible.
     
    Boxes are the most common primitive created, by a huge margin, followed by cylinders, wedges, spheres, and cones, in that order. Maybe the list of available primitives should be rearranged based on this? Not a big deal, but it's interesting to see.
     
    There's definitely a disconnect between user activity and the community, so in the future I hope to encourage people using the program to register forum accounts and become active in the community.
     
    Overall, I am glad that analytics have allowed me to get a broad picture of collective user behavior so I am no longer working blindly. It's a blunt instrument, but it will be interesting to see how I can use it in the future to improve the user experience.
  25. Josh
    Leadwerks Engine 4.5 will add ZIP files to the list of file formats you can import into the editor.  This isn't really anything special except that it works in a very specific way.  Source art files will be extracted first, followed by final game-ready formats (mdl and tex), followed by .meta files, which contain thumbnails and conversion settings for each file.  The resulting behavior is that you can import a zip file of game assets, with source art files, and the files will be copied in a way so that no reconversion of the files is triggered, because the time stamps are sequenced in the correct order.
    It's the little things. 
×
×
  • Create New...