Jump to content

Josh

Staff
  • Posts

    23,262
  • Joined

  • Last visited

Blog Entries posted by Josh

  1. Josh
    I'm writing this as we're a few dollars away from the mythic 30% target that has been claimed to be a "tipping point" past which Kickstarter campaigns reach critical mass. I'm not going to go into any detail about that because I don't want to jinx it, but so far I am blown away by the response. We put this up Sunday in advance of contacting bloggers, so nobody really knew about it the first day. It's Tuesday morning and we're presently at 29%.
     
    I've heard a number of people point out that putting Leadwerks on Linux would be the last tool they need to ditch Windows completely and move over to Linux. I myself am sort of platform-agnostic, and don't really get into the politics of different operating systems. However, the response we're getting with this campaign is making me realize something new.
     
    It's arguable that Microsoft has been a poor custodian of PC gaming. They haven't done much to support OpenGL, instead trying to push everyone into their own proprietary graphics API, DirectX. The problem with DirectX is it only runs on Windows and XBox, and it completely changes every few years, so developers have to rewrite all their rendering code. OpenGL has all the same functionality, it's stable, and it runs on everything (except XBox and Surface).
     
    The second problem with PC gaming on Windows is that Microsoft has a fundamental conflict of interest because they own a closed gaming platform, the XBox. Closed platforms are bad for developers because it can be expensive to push out game patches. The creator of Fez famously declared they would not be patching a known bug, because it would have cost an amount rumored to be around $40,000. It's bad for consumers because they don't get access to the same range of indie titles an open platform like Linux or the upcoming SteamBox can get. In addition, recent restrictions for the new XBox One have been announced that threaten the ability to lend games and may make the system "un-future-proof" (is there a real word for that?).
     
    Given these problems, it seems logical to us that PC gaming on Linux would grow quickly. Linux has faster OpenGL performance than Windows or Mac, and there's none of the "dueling APIs" issues and conflicts of interest Windows has. Thanks in part to Valve, the graphics drivers are now really solid. We have an optional distribution system through Steam. It's really got everything we need. So I am very optimistic about the future of PC gaming on Linux, and am really happy to be a part of this movement.
     
    The next step is for us to keep spreading the word and reaching out to publications so that we can make sure the target goal is met. Your help is appreciated. You guys are making quite a buzz on Twitter, Google+, and Facebook!
     
    To all our backers, thank you so much for sharing our vision for Linux gaming. I'm really excited to be working on this and glad I can deliver something the PC gaming community really needs right now.
  2. Josh
    Last week we launched our Steam Greenlight campaign to get Leadwerks into the hands of the Steam community. This week, we're rolling out the second stage of our plan with a Kickstarter campaign to bring Leadwerks to Linux. This will let you build and play games, without ever leaving Linux. The result of this campaign will be Leadwerks 3.1 with a high-end AAA renderer running on Linux, Mac, and Windows, with an estimated release date before Christmas.
     
    Valve has given Linux users a taste of PC gaming, so now it's up to us to reach the Linux community with our message. If you dig this, please help spread the word that someone is trying to put game development on Linux:
    http://www.kickstarter.com/projects/1937035674/leadwerks-build-linux-games-on-linux
     



     
    Leadwerks for Linux
    Linux is a solid and secure operating system that’s perfect for gaming, but at this time Windows remains the lead platform for PC games. We want to change that by putting the game development process right on Linux, with Leadwerks for Linux. This will allow you to build and play games without ever leaving the Linux operating system.
     
    Leadwerks is a visual tool for building any kind of 3D game, including dungeon crawlers, first-person shooters, and side-scrollers.. We want to put game development on Linux with Leadwerks for Linux. Our campaign has three goals:
     
    Linux Game Development. On Linux.
    It’s not enough just to export games to Linux. We want to put the game development process on Linux, so you can build and play games, without ever leaving the Linux operating system. We have a complete visual editor that handles all aspects of the game development process, and we’re porting it to run natively on Linux. We’re using GTK for the user interface, so our editor will look and feel like a native Linux application.
     
    We're targeting Ubuntu 12.04 to start with, and will support other distros as we make progress. You'll also be able to compile games for Windows and Mac...if you feel like sharing.
     

     
    Expand the Linux Library of Games
    Our second goal is to facilitate expansion of the Linux library of games, and encourage the production of Linux-exclusive titles. The Linux community is pretty intelligent, and they have a lot of good programmers. We think by putting the appropriate tools in their hands, it will enable them to make great Linux games.
     

    Hoodwink by E-One Studio
     
    AAA Graphics on Linux
    Leadwerks is known for having great graphics. We want to push Linux graphics beyond anything that’s ever been done. Linux is the perfect platform for triple-A graphics, because it has OpenGL performance faster than Windows or Mac. We’re taking advantage of this performance with deferred lighting, hardware tessellation, and up to 32x multisample antialiasing.
     

    The Zone by Dave Lee
     
    Steam Integration
    When Valve announced Steam was coming to Linux, that was a clear sign to us that Linux is ready for PC gaming. We’re working to integrate Leadwerks with Steam and take advantage of new features Steam offers for developers.
     

     
    Steam Workshop
    We’re hooking into the Steam Workshop to deliver game assets. This includes models, textures, scripts, and maps, so you can get everything you need to make games. When you find an object in the Steam Workshop you want to use in your game, just hit the “Subscribe” button and it will show up right away, ready to use in Leadwerks. We’re also adding support for Valve’s asset formats, so you can access lots of great content from the rest of the Steam Workshop, and add it to your game.
     
    Export for Steam
    We’re working with the Steam SDK to make it easier to submit Linux games to Greenlight. Just press a button, and your game files will be packaged up, ready to send to Steam.[/color]
     
    Features
    Leadwerks is a powerful yet easy to use game engine with thousands of users worldwide. Here are just a few of the main reasons we think Linux users will love Leadwerks.
     
    C++ Programming
    Programming with Leadwerks is a breeze. Underneath our visual editor lies a powerful yet easy to use programming API that can be accessed in C++, Lua, and other languages. With documentation and examples for every single command, you’ve got everything you need to make any kind of game.
     
    Visual Scripting
    For scripting, we use the Lua script language, just like in Crysis, World of Warcraft, and hundreds of other games. We’ve got a built-in script editor, so you don’t have to switch back and forth between Leadwerks and an external editor. It’s even got a built-in debugger so you can step through your script and see everything that’s going on in the game. The flowgraph editor is used to connect scripted objects and make gameplay happen. This lets map designers set up sequences of events and complex gameplay, with no programming required.
     
    Constructive Solid Geometry
    Finally, we use a level editor based on constructive solid geometry. This lets everyone make game levels, without having to be an expert. If you’re familiar with Valve’s Hammer Editor, you’ll feel right at home in Leadwerks.
     

    Combat Helo by Tricubic Studios
     
    We plan to deliver a visual editor that handles every aspect of the game development process, a powerful yet easy to use programming API, with triple-A graphics, all running natively in Linux. By working with Steam and the Linux community, our goal is to make Linux the number one platform for PC gaming. Thank you for helping us take Linux gaming to the next level.
     

    Big Five Game Hunter by Unidev
     
    Risks and challenges
    We expect to encounter some graphics driver bugs. This is always the case when you are pushing advanced graphics. Fortunately, we have good relationships with the major graphics hardware vendors, and have been able to get driver bugs fixed on other platforms in the past. Valve Software has done some of the heavy lifting for us here, by prompting the graphics hardware vendors to get their drivers in good shape.
     
    Our GUI has a GTK implementation for Linux, but we expect to encounter some problems that have to be overcome. Our GTK Scintilla implementation (for the code editor) has not been written, and it's a complex library.
     
    Since the Linux file system is case-sensitive, we expect to have to modify some code to work properly on Linux.
     
    We're implementing a new method for terrain layers using virtual texturing. We do not anticipate any problems here, but it is one of the few features we haven't fully prototyped.
     
    Although building Leadwerks for Linux will undoubtedly present some difficult problems, our team has a lot of experience with multi-platform development and I'm confident we can deal with all issues we encounter.
  3. Josh
    I first connected with Valve Software during GDC 2013. I recognized an opportunity to work together, so last week I paid a visit to Bellevue, Washington and met with Valve employees (no one has job titles in the company except Gabe) and discussed Leadwerks and the evolving Steam platform.
     
    Today, I'm excited to announce our Greenlight campaign for Leadwerks 3: Steam Edition.
     


     
    This software will be distributed through Steam and allow you to build games with Lua script and publish them to Windows and Mac through Steam. We think Steam users will love Leadwerks, for a few reasons.
     
    Constructive Solid Geometry
    First, we use a level editor based on constructive solid geometry. This lets everyone create game levels, without having to be an expert. If you're familiar with Valve's Hammer Editor, you'll feel right at home in Leadwerks. It's fun to make game levels, and anyone can do it.
     
    Write Games with Lua Script
    Second, we use Lua script, just like in Garry's Mod, World of Warcraft, Crysis, and hundreds of other games. We have a built-in script editor so you don't have to switch back and forth between Leadwerks and an external program. It's even got a built-in debugger so you can step through your script and see everything that's going on in the game.
     
    Visual Scripting
    Finally, we use a flowgraph editor to connect scripted objects and make gameplay happen. You can view the functions of scripted objects and just click and connect them. This lets map designers create sequences of events and complex gameplay, with no programming required.
     
    But it's not enough to just put Leadwerks on Steam. We want to fully integrate these technologies to deliver a complete game development platform, running within Steam.
     
    Steam Workshop Integration
    We're hooking into the Steam Workshop to deliver game assets. This includes models, textures, scripts, and maps, so you can get everything you need to make games. When you find an object in the Steam Workshop you want to use in your game, just hit the "Subscribe" button and it will show up right away, ready to use in Leadwerks.
     
    Support for Valve Asset Formats
    We're also addng support for Valve's asset formats so you can access lots of great content from the rest of the Steam Workshop and add it to your game.
     
    Export for Steam
    We're working with the Steam SDK to make it easier to submit your games to Greenlight. Just press a button and your game files will be packaged up ready to send to Steam.
     
    Our dream is to unite the entire Steam community into this big global game-producing factory, where everyone can do what they're best at. We need your help to make it happen. Please vote for us on Greenlight and show Valve the Steam community wants to build their own 3D games with Leadwerks.
     
    We'll do our best to make sure all current Leadwerks users can get Leadwerks 3: Steam Edition added to their Steam account for free. To help facilitate this, please add your Steam ID to your Werkspace profile.
     
    Vote for Leadwerks
    To vote for Leadwerks 3: Steam Edition on Greenlight, visit www.leadwerks.com/greenlight or find us in the Greenlight software section in Steam.
  4. Josh
    This update brings the addition of lightmapping across curved surfaces with smooth groups. The image below is a set of lightmapped CSG brushes, not mesh lighting. You can read a detailed account of our implementation of this feature here.
     

     
    The project manager now includes an "Update" button, so you can easily update your project any time we modify files in the template folders. Although we tested with no problems, it is recommended you back up your project before using this feature. The editor will make a copy of any overwritten files, as an added precaution.
     

     
    You've now got full control over all the features and settings in the Leadwerks editor, through the new Options dialog. This gives you control over various program behaviors and settings. You can toggle grid snapping, control the snap angle, and lots of other stuff.
     

     
    We have made one change to the script system. Our multiple script design worked reasonably well during the development of Darkness Awaits. The flowgraph interactions were clean, but when it came to AI and player interaction, things got messy. For example, when the player pushes a button we perform a raycast or proximity test to get the entity hit. Then we have to go through all the scripts attached to the entity, looking for a relevant script attached to it:

    --Check if GoblinAI component is present if entity.script.GoblinAI~=nil then
     
    --Call the TakeDamage() function
    entity.script.GoblinAI:TakeDamage(10)
     
    end
     
    That works okay in our example, but when we consider other enemies we want to add, suddenly it gets ugly. We have a few choices.
    Add an if statement for every new AI script, checking to see if it is present.
     
    Separate the health value out into its own script.
     
    Loop through all attached scripts looking for a TakeDamage() function.

     
    It should be obvious why option #1 is a bad idea. This would make our code highly interdependent. Encapsulation is one of our goals in game scripting, so we can achieve drag and drop functionality (or as close to that as is reasonably achievable without limiting ourselves).
     
    The second option would solve our immediate problem, but this approach means that every single script variable two scripts access has to be a separate script. The thought of this just shuts my creativity down. I already think it's tedious to have to attach an AI and AnimationManager script to an entity, and can't imagine working with even more pieces.
     
    The third option is the most reasonable, but it greatly impedes our coding freedom. It means every time two entities interact, you would have to do something like this:

    --Check if GoblinAI component is present if entity.components~=nil then
     
    for local k,v in entity.components do
     
    if type(v.TakeDamage)=="function" do
     
    --Call the TakeDamage() function
    v:TakeDamage(10)
    end
    end
    end
     
    If you actually wanted to return a value, you would just have to get the first value and exit the loop:

    local enemyhealth=0  
    --Check if components table is present
    if entity.components~=nil then
     
    --Iterate through all attached components
    for local k,v in entity.components do
     
    if type(v.GetHealth)=="function" do
     
    --Call the GetHealth() function
    enemyhealth = v:GetHealth()
    break
    end
    end
    end
     
    This is a major problem, because it means there is no firm "health" value for an entity. Sure, we could consider it a "HealthManager.health" value but therein lies the issue. Instead of having plug-and-play scripts everyone can share, we have to devise a system of expected script names and variables. This breaks compartmentalization, which is what we were going for in the first place. Both Chris and I realized this approach was fundamentally wrong.
     
    After careful consideration, and based on our experience working on Darkness Awaits, we have restructured the system to work as follows, with a 1:1 entity:script relationship:

    --Check if script is present if entity.script~=nil then
     
    if type(entity.script.TakeDamage)=="function" do
     
    --Call the TakeDamage() function
    entity.script.TakeDamage(10)
    end
    end
     
    You can set an entity's script with the new function:

    Entity::SetScript(const std::string& path)
     
    You can also set and get entity script values right from C++:

    virtual void SetString(const std::string& name, const std::string& s); virtual void SetObject(const std::string& name, Object* o); virtual void SetFloat(const std::string& name, const float f);
     
    And it's easy to call a script function from your C++ code:

    virtual bool CallFunction(const std::string& name, Object* extra=NULL);
     
    The properties dialog is changed slightly, with a consistent script tab that always stays visible. Here you can set the script, and properties will appear below, instead of being spread across a bunch of different tabs:

     
    Maps with entities using only one script (which has been almost everything we see) are unaffected. Objects with multiple scripts need to have their code combined into one, or split across multiple entities. I am very reluctant to make changes to the way our system works. Our API has been very stable since day one of release, and I know it's important for people to have a solid foundation to build on. However, I also knew we made a design mistake, and it was better to correct it sooner rather than later.
     
    Probably the best aspect of the script system in Leadwerks 3 has been the flowgraph connections between scripted objects. That's been a big winner:
     

     
    As we use the editor more and hear about the community's experience, it allows us to refine our tools more. One of the more subtle but we made is in the properties editor. One of the annoyances I experienced was when setting a property like mass or position when an entire hierarchy of entities was selected. Obviously I didn't want to set the mass for every single bone in a character, but how to tell the editor that? I went through all the properties, and for ones that the user is unlikely to want set, I made the following rule: If the entity has a selected parent anywhere in the hierarchy, it gets ignored when properties are retrieved and applied. (Other things like color will still work uniformily.) Just try it, and you'll see. It speeds up editing dramatically.
     
    In a similar vein, we finally solved the problem of "too many selection widgets", We only display the top-most control widget for each group of selected objects. Again, it's easier for you to just try it and see than for me to explain in detail. If we did our job right, you might not even notice because the editor will just do what you want without any thought.
     
    You've also got control over the color scheme, and can use it to customize the look and feel of the 3D viewports and code editor.
     

     
    On Windows we fixed an annoyance that triggered menu shortcuts when the user tried to copy and paste in text fields. This tended to happen in the properties editor. We're working to resolve the same issue in the Cocoa UI for Mac.
     
    I'm a big fan of the 3ds max Max Script system, so in the output panel we've added a real-time Lua console:

     
    You can type Lua commands in and interact with Leadwerks in real-time. Just for fun, try pasting in this line of code and see what happens:

    for i=0,10 do a = Model:Box(); a:SetColor(math.random(0,1),math.random(0,1),math.random(0,1)); a:SetPosition(i*2,0,0); end  
    You can't create objects the editor will recognize (yet), but it's fun to play with and should give you an idea of where we're going with the editor.
     
    This is an important update that includes new features and enhancements that improve usability and workflow. Thank you for your feedback. It's great to see all the activity that is taking place as people learn Leadwerks 3.
  5. Josh
    I'm a big fan of constructive solid geometry because it allows people without advanced modeling skills to design a game level that looks great. In fact, I originally got my start in game development using the Quake and Half-Life modding tools, making game maps.
     
    One of the criticisms of CSG has been that it only allowed creation of faceted objects. (Valve's Hammer Editor has a workaround for this that lets you set smooth groups, but you can't see the results until they are run in the game.) This was preventing me from making some game level features I wanted, like curved arches and rounded corners, so I decided to do something about it.
     
    Leadwerks supports smooth groups for CSG objects. To access the controls, switch to face editing mode and then select the objects tab in the right-hand sidepanel:

     
    It was fairly easy to calculate vertex normals from smooth group information. However, that information still has to be fed to the lightmapper or the lighting will appear faceted across a curved surface:

     
    To solve this, I needed to calculate the interpolated normal across the surface, and use that for the lighting equation for each luxel (lightmap pixel). Initially, I thought I could use a simple weighted average. Vertices near the luxel would have a high influence, and vertices further away would have less influence. However, it quickly became apparent this would not produce anything close to accurate results!

    Gouraud Shading
    The problem I was facing is actually a very common calculation that is done in real-time on the GPU. This was the first time I ever had to calculate it myself. It turns out the problem was first solved before I was born by a clever fellow by the last name of Gouraud, and thus we call it Gouraud Shading or Gouraud Interpolation. 
    The algorithm works like this: draw a straight line in any direction from the point you want to interpolate. It doesn't matter what angle, as long as it's one straight line. Now find the two triangle edges the line intersects. Each of those edges is connected to two vertices, each with a normal. Use a linear interpolation to weight those two normals, for each point. Finally, use the distance of both these points from your original position to weight their interpolated normals:

    More information on this technique can be found here.

    Implementation
    Getting this to work on a CSG lightmapper was difficult for two reasons. First, CSG objects consist of n-sided polygons, not triangles. Although they can be broken down into triangles, I was worried that visual artifacts might arise. Second, lightmaps have a user-defined bleed border, and the luxels of a lightmap extend beyond the edges of the polygon being lit. Gauroud shading requires the point being interpolated actually be inside the triangle. Our luxel positions could be inside any of the triangles that make up a polygon face, or they might not be on the face at all! 
    I decided to start by only worrying about the luxels that fell inside one or another triangles on the face, and solve the outliers later. Fortunately, the transform and math classes built into Leadwerks 3 made it fairly easy to convert all the points into flat 2D space to solve the problem. As expected, my first attempt identified the luxels that fit inside a particular triangle, but the luxels along the edges could not be processed, and appear dark:

     
    I added an error threshold for the triangle intersection routine, which got rid of the black borders, but turned out to be a bad idea. Some of my values were being interpolated in the wrong direction, as you can see in the following images:

     

     

     
    In this image, it's almost working, but the error threshold is causing luxels along the center seam to get lit incorrectly. Additionally, a few luxels in the top right are forming a dark border:

     
    The final piece of this puzzle was to deal with luxels that didn't fit into a particular triangle, This was a pretty puzzling problem, and for a while I thought there might not be a "correct" solution. However, if you think about it intuitively, a luxel that lies just outside a triangle should use the same lighting as a luxel just inside that triangle, right next to it.
     
    For the remaining unsolved luxels, I tested each of their distances to each triangle in the face they belong to. I found a nearest triangle to each, then found the nearest point on that triangle, and calculated the normal from that point's position.

    Results
    This technique produces beautiful smooth lightmapping on curved surfaces:
     
    The algorithm works with curves, arches, sphere, any CSG objects that use smooth groups. So now you can make those castles, arches, and towers you've always wanted to build:

     
    This feature will be available in the next update to Leadwerks 3.
  6. Josh
    About a week ago we sent a survey out to Leadwerks 3 customers to get their feedback and plan our next leg of development. According to the results, the number one most important issue Leadwerkers care about is tutorials.
     
    We've taken the following steps to build resources for Leadwerks user to learn from:
    The Leadwerks 3 tutorials database is available here. Anyone can submit a new article, but all articles must be approved by the staff before they appear visible. Without a process of approval, it's difficult to keep everything consistent and error-free.
    We added some new features to the tutorials template to make it easier to convey knowledge. First, we added a tabbed interface to display multiple code files. You can use this to display a lesson in C++ and Lua side-by-side, or you can use it to display multiple code files from a single project.
     
    We've also added some new BBCode tags, available only in the tutorials database, that allow you to display a chunk of code with both C++ and Lua syntax. The "tabber" BBCode tag starts a tabbed box. "tabitem={title}" will open a tabbed panel. Both these tags need to be closed like so:[tabber][tabitem="Item 1"]Panel 1 content.[/tabitem] [tabitem="Item 2"]Panel 2 content.[/tabitem] [tabitem="Item 3"]Panel 3 content.[/tabitem] [/tabber]
     
    The code above will yield this result:

     
    You can use this to explain what a chunk of code does, and a block of C++ and Lua code, covering both languages in a single lesson.

    Search tags are now available. The following built-in tags can be used: "C++", "Lua", and "Blender". We will add more tags as new content becomes available.

    Educating our community is a powerful thing. For our staff, we have all the knowledge of how Leadwerks works in very deep detail, but it can be difficult to communicate that knowledge in a structured way that makes sense. On the other hand there's the community, made up of people who are smart and eager to learn. Conveying the knowledge of how to use Leadwerks to our community is a powerful thing. Like Agent Smith creating clones of himself in the Matrix, we can create new experts and mini-experts just by showing the way.


     
    There's a gap that needs to be overcome. In some ways, this is as difficult as writing the actual code that powers Leadwerks. There's three levels of code examples we're providing right now.
    The first are the documentation examples. Just about every command has an example in both C++ and Lua that shows how to call that command. These are kept as simple as possible so it's easy to isolate how the command works.
     
    The second type is the game-ready code we write for examples. Darkness Awaits is an example written entirely in Lua, while our first-person player tutorial is using C++. These examples show real game code I would use in a commercial product, but they're harder to understand.
     
    Somewhere in the middle lies the "feature" examples. "Aggror" has posted a lot of tutorials like this for C++. These are more conceptual than the simple documentation examples, but are usually just one code file, and they don't go into a lot of heavy game structure so they're lightweight enough they could be used to demonstrate both C++ and Lua simultaneously.

    So now I would like to ask the community, what's working best for you? What kind of tutorials would you like to see more of in the future?
  7. Josh
    We've got a Leadwerks 3 update coming out this week, with miscellaneous fixes and some new features.
     
    The first are the addition of Import and Export buttons in the Project Manager. You can export an entire project to a zip file. You can import a project from either a Leadwerks project file (*.werk) or a zip file. This makes it easy to share projects and synchronize your work across different computers.

     
    The second new feature is projected shadows. These allow characters and other objects to cast dynamic shadows on the scene around them. They run fast, even on mobile devices, and add an extra degree of depth to your scene:

     
    You can expect these updates to become available later this week.
  8. Josh
    Shadows in 3D games are important. Not only do they look good, but they communicate information about the 3D geometry of the scene. Leadwerks pioneered dynamic deferred lighting, with one of the first deferred renderers in the world on PC. However, fully dynamic lighting requires some pretty beefy hardware, and the reality of today's situation in computing hardware has to be considered when we are designing a platform for other people build commercial products on.
     
    To support games that reach the widest audience possible, we launched Leadwerks 3 with a baseline renderer that runs across the board on all supported platforms. The engine has been designed in a modular fashion so we can add on a new high-end deferred renderer later on, and Leadwerks games will get an instant graphics upgrade with no code changes. I am looking forward to pushing graphics even further later on when I turn my attention to the OpenGL 3.2/4.0 renderer.
     

    Projected Shadows
    As for the baseline renderer, there are a few extra enhancements I'm finishing up that will make Leadwerks 3 games look good on a wide range of hardware. In my last blog I talked about light vector maps, which store normal mapping information in a second lightmap. We delivered the results to users last week, and are am working on projected shadows, a low-cost technique Source Engine uses to provide dynamic shadows on characters and other dynamic objects in the scene. 
    I started by just rendering an object and getting its rendered image to line up with the original object:
     

     
    The next step was to color the shadow black and use alpha blending, to make it look like...a shadow!:
     

     
    The hardest part of this process, which I am still working on, is the data management. It's easy to set up a simple one-time effect like this, but making it scalable so your games keep running fast takes much more work. We don't want to re-render shadows when they aren't visible on screen, and we only want to re-render them when the orientation of the shadow caster changes. We can't simply loop through all shadow-casting objects in the scene, because that approach will slow down when more objects are added. Instead we have to build the shadow system into the scene octree so that shadows only get updated when its absolutely needed.
     

    Post-processing Effects
    Thanks to our for GDC 2013, we found that post-processing effects on mobile are completely doable. Consequently, we're adding a few post-processing steps to finish out the baseline renderer before we move on to OpenGL 4. Bloom and HDR iris adjustment are the two that make the biggest impact on visual quality, and will be approached first. Refraction effects are easy to add, and this time we're going to make them easier for the end user to set up. The end goal is for the baseline renderer to be on par with Valve's Source Engine, and have it run on mobile. 
    We think these features will provide a striking visual impact on a wide range of hardware, and provide a good fallback for systems that don't support full deferred rendering. Next, we'll be moving on to terrain and a new deferred renderer based on OpenGL 3.2 / 4.0.
  9. Josh
    We're very busy this week, doing a lot of things that are out of the ordinary for us.
     
    Leadwerks Software will be at booth #938 at GDC 2013 in San Francisco March 27-29. Come by our booth if you're in the neighborhood, play with the full software, watch our demo reel, and get a look at the world's first...well, you'll have to come see it for yourself.
     
    If we get a chance, we'll stream some video from the event.
     
    Here's our staging area.

     
    Following the GDC, Chris will be focusing on a series of tutorials to take you through the steps of making a full game. I'll be fixing small bugs and implementing a few simple lighting features that will finish out the basic renderer:
    Normal maps for lightmapped surfaces.
    Dynamic lights on lightmapped surfaces (for flashlights and explosions).
    Projected shadows. (I had to implement render-to-texture on mobile for my lecture, so we're halfway there.)

  10. Josh
    The last few weeks have been interesting as we've been figuring out where Leadwerks 3 fits into the game development landscape.
     
    The good:
    The feedback from the Leadwerks 3 users has been more positive than anything I've ever seen. People love using it. All the care and attention to the tools has really paid off. The return of constructive solid geometry is a huge win.
    At the upgrade pricing, we're doing a lot of sales. Leadwerks 3 makes more in a week than Leadwerks 2 made in a month, at its best. (Our best sales are typically in the middle of the product life cycle, not the beginning.)
    Leadwerks 3 has a much wider appeal than anything we've ever made. We're no longer trapped in a small niche, but we still have the expandability to reclaim the crown of high-end graphics.

     
    The bad:
    Indie developers can't afford the full price we hoped to set. It doesn't matter what features we add to the product, there's a certain price threshold we can't cross without a multi-million dollar marketing budget.
    Although our documentation is excellent, people still need a full "how to make a game" series of tutorials. The "Darkness Awaits" example game isn't enough, without being put into a tutorial format.

     
    My original idea for Leadwerks 3 was to make a premium product, with a premium price. I was counting on revenue to come primarily from existing Leadwerks users, because it's easier to sell to an existing customer than to attain a new one. However, it's clear that Leadwerks 3 has mass appeal like nothing we've ever done, and a lot of potential for growth if we price it right. Indie developers are happy to buy Leadwerks 3 at an affordable price point. I think there are enough indie developers out there to support us, so we're making the final price $199/199/199 across the board for new customers. Our other market segment are pro game studios, and for them we can offer source code licenses (at a much higher price). Selling a binary license that's too expensive for indies and too cheap for studios is an awkward positioning, and I don't think it works.
     
    When we get back from the GDC, Chris is going to be taken off the core engine development and put exclusively on end user lessons. We are planning a series of weekly tutorials taking you through the steps to make a full first-person shooter game with Leadwerks 3. We chose this genre because we think the precision of the controls maximizes the potential for interactions, which is where Leadwerks 3 can really shine. I will be focused on core engine and editor fixes, and new features.
     
    Leadwerks 3 has a wide enough appeal that I think we can count on growth to fuel the company, not high prices. Leadwerks 3.1 will be the next stop. I know graphical enhancements are a high priority for a lot of people, as well as gameplay features and editor enhancements.
     
    It is an exciting time when the only limits you have are the size of your ideas and the degree of your dedication. We're already seeing some incredible stuff come from the community with Leadwerks 3.
  11. Josh
    That was one crazy weekend! Things were hectic at times, but we managed to process all orders and get people started with Leadwerks for Android. Well, everyone except YouGroove. I've got to do some tests on a clean install of Windows, so I will figure out exactly what JRE to install, since that part can be confusing.
     
    I uploaded new builds for Windows, Mac, and Android just now with performance improvements. Darkness Awaits is playable now on my Samsung Galaxy Tab 2, though I know I can still improve the performance. I will be focused primarily on performance optimization and fixing any showstopper bugs for the next two weeks. You can tell one problem right away, and it was only the limited performance of my low-end Android devices that demonstrated this...in Darkness Awaits, if the player stands still the FPS is fairly high, but when they start moving there is a visible drop. I believe there is some stupid mistake in the recursive bounding boxes invalidation that causes this to be slow. The good news is, now that I have identified where the inefficiency is, I can find and improve it rather easily.
     
    I also think we can lower our poly count quite a bit in that scene, with no visible loss of quality. Leadwerks can scale very well, so I don't worry about how big the map is or how many objects are offscreen. However, mobile devices have very real constraints on polygon counts, and the torch holders are pushing the polycount up unnecessarily.
  12. Josh
    Well, starting with leaving my iMac's power cord at home, this has been a chaotic day, but we're getting it under control. Leadwerks 3 is a much bigger step beyond Leadwerks 2. We're no longer confined strictly to the PC platform, we've now got a C++ code base that can be used in many ways, and our new tools are really nice to use, if I do say so myself. It's also nice to sort of reconnect with our origins in the CSG editing tools. The feedback on this has been very positive, and I think it was a good move including that.
     
    Our community was built up with hobbyists and indies on the PC platform. Leadwerks is growing up, but I wanted to make sure our long-time users can move forward with us. Therefore, I decided to give everyone an easy entry into the new game engine. The reduced price is good for Leadwerks 3 as a digital download and will be available to Leadwerks 2 users until April 30th, 2013.
     
    Thanks everyone for your feedback and participation in the whole design of Leadwerks 3. Today is the start of something really great.
  13. Josh
    The Leadwerks community project "Midnight Salsa" was one of my favorite things that came out of Leadwerks 2. Watching the videos of everyone collaborating across the globe was really interesting, and with Aggror's leadership they did pull off what they set out to do: Make a playable zombie FPS. However, there were some weak points that showed me where I could put effort and have it be the most useful.
     
    When you go through the first set of doors, a carefully placed light above the door shines to illuminate a sitting zombie as the doors open. I noticed right away the animation transitions weren't completely smooth. Although our animation system makes it very easy to transition between frames and do all sorts of interesting things, the logic that manages multiple animation sequences blending in and out can get a little messy. I approached this as a general problem and wrote an animation manager script in Lua that handles a "stack" of animations. When you set a new animation sequence, it is added to the top of the stack and blended in over a specified amount of time. Once it is completely blended in, all animations beneath it in the stack are removed. This process can handle any number of transitions smoothly, so you can just always set the latest one and there will never be more than two or three sequences active in the stack.
     
    The second problem that affects a lot of people is AI. How do you get characters to go where you want them to go? My advice in the past was to implement a system of connected nodes, as I did in my game "Metal". I finally solved this problem once and for all with a relatively recent technique called navmesh pathfinding. This provides more accurate pathfinding that isn't limited to node points, and it's completely dynamic. If the level changes, the pathfinding adjusts to it. This level of integration is only possible because Leadwerks 3 was built with pathfinding baked into the core, and it makes it very easy to use. Implementing this system was a huge investment of time and effort, and there was no guarantee it would have succeeded, so it probably wasn't conceivable to add this on top of Leadwerks 2. In retrospect, I really should have built node-based pathfinding into Leadwerks 2 so we could all have a common foundation for AI.
     
    In this video, the project leader mentions having to send the level model back to the artist for resizing. This causes a delay in progress while everyone waits for the new model. Our new CSG level design tools eliminate this problem because the map can be immediately adjusted right in the editor, without any waiting around or reimporting. Even if the artist wanted to take their time to make it perfect, a quick modification could be made to give the other team members something to test with. When combined with the built-in navmesh pathfinding, you can visualize the navigable areas as you build the level. There's never any guessing or going back to redo things because your enemies don't have room to get through a hallway or something.
     
    Finally, there is the matter of game object interaction. Sometimes you have special interactions in a map, and abstract classes aren't always the best way to manage that. In the past, gameplay mechanics like doors, switches, were exclusively the domain of expert programmers. Although Leadwerks 2 had a built-in messaging system, too much was left undefined. Consequently, even the programmers who were able to implement advanced interactions each isolated themselves from the community of developers, because they were branching the engine. Our new flowgraph system provides a shared framework we can all utilize and share code within. This means reusable scripts can be written that can be used in many games, by many developers, and our scripts can "talk" to each other through the flow graph. In the map below I've set up a collision trigger (shown in grey) and attached it to two doors (shown in green). When the player walks into the collision trigger the doors open. This simple example shows how anybody can set up advanced game interactions in their map.

     
    Our primary focus for Leadwerks 3 is delivering gameplay. I think all of these features will facilitate collaboration and give the community some much needed high-level frameworks. Not only does it make building games faster, it gives us all a common framework to work together within.
  14. Josh
    A couple weeks ago I replaced the Object::SetHook() function with an Object::AddHook() function. The difference is subtle but significant. SetHook() supported a single hook function but AddHook() supports multiple hook functions for each hook ID, that will be called in sequence.

    Syntax
    AddHook(const int& hookid, void* hook)


    Example
    #include "App.h" using namespace Leadwerks; App::App() : window(NULL), context(NULL), world(NULL), camera(NULL) {} App::~App() { delete world; delete window; } void Hook1(Entity* entity) { System::Print("Hook 1"); } void Hook2(Entity* entity) { System::Print("Hook 2"); } void Hook3(Entity* entity) { System::Print("Hook 3"); } bool App::Start() { window = Window::Create(); context = Context::Create(window); world = World::Create(); camera = Camera::Create(); DirectionalLight::Create()->SetRotation(35,45,0); //Create a model model = Model::Box(); model->SetPosition(0,0,3); //Add some hooks model->AddHook(Entity::UpdateMatrixHook,Hook1); model->AddHook(Entity::DrawHook,Hook2); model->AddHook(Entity::DrawEachHook,Hook3); //Remove one hook model->RemoveHook(Entity::DrawEachHook,Hook3); return true; } bool App::Continue() { if (window->Closed() || window->KeyDown(Key::Escape)) return false; //Make the model spin model->Turn(0,Time::GetSpeed()*1.0,0); Time::Update(); world->Update(); world->Render(); context->Sync(); return true; }
     
    Inside the engine, this just uses a multimap, which has some very complicated syntax that I could not type from memory:

    //Call hooks std::pair <std::multimap<int,void*>::iterator, std::multimap<int,void*>::iterator> ret; ret = (*entity)->hooks.equal_range(Entity::UpdateWorldHook); for (std::multimap<int,void*>::iterator it=ret.first; it!=ret.second; ++it) { void (*hook)(Entity*) = (void (*)(Entity*))(it->second); hook(*entity); }

    So What's the Big Deal?
    It's important for the API to be future-compatible. It's okay for new commands to be added, but once the first release is out I really want the API to always act as described in the documentation. We wouldn't be bothering to produce a printed manual otherwise. 
    This design was adopted so that in the future it can be used for plugins. A plugin would add its own hooks onto objects. If we used SetHook(), it implies there is only a single hook allowed. We want the user to be able to add their own hooks without overriding any plugins they may be using. This also allows multiple plugins to add and remove their own hooks without interfering with one another.
     
    It's too early to worry much about a plugin system. The best thing to do right now is build a really focused tool that fulfills the function it's designed for. However, by anticipating plans for future expansion we can design things now so that we don't have to go back and change them later.
  15. Josh
    I've spent the last few days writing simple examples for every single command in Leadwerks 3. Not only does this make the documentation more friendly, it also acts as a final test to make sure all the commands work the way they say they should. I make the C++ example and then Chris converts it to Lua (and tells me what I did wrong!).
     
    I didn't realize it at first, but this really showcases the strength of API design of Leadwerks. Since you get full control over the execution and flow of a Leadwerks program, it's easy to learn from simple examples that demonstrate one idea. Below are a few examples for different commands in the API.
     
    Get the device accellerometer reading:

    #include "App.h" using namespace Leadwerks; Window* window = NULL; Context* context = NULL; bool App::Start() { window = Window::Create(); context = Context::Create(window); return true; } bool App::Continue() { if (window->Closed() || window->KeyDown(Key::Escape)) return false; Draw::SetColor(0,0,0); context->Clear(); //Display the device information on the screen Draw::SetBlendMode(Blend::Alpha); Draw::SetColor(1,1,1); Draw::Text("Orientation: "+String(Device::GetOrientation()),2,2); Draw::Text("Acceleration: "+Device::GetAcceleration().ToString(),2,22); Draw::SetBlendMode(Blend::Solid); context->Sync(); return true; }
     
    Create a physics shape from a model and use it on a scaled entity :

    #include "App.h" using namespace Leadwerks; Window* window = NULL; Context* context = NULL; World* world = NULL; Camera* camera = NULL; bool App::Start() { window = Window::Create(); context = Context::Create(window); world = World::Create(); camera = Camera::Create(); camera->SetRotation(35,0,0); camera->Move(0,0,-10); Light* light = DirectionalLight::Create(); light->SetRotation(35,35,0); //Create the ground Model* ground = Model::Box(10,1,10); ground->SetPosition(0,-0.5,0); ground->SetColor(0,1,0); //Create a shape Shape* shape = Shape::Box(0,0,0, 0,0,0, 10,1,10); ground->SetShape(shape); shape->Release(); //Load a model Model* model = Model::Load("Models/teapot.mdl"); model->SetPosition(0,0,0); model->SetColor(0,0,1); model->SetScale(4,4,4); //Create a shape shape = Shape::PolyMesh(model->GetSurface(0)); model->SetShape(shape); model->SetPosition(0,0,0); shape->Release(); //Create some objects to fall model = Model::Sphere(); shape = Shape::Sphere(); model->SetShape(shape); shape->Release(); model->SetMass(1); model->SetColor(Math::Rnd(0,1),Math::Rnd(0,1),Math::Rnd(0,1)); model->SetPosition(Math::Rnd(-1,1),Math::Rnd(3,6),Math::Rnd(-1,1)); for (int i=0; i<10; i++) { model = (Model*)model->Instance(); model->SetCollisionType(Collision::Prop); model->SetColor(Math::Rnd(0,1),Math::Rnd(0,1),Math::Rnd(0,1)); model->SetPosition(Math::Rnd(-1,1),5+i*2,Math::Rnd(-1,1)); } return true; } bool App::Continue() { if (window->Closed() || window->KeyDown(Key::Escape)) return false; Time::Update(); world->Update(); world->Render(); context->Sync(); return true; }
     
    Or in Lua, if you prefer:

    function App:Start()  
    self.window=Window:Create(self.title,0,0,1136+6,640+32,Window.Titlebar+Window.Center+8)
    self.context=Context:Create(self.window,0)
    self.world=World:Create()
    camera = Camera:Create()
    camera:SetRotation(35,0,0)
    camera:Move(0,0,-10)
    light = DirectionalLight:Create()
    light:SetRotation(35,35,0)
     
    --Create the ground
    ground = Model:Box(10,1,10)
    ground:SetPosition(0,-.05,0)
    ground:SetColor(0,1,0)
     
    --Create a shape
    shape = Shape:Box(0,0,0, 0,0,0, 10,1,10)
    ground:SetShape(shape)
    shape:Release()
     
    --Load a model
    model = Model:Load("Models/teapot.mdl")
    model:SetPosition(0,0,0)
    model:SetColor(0,0,1)
    model:SetScale(4,4,4)
     
    --Create a shape
    shape = Shape:PolyMesh((model:GetSurface(0)))
    model:SetShape(shape)
    model:SetPosition(0,0,0)
    shape:Release()
     
    --Create some objects to fall
    model = Model:Sphere()
    shape = Shape:Sphere()
    model:SetShape(shape)
    shape:Release()
    model:SetMass(1)
    model:SetColor(Math:Rnd(0,1),Math:Rnd(0,1))
    model:SetPosition(Math:Rnd(-1,1),Math:Rnd(3,6),Math:Rnd(-1,1),true)
     
    for i=0, 9 do
    model = tolua.cast(model:Instance(),"Model")
    model:SetCollisionType(Collision.Prop)
    model:SetColor(Math:Rnd(0,1),Math:Rnd(0,1),Math:Rnd(0,1))
    model:SetPosition(Math:Rnd(-1,1),5+i*2,Math:Rnd(-1,1),true)
    end
    return true
    end
     
    function App:Continue()
     
    if self.window:Closed() or self.window:KeyHit(Key.Escape) then return false end
     
    Time:Update()
    self.world:Update()
    self.world:Render()
    self.context:Sync()
     
    return true
    end
     
    Create a texture from scratch:

    #include "App.h" using namespace Leadwerks; Window* window = NULL; Context* context = NULL; World* world = NULL; Texture* texture = NULL; bool App::Start() { window = Window::Create(); context = Context::Create(window); //Create a texture texture = Texture::Create(256,256); //Set the texture pixel data char* pixels = (char*)malloc(texture->GetMipmapSize(0)); char r,g,b; for (int x=0; x<256; x++) { for (int y=0; y<256; y++) { int p = (x*texture->GetWidth() + y)*4; memcpy(&r,pixels + p + 0, 1); memcpy(&g,pixels + p + 1, 1); memcpy(&b,pixels + p + 2, 1); if (x<128) { if (y<128) { r=0; g=0; b=255; } else { r=255; g=0; b=0; } } else { if (y<128) { r=255; g=0; b=0; } else { r=0; g=0; b=255; } } memcpy(pixels + p + 0, &r, 1); memcpy(pixels + p + 1, &g, 1); memcpy(pixels + p + 2, &b, 1); } } texture->SetPixels(pixels); return true; } bool App::Continue() { if (window->Closed() || window->KeyDown(Key::Escape)) return false; Draw::SetColor(0,0,0); context->Clear(); //Display the texture on screen Draw::SetColor(1,1,1); Draw::Image(texture,0,0); context->Sync(); return true; }
  16. Josh
    I got the editor documentation written pretty quickly. It was hard to start, but once I figured out how I wanted to lay out the information, it all started flowing pretty easily.
     
    Documentation in Leadwerks Engine 2 was a weakness, especially in stuff other than the programming reference. This is unfortunate, because I have come to see documentation as the final product. Everything in the development cycle leads up to the ability to write good documentation.
     
    Good documentation starts with good program design. It would have been difficult to give the same attention to detail in Leadwerks Engine 2 as I am now, because there was much more behavior that was undefined, or left up to the user. Because Leadwerks 3 absorbs a lot of that complexity, I can definitively say "if you want to do X, press this button". It makes for documentation that is nice to read, and kind of fun to write.
     
    Here's a screenshot, just to give you an idea of the formatting and style I am using.

     
    I usually feel overwhelmed by the documentation when I look at game engines. It's hard to know where to start, and I just feel like I am picking up random bits of disorganized information. I am hoping the manner in which I have organized our docs will provide a streamlined learning experience, with the ability to drill down to more detail when needed. My organization is as follows:
     
    Editor
    This covers the entire Leadwerks workflow and art pipeline. You can find answers to all non-programming questions here.
     
    Script Reference
    This section describes all the object scripts included with Leadwerks, and how to use them to make game interaction.
     
    Programming
    This section discusses general information about programming with Leadwerks, in C++ and Lua.
     
    Command Reference
    This section provides detailed descriptions and examples for the entire Leadwerks API.
     
    Index
    This is a list of all pages in the documentation, in alphabetical order.
     
    It feels very easy to navigate and it doesn't take long to learn how the entire workflow and art pipeline work, but it's not lightweight by any means. The docs have more than 600 pages! Most of that is for individual class functions, which is information you will usually specifically seek out, rather than just reading through them all for fun.
     
    --EDIT--
    I added some additional fields for C++ and Lua examples, with a tabbed interface to view each:

  17. Josh
    Development of Leadwerks 3 was (theoretically) completed today. We still have a lot of testing and bug hunting to do, but all features for release are written.
     
    This is where it started:
    http://www.leadwerks.com/werkspace/blog/1/entry-500-day-1/
  18. Josh
    In this blog I'm going to explain the evolution of the entity and physics system in Leadwerks 3.
     
    In Leadwerks Engine 2, physics bodies and character controllers are both separate entity classes. If you want a model to be physically interactive, you parent it to a body entity. If you want a model to walk around with physics, you parent it to a character controller body.
     
    In Leadwerks 3 I decided to give physics properties to all entities. This means all entities can use commands like GetVelocity(), AddForce(), SetMass(), etc. However, since character controllers are quite different, and they involve kind of a big chunk of code, I decided to keep the character controller as a separate entity. To make an enemy or NPC, you would create a character controller entity and then parent an animated model to that entity.
     
    This was simple enough to do in the editor, but it started getting weird when we added scripts. Scripts for animation would need to be added to the child model, because the character controller would not return any animation lengths or the number of sequences. Scripts to control movement, on the other hand, would have to be attached to the parent character controller, for obvious reasons.
     
    Next I tried creating a character controller script that attached to the model itself. This eliminated the extra entity in the hierarchy, and would automatically create a character controller when loaded in the engine, and parent the model to it. I didn't like that this was changing the hierarchy from what the user saw in the editor, and script accessing the character controller would still be based on some wonky assumptions.
     
    Finally, I decided to just give the entity class a physicsmode member. This can be one of two values. By default, it is Entity::RigidBodyPhysics. However, you can set it to Entity::CharacterPhysics and the entity itself will act as a character controller! All the character controller functions are now available in the entity class, so you can just load a model, adjust some settings, and send him on his merry way around town:

    Model* enemy = Model::Load("Models/Characters/barbarian.mdl"); enemy->SetMass(10); enemy->SetPhysicsMode(Entity::CharacterPhysics); enemy->GoToPoint(20,0,0);//model will walk to this position, using AI navigation
     
    Pretty cool, eh? (If you wanted to add animation, you'd just go it like below.)

    enemy->SetHook(Entity::DrawHook,UpdateEnemyAnimation) void UpdateEnemyAnimation(Entity* entity) { entity->SetAnimationFrame(Time::GetCurrent()/100.0); }
  19. Josh
    Today I added the visible guides in the editor for point and spot lights. I also tested out the new FBX converter, recompiled with the 2012 FBX SDK. It works. (There are no file format changes in the 2013 FBX SDK, so this will load everything.) Our character models still have to be rescaled, so I added a resize option in the model editor. That way models can be resized and the model file saved, so you don't have to rescale a model every single time you place it in the editor. Having models I obtained from a third party who had never used Leadwerks gave me models that required slight fixing, but I didn't mind because it was a chance to test the art pipeline and improve the import process.
     
    The command reference is just about finished up. Chris just needs to add a few missing pages. I still have to write most of the editor documentation.
     
    Literally, the only thing left to program is the undo system. I expect there are still a few bugs to fix, but there's no new features that have to be implemented.
     
    We are meeting with a packaging manufacturer tomorrow...
  20. Josh
    I spent the day manually setting entry categories in the new documentation database. This was needed to make the docs actually use the nice breadcrumb bar in the website header. Our content management system doesn't exactly support hierarchical pages, so some clever PHP scripting was used to make it work. The whole point is simply to make navigation easier, and it works well. I also wrote some PHP code that does a search and replace with class names, so class names are always links to the page for that class.
     
    Here's the list of classes and commands at this point, weighing in at just under 500 pages. There are some small errors and a couple missing commands, but it's mostly there:
    commands.txt
     
    Have a happy new year, and drive safely!
  21. Josh
    Here's something I've been thinking about. What do you think?
     
    Apple
    Locking down OSX.
    No optical drive. The Mac software shelf at Fry's is now obsolete.
    Mac App Store.
    Gatekeeper only allows "signed" applications, by default.
    [*]Miniaturization of computer hardware, at the cost of graphical performance.
    [*]Move to non-upgradable hardware (glued-in memory).
    [*]Moving away from file system access (iCloud).
    [*]Hardware is expensive, and will always be a luxury item.


     
    Windows
    The people who made Windows 2000 and XP have retired. Microsoft does not appear to possess the same talents it once had.
    Artificial upgrade requirements for DirectX are impeding development (tessellation works fine on Windows XP with OpenGL).
    Attempting to lock down Windows like iOS.
    Intel attempting to absorb entire PC (socketless CPUs).
    Moving away from file system access.
    MS failures tend to encourage them, so I expect the trend to continue:
    Office ribbon sucked, so they added it to everything.
    Zune interface sucked, so they used it for everything.



     
    Ubuntu
    Valve and THQ coming to Ubuntu.
    Less fragmented than Windows.
    One UI (GTK).
    vs. MFC, WPF, .NET, and Modern UI.
    [*]GUI applications can be developed with one language (C++) instead of C#/Objective-C.
    [*]One environment.

    vs. Legacy/Modern division.
    [*]One version (12.10).

    vs. XP, Vista, 7, 8, and Blue.


    [*]Competition between Linux distros.

    If Ubuntu really pisses developers off, they can easily switch to a competing one like Mint.
    Can never be "locked down".
    [*]Fastest performance.
    [*]Still sucks, but getting better while Windows and Mac get worse.


     
    Maybe in five years, computing will look like this:
    Office workers will use Windows.
    Gamers wil use Linux.
    The general population will use a cheap tablet for Email and web browsing.

     
    What do you think?
  22. Josh
    I hope everyone is having an awesome Christmas week. I'm taking a break from coding to show you our new office we moved into in November at the Sacramento Hacker Lab.
     
    All decked out for Christmas:

     
    Chris is pretending to work, but he's not fooling me:

     
    So we changed the arrangement to make a reverse mullet. (Party in the front, business in the back):

     
    The kitchen provides energy, both in the form of food and alcohol:

     
    The common area:

     
    The room-temperature beer flows freely:

     
    A closeup of our lovely tree, topped with the stuffed figurine Intel gave us (they're one of the sponsors here):

     
    To celebrate, here is an eggnog-induced off-the-cuff Christmas poem:
     
    Twas the night before Christmas,
    And all through the forum,
    Not a creature was stirring,
    (But Lumooja was snoring.)
     
    The coders were nustled all snug in their beds,
    While visions of Leadwerks 3 danced in their heads,
    And Aggror in his T-Shirt, and Roland in Sweden,
    Had just settled down their brains after solving a rather difficult programming problem.
     
    (Add your additional verses in the comments below.)
     
    MERRY CHRISTMAS!!!
×
×
  • Create New...