Jump to content

Refocusing on the PC



blog-0970343001396381999.jpgBack when Leadwerks 2 was first launched, it was just a BlitzMax programming SDK, intended to be a modern replacement for Blitz3D. It turned out Blitz users generally did not want it, and instead the audience it attracted was C++ programmers who like graphics. A visual editor was introduced and it was made as good as possible for a product that started with the intention of just being a programming SDK.


Leadwerks 3.0 was launched with a strong emphasis on the tools that Leadwerks 2 lacked, and mobile. It was pretty clear that the main target was mobile. Once again though, the intended audience and the audience that came to me were two different things. There's still a lot of C++ programmers on Windows, but the appeal has broadened to include a lot of modders, artists, and beginners who want an easy to use editor, and of course Linux users. My favorite aspect of Leadwerks 3 is that it serves both advanced programmers and total beginners, with no compromises in the design. (Big win!)

Leadwerks for Mobile

My mobile offering, on the other hand, has not done well. There are two problems:


I estimate that mobile has accounted for around 80% of the time I spent debugging things in Leadwerks 3.0, yet it accounts for less than 10% of revenue. (It wasn't 80% of the problems, but because the whole process of developing on mobile is painfully slow, it takes more time to do simple things.) Sending an application from the computer to a device can take several minutes, the debuggers are slow, and the whole process is much less transparent than PC development. It's not terribly challenging in an intellectual sense, but it eats a lot of time. For example, it took about two weeks to implement our terrain system, but it took an extra week after that just to get it working on iOS and Android. That week could have been spent adding a different feature, but instead I was messing around with various tablets just trying to make them work.


The other problem is that there's a big disparity between mobile and PC graphics. I saw a huge upswing in interest when I started showing shots of the OpenGL 4.0 renderer. Although we have moved beyond just being a graphics engine, and I know the renderer is a big part of the appeal of Leadwerks. On mobile, the hardware is comparatively limited, so it's much harder for me to do anything that makes Leadwerks mobile stand out.


If I could just hire one engineer dedicated to mobile support, the first problem would be solved, because it wouldn't cut into my time. However, mobile has accounted for less than 10% of revenue in the last year. I didn't even break even on my development costs. PC sales have been consistently strong, but mobile doesn't even make enough to pay for its own maintenance. So what's been happening is the PC side of the business is subsidizing the mobile side.


I expect the second problem will be solved within a couple of years. Nvidia's Tegra 4 chips can supposedly run regular OpenGL 4 (not ES). When those become the norm, it could give us total convergence of graphics between the PC and mobile. At that point, I might actually have a mobile product that stands out and provides something different.

Leadwerks Tomorrow

Now, as I am shipping the Kickstarter rewards and about to launch 3.1 proper, I have to think about where I want Leadwerks to be in 6 months, and in 12 months. There are three main areas I want to move forward in:


Leadwerks Editor

  • Adding new tools to make life easier.
  • Refining the workflow to eliminate any remaining"sticky" points.
  • Bug fixes, to make it a super slick and polished experience.


The Engine

  • New features in graphics, physics, networking, etc.
  • Performance optimization.
  • Improved compatibility across all OpenGL 4 hardware.


Third-Party Technologies

  • Blender, SteamOS, Steam Workshop, virtual reality, etc.


Leadwerks on the PC is in a very good position today. Virtually every computer being sold today will run Leadwerks. We came into desktop Linux at just the right time, and I am very optimistic about that space. SteamOS is opening up the living room for the first time to us lowly indies. Think about where we are now, and where this community can be a year from now...there's a ton of opportunity for all of us, but I need to focus on where we're winning. If I continue to subsidize our mobile efforts, it's going to slow down development and result in a buggier product with fewer features. So I think it's pretty clear mobile should be discontinued as of version 3.1, in favor of a stronger PC-centric product.


It sucks because I lost a lot of money on mobile, and the people most willing to take a chance on a new venture also lost out. But at the same time, if I had just stayed still on Windows and continued along the Leadwerks 2 path, none of the great things we have going for us now would have happened. It may make sense to pick mobile up again, when the hardware can provide enough power, and when there is more interest from the community. So far the response has been pretty much what I expected; a handful of (understandably) disappointed people, but most of our community was never really into mobile, and the new growth is coming from other parts of the PC ecosystem, not mobile.


Support for the OUYA was added rather thoughtlessly as a stretch goal for the Kickstarter campaign. Given the OUYA's failure, it should obviously be scrapped and replaced with SteamOS support. Since Android was a part of that, I am giving Kickstarter backers the ability to opt out of the campaign instead of receiving the final rewards. Kickstarter was an overall good experience, but I probably won't ever do another one, unless the project is really well-defined and doesn't have a lot of unknown parts.


Desktop Linux, VR, and SteamOS are on the upswing, and all of these play to the strengths of Leadwerks. If 2013 was the year of finding our place, I think 2014 is going to be a year of reaching out to the gaming world and making some really astonishing developments.


Recommended Comments

Thanks for this blog post Josh.


Looking forward to the improvements and new features that are coming.

Share this comment

Link to comment

A quite insightful post. I wonder if this was largely due in part to the fact that Leadwerks was Greenlit which the user base primarily consist of PC users.


Discontinuing mobile sounds like it's ultimately good news. You have momentum in a particular direction and now it's all about feeding that momentum.


If you can dominate the PC indie game dev market segment it will then be easy to bleed into other market segments, when it could become profitable to support mobile.


Impressive stuff Josh!

Share this comment

Link to comment

Thank you for the linux version.

I am one of disappointed for dropping mobile. Well at least i am glad that I was able to help funding linux version. Unfortunately for my current project long term support and Mobile is a must(will help differentiate my product to the rest) and I will go back to unity and give them (unfortunately a lot of)money

Other than this I wish all the best to Leadwerks and hopefully next year linux will not be dropped due to smaller market share in gaming(~2% accordingly to steam).

Share this comment

Link to comment

Thanks for this post!

I have a big interest for mobile (Android only), and would pay as much of the price of the PC version, but at the same time I understand your point developing mobile would need more staff and your current sales result does not show this as profitable.


Would version 3.0 (Android) would still be available? I just want to use it to do some little demos with it and experiment with the Android platform. And using the same "workflow" would simplify the thing. Also the mesh format for 3.0 to 3.1 should not have changed that much.

Share this comment

Link to comment

If you want 3.0 for Android, I can make that available in some way, but I would not count on it for long-term support. I don't particularly want to sell it, but if I make it free then people who bought it will not be happy. So let me think about that.


I don't see Linux or SteamOS as having this problem because they pretty much work the same as Windows and Mac, so it's not hard to keep those going, and I don't really have to worry about cost/benefit like I do with mobile. Mobile development is just sooooooooo incredibly slow. Provisioning profiles, having to kill the adb.exe task, waiting for Eclipse to perform a five-minute build, waiting for devices to start up...


I am one of disappointed for dropping mobile.
I'm sorry. That sucks. I hate to let anyone down like that.

Share this comment

Link to comment

I presume everyone is interested in developing for Android and/or iOS. But why pay 99$ extra if you at first only need the base SDK anyways (to get started with developing).


I did buy the Android extra and only tried it once with Darkness Awaits to see that it lacks performance (haven't tried it with my latest device though). Also, why not just supply an APK or publish Darkness Awaits to Google Play? People want to see what it can do before buying 99$ extra.


Despite above, I understand your decision. :)

Share this comment

Link to comment

I'm disappointed about mobile but I understand, have tried the Android version and was hoping for updates.


As ever I will continue to support, just don't get rid of Lua rolleyes.gif

Share this comment

Link to comment

Honestly, if you would have done a Kickstarter for mobile back when making 3.0 I think your stance would be different today because you would have had the money up front from supporters, or it would have shown the demand wasn't there if it really wasn't there. Either way, it would have been a better experience today for everyone.


This does show the importance on us developers side to create frameworks for our game logic that is a layer above the engine we use so we can reuse our logic code between engines because there is a void of a 1 stop game engine that doesn't cost thousands of dollars or charge royalties or is complicated as all hell.

Share this comment

Link to comment

"This does show the importance on us developers side to create frameworks for our game logic that is a layer above the engine we use"


I did this very thing with RogSys, which is partly the reason why I have the engine almost fully integrated after only a month. There's still specific things to do and lots of bug testing still, but the bulk of the work is done. A layer of separation between the engine and the game code is never a bad thing--it allows you to be flexible.


As for Josh's stance--beyond the fact this is his baby and he can raise it as he see's fit, we all known the gaming industry is constantly in a state of flux. Not long ago the PC was "dead" (as it's been many times before), and is now on the rise again. You have to be prepared to move with the trends if you want to keep going and growing :)


Add to this the other reasons he mentioned and it's not hard to see why he's making the choices he is....

Share this comment

Link to comment

I would add my voice to Christian Clavet's in expressing interest in retained access to 3.0 for mobile (assuming it works as advertised). Porting PC code to an older and unsupported version of Leadwerks has still got to be better than porting it to a completely different engine, at least to get something started. (I was one of the people foolishly deciding to wait for 3.1 and the Kickstarter to complete before buying mobile support... oops.)

Share this comment

Link to comment

As a PRO backer myself, it would be nice if Mobile was simply parked, not discontinued.


In the interim, access to V3.0 for mobile would help to satisfy my curiosity.


Likewise, the suggestion from Ywa of publishing Darkness Awaits to Google Play (or just on our board here) would allow others to understand its performance.


Overall, I have no doubt that you are trying to make the decisions possible moving forward and leveraging depreciated assets on non-active development platforms seems fairly straight forward.

Share this comment

Link to comment

Nothing is absolute. If Linux users respond well after we launch the Linux version on the Ubuntu Software Center and Steam, then we can build up the number of users there, and Android development on Linux would be an obvious niche to go after.

Share this comment

Link to comment

Have you considered using or integrating another framework like GamePlay3D to bring mobile back? (i am not a programer so i clearly dont know what i am talking about)

Share this comment

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Blog Entries

    • By Josh in Josh's Dev Blog 4
      I made some changes to the design of the particle system. I am less concerned with the exact behavior of particles as they move around and move interested right now in building a system with good performance and deep physics interactions. Although I want particle behavior to be customizable, I don't think scripts are the right tool for the job. C++ plugins are better suited for this for two reasons.
      C++ is much faster, and particles are a system that will make heavy use of that. Lua scripts can't be run on separate threads. In Leadwerks Engine 4 we have basic particle collisions, but I wanted something more interactive in the new system. I move the particle update code into the physics thread. I implemented collision as well as the ability for particles to exert forces on other objects. Here's what happens when some slow-moving smoke particles interact with a scene: The lower platform rotates freely while the upper platform is motorized.
      When the particle velocity is increase they start to behave like a stream of water:
      Best of all, the speed is surprisingly fast. 4000 particles with collision update in just 2 milliseconds. The code scales well across cores so if you have a lot of CPU cores simulations with 100,000 particles are possible.
      Right now particles are processed in the physics thread, and get sent to the rendering thread for display, but right now the main thread actually never sees the individual particles.
      This is fast enough I think particles will default to full physics. Instead of just being a dumb visual effect we are going to have fully interactive fluids and gases. Flamethrowers can fill a room with fire and it will creep around corners to fill a space.
    • By Josh in Josh's Dev Blog 7
      For finer control over what 2D elements appear on what camera, I have implemented a system of "Sprite Layers". Here's how it works:
      A sprite layer is created in a world. Sprites are created in a layer. Layers are attached to a camera (in the same world). The reason the sprite layer is linked to the world is because the render tweening operates on a per-world basis, and it works with the sprite system just like the entity system. In fact, the rendering thread uses the same RenderNode class for both.
      I have basic GUI functionality working now. A GUI can be created directly on a window and use the OS drawing commands, or it can be created on a sprite layer and rendered with 3D graphics. The first method is how I plan to make the new editor user interface, while the second is quite flexible. The most common usage will be to create a sprite layer, attach it to the main camera, and add a GUI to appear in-game. However, you can just as easily attach a sprite layer to a camera that has a texture render target, and make the GUI appear in-game on a panel in 3D. Because of these different usages, you must manually insert events like mouse movements into the GUI in order for it to process them:
      while true do local event = GetEvent() if event.id == EVENT_NONE then break end if event.id == EVENT_MOUSE_DOWN or event.id == EVENT_MOUSE_MOVE or event.id == EVENT_MOUSE_UP or event.id == EVENT_KEY_DOWN or event.id == EVENT_KEY_UP then gui:ProcessEvent(event) end end You could also input your own events from the mouse position to create interactive surfaces, like in games like DOOM and Soma. Or you can render the GUI to a texture and interact with it by feeding in input from VR controllers.

      Because the new 2D drawing system uses persistent objects instead of drawing commands the code to display elements has changed quite a lot. Here is my current button script. I implemented a system of abstract GUI "rectangles" the script can create and modify. If the GUI is attached to a sprite layer these get translated into sprites, and if it is attached directly to a window they get translated into system drawing commands. Note that the AddTextRect doesn't even allow you to access the widget text directly because the widget text is stored in a wstring, which supports Unicode characters but is not supported by Lua.
      --Default values widget.pushed=false widget.hovered=false widget.textindent=4 widget.checkboxsize=14 widget.checkboxindent=5 widget.radius=3 widget.textcolor = Vec4(1,1,1,1) widget.bordercolor = Vec4(0,0,0,0) widget.hoverbordercolor = Vec4(51/255,151/255,1) widget.backgroundcolor = Vec4(0.2,0.2,0.2,1) function widget:MouseEnter(x,y) self.hovered = true self:Redraw() end function widget:MouseLeave(x,y) self.hovered = false self:Redraw() end function widget:MouseDown(button,x,y) if button == MOUSE_LEFT then self.pushed=true self:Redraw() end end function widget:MouseUp(button,x,y) if button == MOUSE_LEFT then self.pushed = false if self.hovered then EmitEvent(EVENT_WIDGET_ACTION,self) end self:Redraw() end end function widget:OK() EmitEvent(EVENT_WIDGET_ACTION,self) end function widget:KeyDown(keycode) if keycode == KEY_ENTER then EmitEvent(EVENT_WIDGET_ACTION,self) self:Redraw() end end function widget:Start() --Background self:AddRect(self.position, self.size, self.backgroundcolor, false, self.radius) --Border if self.hovered == true then self:AddRect(self.position, self.size, self.hoverbordercolor, true, self.radius) else self:AddRect(self.position, self.size, self.bordercolor, true, self.radius) end --Text if self.pushed == true then self:AddTextRect(self.position + iVec2(1,1), self.size, self.textcolor, TEXT_CENTER + TEXT_MIDDLE) else self:AddTextRect(self.position, self.size, self.textcolor, TEXT_CENTER + TEXT_MIDDLE) end end function widget:Draw() --Update position and size self.primitives[1].position = self.position self.primitives[1].size = self.size self.primitives[2].position = self.position self.primitives[2].size = self.size self.primitives[3].size = self.size --Update the border color based on the current hover state if self.hovered == true then self.primitives[2].color = self.hoverbordercolor else self.primitives[2].color = self.bordercolor end --Offset the text when button is pressed if self.pushed == true then self.primitives[3].position = self.position + iVec2(1,1) else self.primitives[3].position = self.position end end This is arguably harder to use than the Leadwerks 4 system, but it gives you advanced capabilities and better performance that the previous design did not allow.
    • By Josh in Josh's Dev Blog 3
      I wanted to work on something a bit different, and this sure is different. I've got a framework of a new particle system worked out. What's really special about this system is the amount of interactivity the particles will allow.
      Particle-world collisions. Particle-particle collisions (repulsion) Particle-particle cohesion (fluids with surface tension) Instead of just being a visual effect, I want our new particles to be fully interactive with physics so that particles can exert forces on objects. This will allow you to simulate fluids, smoke, and other effects in a realistic manner, not just dumb collision of particles bounding off walls. It should even be possible to simulate hydrophobic and hydrophillic liquids if you mix two together with different cohesion values.
      Basically what I want is something like Nvidia Flow on the CPU and exerting forces on the world. So if you had water falling on a water wheel the wheel would move because of the forces, or a blast of wind could knock objects over without any special force fields or other fake effects.
      I also have a technique worked out that will allow lighting of clouds and other masses of gas, with back-scattering.
      Emitters can be instanced so if you have one really high-quality torch effect, for example, you can instance it and use it as much as you like without any additional computational cost per instance.
      Particle emitters can be controlled with a Lua script or C++ actor. Two new functions are available, UpdateParticle() and EmitParticle(). Here is a script that controls particle behavior over time:
      entity.particleVelocity = Vec3(0,0,1) entity.particleAcceleration = Vec3(0,-1,0) entity.inverseSquareFalloff = true entity.particleRadiusBegin = 0.1 entity.particleRadiusEnd = 0.2 entity.particleColorBegin = Vec4(1,1,1,1) entity.particleColorEnd = Vec4(1,1,1,0) entity.particleMass = 1 entity.particleSpin = 5 function entity:Start() self.particleColorBeginHSL = HSL(self.particleColorBegin.rgb) self.particleColorEndHSL = HSL(self.particleColorEnd.rgb) local emitter = Emitter(self) if emitter == nil then return end local n for n = 1, #emitter.particles do emitter.particles[n].mass = self.particleMass emitter.particles[n].falloff = (n-1) / (#emitter.particles - 1) end end function entity:EmitParticle(index) local emitter = Emitter(self) if emitter == nil then return end emitter.particles[index].position = self:GetPosition(true) emitter.particles[index].velocity = TransformVector(self.particleVelocity,self,nil) emitter.particles[index].radius = self.particleRadiusBegin emitter.particles[index].color = self.particleColorBegin end function entity:UpdateParticle(index) local emitter = Emitter(self) if emitter == nil then return end emitter.particles[index].velocity = emitter.particles[index].velocity + self.particleAcceleration / 60 local falloff = emitter.particles[index].falloff if self.inverseSquareFalloff then falloff = falloff * falloff end emitter.particles[index].color.rgb = RGB(self.particleColorBeginHSL * (1 - falloff) + self.particleColorEndHSL * falloff) emitter.particles[index].color.a = self.particleColorBegin.a * (1 - falloff) + self.particleColorEnd.a * falloff emitter.particles[index].radius = self.particleRadiusBegin * (1 - falloff) + self.particleRadiusEnd * falloff emitter.particles[index].rotation = emitter.particles[index].rotation + self.particleSpin / 60 end A different script could be used to make particles emit from vertices of a model, to make the model appear to be on fire, or other effects. This will allow infinite customization to create any behavior you want.
      Particle physics will be calculated on the physics thread so I expect them to be very fast.
  • Create New...