Showing posts with label clojure. Show all posts
Showing posts with label clojure. Show all posts

Friday, 18 January 2013

Sweden, Ho!

I moved again! Now living in Uppsala, working in Stockholm. The past few months have been pretty exciting and we just moved to a new flat, but things are settling down. I've had a little time to poke at my personal projects, although I'd always like more.

My recent obsession has been with managing state. For many things, I seem to be tending towards a pipeline approach:

(defn foo [state x y z]
  (let [{:keys [a b c]} state]
    (assoc state 
           :a (bar x a)
           :b (baz b z y)
           :c (inc c))))

(defn quux [state]
   (-> state
       (foo "x" [] 0)
       (foo "y" [:r :s] 42)))

(defn outer-loop [state] (recur (quux state))

And so on and so forth. Passing state around explicitly as maps, writing functions that take the current state as their first argument and return that state modified with assoc, dissoc, assoc-in, update-in, merge etc.

Honestly, I'm not sure that this approach is the best way to do what I want. I have spent a little time looking at Clojure's state monad, but I suspect this is overkill (and despite being simple in practice, the whys and wherefores of all monads ever continue to befuddle me). The piped-stateblob approach translates nicely into ClojureScript with WebGL too; this is another thing I have been investigating of late.

Other advantages include very quick inspection or serialisation of a system's state (pprint to the rescue), and a single obvious point to recurse around in a thread's main loop. The stateblobs can also be useful carriers for communicating between threads.

On the other hand there's nothing particularly elegant or nice about carrying around the entire world with you wherever you go. And it works well enough that I'm starting to feel it is my hammer with which to treat every problem as a nail.

Using stateblobs everwhere: an ugly turn-based for prototype graphical RL #734.

Wednesday, 14 March 2012

Clojure-flavoured Rendering Framework: State

My rendering framework, such as it is, sits on clojars.org and does... not very much. That should change. I can't guess how useful it'd be to anyone else, but it could certainly be a lot more friendly.

With that in mind, I started taking a critical look at a few emergent antipatterns in the very core of the framework: the OpenGL wrapper.

This example, I am happy with. Mostly.

Last time, I mentioned how the rendering functions have state very explicitly threaded through them in the form of an argument. A bunch of my wrapper functions do very simple things to mutate GL state. Some of them reset it afterwards, or wrap those that don't in a friendly way. For example, matrix stuff is done something like this:

(ogl/with-matrix
  (ogl/translate 1 0 0)
  (ogl/scale 5.0)
  (ogl/triangles
    (ogl/vertex 0 0 0)
    (ogl/vertex 1 0 0)
    (ogl/vertex 1 1 0)))


Hopefully that's fairly obvious to someone familiar with OpenGL. The with-matrix wraps a glPush/PopMatrix pair of calls around all the expresions within it. Likewise triangles calls glBegin/glEnd with the appropriate primitive type. I debated not including this ancient method of drawing stuff, but it's so handy for debugging and quick tests... anyway, the point is that even though translate and scale mutate some OpenGL state, they're intended to be used within this kind of protected block. Maybe they should all have exclaimation marks, I'm a little bit hazy of when it's polite to start exclaiming when you're not mutating your arguments.

Obviously the triangles call and all the stuff therein is side effecting like crazy, but I'm not sure how much value attaches to trying to make those calls look different. If anyone has an opinion on the aesthetics of such things, please yell.

A lot of the rendering stuff behaves similarly to with-matrix. I have equivalent calls to wrap GL attribute fiddling, wireframe rendering (mostly debug friendliness), capturing the results of rendering expressions to render targets, assigning vertex buffers, and binding shaders. Some of these are could do with a refactor to make them more consistent, but they generally behave.


But then there's this...

So that's all well and good. Then I came across the with-matrix-mode macro.

Ick.

This one looks so similar to the with-matrix example, but instead of pushing and popping from the current matrix stack to allow safe manipulation of a transformation, it changes which matrix stack is currently active. OpenGL has a few of these, but the only ones that are really relevant are your "world" transform (GL_MODELVIEW) and your view/projection transform (GL_PROJECTION). The former moves vertices around, the latter manipulates your notional camera, as it were.

The reason this makes me twitch is that this doesn't in any way revert the changes you make within it. For example, here's a little function that sets up an orthographic view in place of the conventional camera-like perspective view:

(defn orthographic
  "Loads an orthographic projection matrix to the top
of the projection matrix stack."
  ([left right bottom top near far]
     (with-matrix-mode :projection
       (GL11/glLoadIdentity)
       (GL11/glOrtho left right bottom top near far)))
  ([left right bottom top]
     (orthographic left right bottom top -1.0 1.0)))


Sure, at the end of the function the matrix mode has been restored to whatever it was at the start, but there's no attempt made to preserve the state of the projection matrix. That's rather the point, in fact - it gets murdered and replaced. Everything after this will be rendered using the orthographic projection.

I suppose this function is named in a misleading fashion. Anyone assuming the state of the GL will be unchanged after executing it will be disappointed, whereas elsewhere I'm trying to leave things as I found them. On the other hand, changing matrix mode is rather rare compared to rendering stuff, you generally do it once to set up your camera and then leave it. This kind of mutate-and-forget approach makes it relatively easy to split up the rest of your rendering into small chunks, as long as you keep things in the correct order.

Elsewhere similar compromises might sensibly be made with the excuse of efficiency; there's no sense constantly setting and then resetting a bit of state if the next expression simply sets it again, or worse, if it sets it back to the same value. All told, I probably just want to find a consistent way to signal that some functions do not behave with respect to render state, whilst the default remains that all functions clean up their toys after playing with them.

Thursday, 2 February 2012

Unpretty

It wasn't pretty, but Leiningen is now generating a large .jar containing almost everything required to run a chunk of stuff excised from my "random clojure braindump" folder. So now I can in theory show my tiny vestigal 3D roguelike/turn-based Dungeon Master/hex-based Legend of Grimrock clone to people! People that don't have Clojure installed!




So, yay for progress! It's not pretty yet, but that's... mostly a case of sorting out my miniature asset pipeline: exporting from Blender in a slightly richer format than .obj, generating tangent and bitangent vertex data, normal and displacement maps, and associating this all together with diffuse and specular info. Some gruntwork to finish recreating the deferred rendering setup in clojure. Mostly simple stuff, although there is a lot of it.


Enough of that, random question time:

How do people approach cross-project hacking at a small scale? In this case, I just grabbed my nascent main file, vector math and rendering files, and a bunch of utility stuff and copied it into an empty project directory, but I would really like to bounce the data back and forth between hacking at random ideas and this (theoretically) slightly more stable project...

I suppose nested Mercurial repositories would be one approach, split all the 'engine' crap into a subfolder with its own repo and use that to keep everything in sync. Anyone have any experience with this approach? I guess using the magical .hgignore file to elide the 'engine' stuff from the main project repo would work in theory.

Wednesday, 1 February 2012

Success With Leiningen, Kinda

Getting Leiningen working was a bit of a trial:
  1. Download lein.bat!
  2. Note that it can self-install, but only if wget or curl are to hand. I'm currently trying to get it working under windows, my primary gaming and dev environment, so I go with the manual download option. Progress seems good.
  3. Putting the .jar file in the place where lein is installed (and on the path) doesn't work. Harrumph a bit.
  4. Mess with batch file a bit, including directing Leiningen at Clojure.
  5. Give up, download a windows implementation of curl, add to path.
  6. >lein self-install now works! Hooray! And oooh, the .jar file goes in \self-install. Durr.
  7. Leiningen crashes on attempting to do anything, with a huge Java call stack. Pout.
  8. Notice that in my arrogance and delusion, I have pointed Leiningen at Clojure 1.3.0, the newly installed latest version, but the original wanted to use 1.2.1. Download the older version, alter batch file again.
  9. Yay, I can make a project!
  10. I'll want to use lwjgl at the very least with this at some point. Some research points me at swannodette's lovely native-deps addition to the tool, and the existence of lwjgl-clj at clojars.org. Cool.
  11. OK, I have a zip file for native-deps. How do I thrust this in lein's general direction?
  12. Welp, via adding it to :dev-dependencies in my project.clj file, it seems. I guess I'll keep the .zip file in case of emergencies. Or something.
  13. Argh, version 1.0.0 just blows up lein again.
  14. Phew, 1.0.5 works. I can now grab lwjgl-clj through the magic of... magic, I guess. And curl possibly.
  15. Look at it go, downloading all those lwjgl-clj files!
  16. I've got a little text-based thing that'd make a nicely self-contained test project for leiningen. Let's try turning it into a self-executable .jar
  17. >lein jar: and there was much grinding and gnashing of gears.
  18. Class "hexed" was not found.
  19. Oh, :gen-class! Silly me.
  20. Class "hexed" was not found.
  21. Err... oh, -main.
  22. Class "hexed" was not found.
  23. wat.


And there were some more steps, mostly consisting of my own stupidity fighting with my own stubbornness, before finally:
>lein uberjar
>java -jar hexrl-1.0.0-SNAPSHOT-standalone.jar
SUCCESS!




Woohoo!

Now, I list my failures mostly because I am quite stupid, and I hope other people feel better about themselves as a result. But also because there's a fair amount of assumed knowledge concerning most JVM languages and their associated tools. Before I started working with Scala, I had only the most vague inklings regarding the black magic of .class and .jar files. Ant, maven and all related stuff is... well, initially I was curious and tried to learn more. Now I'm just hoping most of it dies and gets replaced by something. Anything. As long as it doesn't involve XML.

I still find it vaguely offensive that I'm expected to this.like.project.my.structure, preferably including URLs (hah), but in moderation it works well enough. Knowing that you need to generate an appropriate class exposing the correct form of a main method is reasonable. It would be nice if some of these things failed more gracefully in case of version mismatch

Long story short, now I have achieved a critical point: using a cuddly-ish tool to build a working application, however trivial. Chances are therefore good that I will learn to use Leiningen correctly (somewhat) and frequently.

Edit: I promised pretty screenshots, and have not yet delivered. The next step is apply the power of the ant-agonistic build tool to the OpenGL-using framework, check everything works with the version of lwjgl available at clojars.org, and then see what happens. Hopefully there will be relatively few explosions and couple of simple meshes to screenshot.

Thursday, 26 January 2012

Oh, that performance thing...

Sooo, via this fascinating post and confirmed by my own dirty timing efforts, there's another excellent reason to not define structures that naively implement clojure.lang.IFn.

That being, it's really rather slow.

Using an AABB tree-node I've been messing with, extracting a single argument from a node defined with defrecord 106 times takes roughly:

TimeForm
15 ms(:key node)
135 ms(node :key) (that is, implementing IFn using get)
85 ms(let [{:keys [key]} node] ...)

Fascinating stuff. But that's definitely a large enough improvment that I'll be stripping out the implementation of invoke, and be more aggressive promoting ad-hoc maps to records in future! It's hard to say no to an order of magnitude improvement.

Edit: I don't mean that clojure.lang.IFn is necessarily slow, just that it seems the (:key record) form is faster than (get record :key). I'm assuming this is due to directly mapping the former to member access, whilst the latter has to use some combination of additional reflection and the hash map implementation to get the value.

Wednesday, 25 January 2012

A Year Of Clojure

Bloody hell, more than a year evaporated.

What happened in that time? Mostly, a lot of Clojure, at least with respect to home stuff. It finally clicked something like nine months ago, in that I suddenly felt much happier writing in this language than pretty much any other. It was also marked by the crushing realisation that I didn't really know how to elegantly structure a program the size of the game I was making, in the new-ish language I was making it in. I still don't having restarted in a new and exciting language, but starting from scratch means the pressure has been relieved. Temporarily.

I've dithered with the old Scala project a bit, but to be honest it has too many ugly bits and not enough game to be worth salvaging. I'll likely rip out the tech that worked and give it a whirl in the new language du jour; the deferred rendering was fun, if simple, and the transparency hack surprisingly effective.

2011 apparently having been the year of Clojure and non-blogging, figured I'd start the renewed attempt at updates with a few notes and statements concerning the language.


Records don't behave like functions of keys, unlike maps which they otherwise resemble.

I can see why this is the case, sorta. I'm sure you don't want records to implement too many interfaces by default. But I like to be able to get the value of a key using both (map :key) and (:key map) syntax, in addition to (get map :key) etc. It's also useful to be able to pass a record/map to higher order functions at times.

To enable the above, you just need to make your record type implement clojure.lang.IFn and a trivial invoke method:
(defrecord record-thing [id biscuit]
  clojure.lang.IFn
  (invoke [this k]
    (get this k)))

Now instances of record-thing will support both (:biscuit a-record-thing) and (a-record-thing :biscuit) syntax. Easy.


Handles, handles for everyone!

This is more of a general functional thing. Any language which encourages the use of immutable data structures obviously invalidates a common method by which objects refer to each other, namely by holding a pointer or reference to the other object(s). Take for example a simple case where a monster wants to keep a short list of relevant enemies, for use as input state to some AI functions. Our monster is stupidly simple, and simply stupid:
(def fred-the-goblin
  {:type :goblin
   :health 10
   :position [0 0]
   :targets []})
What goes in the :targets list? Clearly it can't be equally simple representations of target entities. They'd have to be updated as the world evolves, and may refer to Fred in their own target lists and thereby create recursive doom. In clojure, we could use atoms or refs everywhere, but that's hideous and rather belies our intent to be pure. What I've been tending to do is stick an :id field on everything, using this as a convenient handle for any object that should be uniquely identifiable (within a collection of similar objects at any rate, I make no attempt at global uniqueness. Quite possibly this will redound to my detriment).

Of course, in order to actually get at the entity referred to by the handle, we really want some nice associative structure.
(defn auto-map [entities] (into {} (map vector (map :id entities) entities)))
This seems like the most reasonable approach. So far it feels like spatial organisation structures, turn ordering, other such ways of organising the set of active entities seem more naturally expressed as collections of smaller chunks of relevant data with an ID attached.

I'm still not convinced this is the best approach though. It seems somewhat brittle. How does a more determinedly pure language handle things?


I don't read enough documentation

I had a semi-rant here about the lack of a promise-delivered? function, equivalent to future-done?... but whilst writing it, I discovered that this function exists. It's just called realized? (and it also works for futures, delays, and lazy sequences). I can't believe I missed this for so long, and it will help simplify some code that currently combines the two.


Promises are nice

Continuing the above: don't get me wrong, I love futures. They're handy little things. But there's a great reason to use promises for games: controlling the thread upon which you do work. One very common case when dealing with things around the level of OpenGL 2.0/DX9 is rendering resource creation, which generally takes place on the rendering thread. In my case, I have a queue of pending jobs on the rendering thread in the form of promise/closure pairs. Each frame, the rendering thread pops a number of these jobs off the queue, executes the closures and delivers the result to the associated promise. Other threads can block or skip executing code that depends on those GPU resources/tasks, as they choose.


Dealing with the (lack of) speed

No real getting around it: Clojure is pretty slow. Not agonisingly slow, but if you're used to decently optimised C++ it can be striking. Now, many things act against this, not least the fact that it's so very joyful to write in the language (In my opinion, YMMV etc). Concurrency is orders of magnitude more tractable. Concision, dynamic typing and a functional style frequently makes iteration on algorithmic optimisations much easier than it would be for a huge lump of C++. Transient collections speed up some common operations without sacrificing referential transparency, and so on.

But.

Still slow. Especially when writing somewhat idiomatic, pure code, which is what I want to be doing.

Thankfully GPUs are fast, and much as with the Scala project my aim is to use relatively few draw calls per frame and make each as expensive as possible to get the results I want. State from the CPU should be small and cuddly. This just leaves physics, AI, sound, IO and general game logic to be worried about when it comes to performance. For a turn based game the remaining problems are greatly reduced in potential for menace, but I'm sure I'll have fun with them when I do something real-time and action-y.


Vectors as vectors

I've lost track of the number of little linear algebra libraries I've written and used. For my Clojure experiments, I wrote yet another, but kept it deliberately stupid.

I have minimal requirements from such a library. In fact after reducing my initial bulletpoints a bit, I have but one: Be like HLSL/GLSL.

That means adding a scalar to a vector is legal. Multiplying two vectors together, also legal (it does this componentwise, dot and cross products are handled as separate ops). Preferably, don't do the GLSL thing and conflate transforming a vector using a matrix with your vector-vector and vector-scalar multiplications.

These are very much not based around sensible mathematics, but instead represent the kind of things you actually do with vector quantities on a regular basis.

Oh, and I like having decent quaternion support, because they're approximately infinitely nicer than trying to keep rotation matrices/Euler angles sane. Swizzling is optional, as it doesn't come up that often in practice.

The end result is that I use Clojure's vector collection type for all vector-like objects. I has nice literal syntax in the form [x y z] and supports unpacking directly: (let [[x y z] v] ...). Components are not named members of a structure. All the basic operations are based around a version of map which accepts a mixture of scalars and collections in all positions.


Because this needs more attention, however negligible the increment may be

A discussion of the concept of "wat" in software.

It's just a few things that Ruby and JavaScript do which... may be surprising. I'm sure there are more than a few of those lurking closer to home, possibly only unremarked upon due to my overlong exposure to the madness.



In closing...

I shouldn't have let this blog rot. I should get some pretty screenshots for next time!

Saturday, 21 August 2010

Side Projects: Gnomon

As I'm frantically running around doing stuff, I figured it'd be a good time to dump some of the small projects I've worked on in my spare time.


First up, the little Clojure/Scala interop project tentatively called Gnomon. Nothing to see here graphically, the fun part is just having a little space in which to evaluate Clojure directly. Rendering commands are pushed from the Edit Window thread (using the (render-command ...) and (render-static ...) macros) by simply converting the s-exprs to strings, and then evaluated on the render thread. The bulk of the app is written in Scala, but all the fun stuff happens in Clojure.

The editor itself is amazingly crude, but it was more a proof-of-concept for a joint Scala/Clojure project. There's a little awkwardness due to Scala frequently emitting a variety of name-mangled classes, but it still works surprisingly well - Clojure provides a certain flexibility and ridiculously easy runtime augmentation, while it's easier to generate a (more) efficient statically-typed framework in Scala, and Java interop on both sides provides for easy communication.

I'd love to follow this up at a later date with a proper project.

Tuesday, 22 December 2009

::tap-tap:: Is this thing still on?

Oh! Hi there.

Amazingly, I have been working on this little project. It's been slow going.



The rendering system has been refactored considerably. It is very much still a nasty mass of imperative wrongness, but its also a bit more consistent and less fragile. I've been experimenting with different methods of generating the world geometry. I've tried half a dozen implementations of a game-entity framework, none of which seemed adequate. I added a quick random map generator (screenshot taken from one such random map), and worked on the water shader a little. It looks OK in motion, but definitely needs to be somewhat more obvious generally. Those little divots in the ground are shallow water, the light source being the player (who's mesh has temporarily elected to disappear).

Oh, and I gave Clojure a spin too. Experimenting with the property-bag approach in a Lisp is relatively joyous, especially with Clojure's explicit syntax for hash maps. I found it hard to scale projects up, though. I'm too used to arranging things in terms of objects and classes, both Haskell and Clojure befuddle me with a mass of functions. My failing entirely, the languages have much to recommend them.

I started using Mercurial SCM for source control on this little project. Although I do find myself wanting a P4Win-like GUI front end (which may well exist somewhere), the command-line tools are quite lovely and I refuse to give up on them before becoming at least somewhat proficient.


Now for some design babble. This idea surfaced recently when trying out a few entity and time-handling systems, and I think has some interesting gameplay connotations. Here's the gist:

  • Every turn, collect actions from all agents in the game world

  • Execute all actions, regardless of validity, to produce a new world state. Each agent also tracks the actions that changed it this turn.

  • Resolve the world state by resolving invalid conditions


The third step is obviously the tricky one, but also where the most interesting aspects spring from. The first two steps merely simplify some aspects of mutating the game world.

So this tricky 'resolve' stage... what happens here? Well, take a very simple set of verbs: agents can either stand still, or move one space each turn. More than one agent occupying a space is invalid. If two agents occupy the same space, do some basic conflict resolution and then generate a valid world state based on that. The losing agent could be displaced back to its original position (and also presumably lose some health, in a standard Roguelike game of HP and damage rolls...), whilst the winner occupies the contested space. In the case of a tie, both agents are returned to their starting positions. An agent who didn't move in this turn gets some manner of defensive bonus, but if it loses the conflict will be displaced away from the attacker.

There are immediate problems with this simple method. What happens if another agent occupies the starting position of the losing agent in a conflict? How do we handle three or more agents in a space? What about an agent surrounded by enemy agents, such that no position is valid after losing? Conflict in dead end corridors?

Some embellishments to the system should allow most of these to be resolved. For example, agents could be in a standing or prone state, and not occupy any space when prone. Losing agents with no valid moves can be knocked prone. And so on.

But what do we gain from this approach?
  • Most interestingly, this represents a gateway to yomi, as described in the linked post. As every action is essentially simultaneous, a suitable number of counter moves and counter-counter moves allow for much greater potential depth in conflict. There aren't enough in the simple example above, but it at least admits the possibility. In order to be really satisfying, either the AI behaviour needs to be tractable for the player, or multiplayer might be considered.

  • Strategic positioning - this is a big part of what I'd like to capture in combat. Being able to 'bull rush' opponents is crucial; several character development options suggest themselves to allow more tactical control over the way a battle evolves. This feels a lot easier to approach when all potential movement is handled in a single step.

  • I think this system is less predictable. As everything happens at once, actions are more likely to fail and rather harder to evaluate. Rather than just considering the success chance of a given action, the player must consider all the possible actions of relevant agents that could interfere with its execution. This is a good thing in general.


And what is lost...
  • Agents all move at a uniform speed, or at integer multiples of that speed. We lose the fine-grained ordering of agents based on some intrinsic properties and/or the execution time of actions. All actions take one turn. We can allow for slower agents by forcing them to take null actions except every N turns. In theory we can also allow faster agents by slowing down the rest of the world in much the same way, but that seems inelegant - as many actions will require a graphical representation and time to be displayed, doing this will slow the game for the player.

  • The system is less predictable. Players can no longer easily guess the outcome of an action, as it depends on the actions taken by other agents in the same turn. This could be a bad thing for transparency.


It needs more thought, and the implementation details could get very messy for the semi-mystical 'fix the world' step.