

Code, Eval, Play, Loop – Common Lisp OpenGL Environment - joubert
https://github.com/cbaggers/cepl

======
raphaelss
Be sure to check out the videos of it in use [1] and the Lisp to GLSL
translator [2].

[1]
[http://www.youtube.com/playlist?list=PL2VAYZE_4wRKKr5pJzfYD1...](http://www.youtube.com/playlist?list=PL2VAYZE_4wRKKr5pJzfYD1w4tKCXARs5y)

[2] [https://github.com/cbaggers/varjo](https://github.com/cbaggers/varjo)

~~~
baggers
Hehe looks like I need to get some visually interesting demos up, I've been
pretty lazy about that. I started looking to input and event propagation and
got lost in a sea of frp and data-flow stuff for a while.

------
zach
For Clojure enthusiasts, I highly recomment Zach Oakes' environment in the
same vein, Nightmod (his Nightcode IDE specialized with his play-clj library).
It's an experimental platform that is a tidy, simple way to experience game
programming in a functional style.

[https://nightmod.net/](https://nightmod.net/)

Also, here is his presentation on this subject at the last Conj (great talk):
[https://www.youtube.com/watch?v=0GzzFeS5cMc](https://www.youtube.com/watch?v=0GzzFeS5cMc)

~~~
krat0sprakhar
My first question on clicking the link was - Does there something like this
exist for Clojure?

Glad to the have my question answered. Thanks for the links!

~~~
lynndylanhurley
Lol me too! I'm gonna check out Nightmod asap. Anybody here tried it yet?

------
orbifold
Not to take anything away from that, because it's awesome, but that can also
be accomplished in C. In fact pretty much any good game engine supports both
dynamic shader recompilation, hot swapping the renderer and dynamically
reloading the game code. A classic example where this technique is implemented
is Quake 2. Basically the renderer and game are linked into the client as
dynamic libraries and reloaded on demand or when a change is detected.

~~~
yarrel
Rebuilding those dynamic libraries requires external build system and compiler
invocation. In Lisp you just use the REPL.

~~~
orbifold
Of course, but in practice that doesn't really matter. Recompilation time for
small changes is negligible and if you have a sane build system setup is
pretty much invoked the same way you would load new code into a repl.

In the case of shader compilation, compiling and linking actually is exposed
as library functions, so you have complete control over how to do that.

Most of the dynamic features a repl provides, like introspection and so on is
also available with a good debugger, depending on the scope of the project you
can also just use Lua as a scripting language to get the majority of the
benefits that Lisp has.

Moreover nested parentheses sort of pale, if you can visualize most of your
state in much more powerful ways on the screen.

Since you have complete control over memory, you can implement time travelling
debugging pretty easily, you just need a good ordinary debugger, a way to
record all input to the game (easily done if you have clean separation between
game and platform code) and a way to snapshot the game state at some point in
time (also easy if you allocate all memory ahead of time and only let the game
code use your memory allocators).

~~~
malisper
Could you redefine a class/structure and update every instance of it at
runtime?

For example, let's say you are currently representing complex numbers in
rectangular form. Is it possible to convert every existing instance to polar
form, at runtime, without breaking any code?

~~~
yoklov
That's a pretty ridiculous use case. I'd think if you wanted to make a change
this drastic, having to reload the game wouldn't be a huge deal. I mean, you'd
want to make sure everything up to the point you were at still works anyway.
(Besides, this is an awful way to represent 2D points in practice).

FWIW, It's certainly possible to write code that reorders struct fields on
changes, but it requires either boilerplate, macro hell, or parsing part of
your C code for structure declarations (I've heard this sounds worse than it
is). Arbitrary mappings are more difficult and IMO not worth the trouble.

Not to say this technique doesn't have downsides. It's downsides are so huge
that IMO it's benefits aren't worth it, _unless_ you were already going to
program in that style to begin with.

\- No pointers to static memory (globals, vtables, and pointers to string
literals or constant arrays are out) \- No pointers to functions (most other
ways of emulating dynamic dispatch are out). \- You need to use custom
allocators that work out of your game state block. And since you have no
global or thread local state... you need to hope that any library you want to
use allows you to provide a context for any memory allocation it wants to do.
Most don't. \- etc, etc, etc... you get the picture. Essentially, you need to
write your game like its 1995.

And sure, maybe you can get this in lisp without any limitations (I don't
know, but I believe it if you say you can), but the reality we live in is that
it's unrealistic to write production-quality game engines in lisp. I've heard
it's used for scripting and AI in some places (probably just Naughty Dog,
tbh), but most of the code that goes into a game isn't in script, unless it's
a slow game.

~~~
malisper
> That's a pretty ridiculous use case.

It was just an example. I never said you would actually want to do it.

> maybe you can get this in lisp without any limitations

See my response to orbifold:
[https://news.ycombinator.com/item?id=8943113](https://news.ycombinator.com/item?id=8943113)

> I've heard it's used for scripting and AI

There are many different versions of lisp, some of them are used for
scripting, but most implementations of Common Lisp could be used for almost
anything.

> most of the code that goes into a game isn't in script, unless it's a slow
> game.

Write version 0 in a high level language. Figure out the design and
representation. Then rewrite the slow parts in a more efficient language.

~~~
yoklov
> See my response...

That's very interesting, and would definitely solve a lot of the problems with
hot-reloading code.

>> There are many different versions of lisp, some of them are used for
scripting, but most implementations of Common Lisp could be used for almost
anything.

I was talking specifically talking about uses inside of production quality,
high performance (e.g. AAA-quality) game engines. The only usage of lisp that
I know of is inside Naughty Dog (Last of Us, Uncharted, Jak and Daxter, etc),
who have used it internally for a long time. I hear they're lisp nuts, but
even they don't try to write the game engine in it.

> Write version 0 in a high level language. Figure out the design and
> representation. Then rewrite the slow parts in a more efficient language.

For something small, retro, or 2D then maybe this could work. For anything
else, this would be setting yourself up for failure.

You'll end up rewriting all or most in C or C++. This will cause you to miss
deadlines and generally people will shit on your game on the internet.

Maybe it will be fast enough at this point, but odds are it won't. It will
probably have the same problem as most game engines written in a high-level
style, even if they're in C or C++. You'll fire up a profiler but there won't
be any optimization targets. The whole program will be more or less equally
slow. This is because you didn't design with memory access patterns in mind.
90% of the code will be spent waiting for memory to load during a cache miss.

Eventually, the game will be released and will struggle to hit 30fps. People
will continue to shit on the game online, and that's if anybody bothers to
play it.

Since you're starting now, it will probably be at least 4-5 year in the
future, so even if 60fps expected by everybody yet, the oculus rift will be
out, and anybody who plays your game on that will have a bad time. On the
oculus, the framerate needs to be at least 90fps, or you risk inducing nausea.
That means you have 9ms to update, and do _two_ renders of the game (one for
each eye), and if you can't make this target, your game isn't just slow, it's
actively harmful to the users.

The only way to avoid this is to think about memory usage, access, and the
cache from the very beginning. At that point, maybe you could still write it
in lisp, but any benefit it would have given you is gone.

I've seen most of this first hand (on engines that were written in C++, but
ignored the cache), and it really sucks.

