Simplified Minecraft4k in C++
Compared to the original the simplified version eliminates the code that generates the texture map and the view down the tunnel of moving blocks remains straight down the Z-axis, so there is less code to write. A good place to start:gem.h:
Note: this is my first OpenGL project and my first GLFW project, so it may well not be "best practice." However, I've compiled and run this on Windows 7 and OS X and it works. There are some notes on how to compile this code in the Appendix below.
Minecraft4k in C++
Simplified Minecraft4k in Lisp
Lisp appeals to me for many reasons, probably mostly the same reasons it appeals to many other people. I think it's fair to say Lisp isn't a mainstream, corporate language. And that's one reason.
This is what I wrote:mc4ka.scm:
Note: not only is this my first OpenGL project this is also the biggest program I've ever written in a Lisp-family language, so it's almost certainly "wrong." However, it works on my DrRacket 5.2.1, producing the same moving tunnel of blocks as the C++ version, but not at the same frame-rate, as discussed below.
C++ vs. Lisp
“The code is nevertheless much more compact, because (no surprise) Racket is better than C++.”
- Matthew Flatt, currently associate professor of computer science at the University of Utah
I assume the people behind Racket have a deep understanding of computer programming languages. But can these things be so black and white?
For the case in hand, the C++ version displays 80 frames per second on my 2008 iMac, and the Racket version displays one frame per second on the same machine. Surprise?
Why is the Lisp version so much slower than the C++ version? I assume I've made some kind of dumb beginner's mistakes in the way I've written the code. (If you can see what they are, would you tell me?) I used Racket's Create Executable... command to create a compiled application; if I just hit the run button in the DrRacket IDE the code runs at a quarter the speed: I get one frame every 4 seconds.
Maybe I'm trying to write C++ in Racket - a classic beginners mistake? - but while writing the code one big C++ feature I missed was the deterministic destructor. I wanted to call glfwTerminate when my gem object went out of scope. Uh-oh! "How do you get anything done in Lisp? It doesn't even have destructors." I am not saying this. In fact I'm pretty sure that there is either already a mechanism that would automatically call a "destructor" method and I just couldn't find it, or there will be a way to build such a mechanism when I've learned a bit more. I know that the Racket with-output-to-file function automatically closes the file "whenever control escapes the dynamic extent" of the with-output-to-file call, which is the sort of thing I'm looking for, I think.
“By induction, the only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one. (This is probably what Eric Raymond meant about Lisp making you a better programmer.) You can't trust the opinions of the others, because of the Blub paradox: they're satisfied with whatever language they happen to use, because it dictates the way they think about programs.”
- Paul Graham
I understand what Paul is saying, but am I really too stupid to see further than my own nose? (Don't answer that!)
“The same is true of Byrne's account of how music has not "progressed" from a "primitive" state -- rather, it adapted itself to different technological realities. Big cathedrals demand music that accommodates a lot of reverb; village campfire music has completely different needs. Reading this, I was excited by the parallels to discussions of whether we live in an era of technological "progress" or merely technological "change" -- is there a pinnacle we're climbing, or simply a bunch of stuff followed by a bunch of other stuff? Our overwhelming narrative of progress feels like hubris to me, at least a lot of the time. Some things are "better" (more energy efficient, more space-efficient, faster, more effective), but there are plenty of things that are held up as "better" that, to me, are simply different. Often very good, but in no way a higher rung on some notional ladder toward perfection.”
- Cory Doctorow
This quote is from Cory Doctorow's review of a book about music by David Byrne. I have no idea where Doctorow stands with regard to discussions about C++ vs. Lisp. But what he says here resonates with my own views about these languages, which is that they are, like men and women, equal but different. It's obvious. I think people often look at a poorly written piece of code and blame the language it's written in. Clearly, some languages are more expressive or abstract than others. But there is more to it than that. As I've written before, I don't care how super-duper your language is, I bet I can write some pretty dumb, incorrect, slow, brittle, half-assed code in it. And conversely it isn't necessarily true that something written in a language lower down the abstraction scale couldn't be good, by any of the usual measures of good, principally by being useful and/or beautiful.
I value the diversity of programming languages. I'm dabbling in Lisp because it interests me. I plan to update this post in ten years' time, when I hope I'll be more of a Lisp programmer than I am now. Maybe my opinion on C++ vs. Lisp will have changed by then.
“Today I committed the first 5112 lines of D code to Facebook's repository. The project is in heavy daily use at Facebook. Compared to the original version (written in C++) we've measured massive wins in all of source code size, build speed, and running speed.”
- Andrei Alexandrescu
My contention is that someone of Alexandrescu's ability, coming to a piece of code with fresh eyes and a certain determination to prove a point, could rewrite the code in C++ and achieve similar "massive wins."
Human beings are so tribal. Don't you think? We seem to need to identify strongly with one group (for protection? from what?) and jeer at the other lot for being different.
A friend with a long-time interest in D has done a port of mc4ka/b. You can see it here. (Yes, but the question is what are we going to do?)
Appendix - Notes on compiling the code
Windows and OS X ship with OpenGL support, but you need something to create a window and handle keyboard input and so on. There are several libraries to choose from, such as SDL, GLUT and GLFW. I used GLFW because it seemed to be actively maintained. I really didn't know much about it, but it all worked out OK.
This article is more fun with programming languages than it is graphics programming tutorial. None of it should be taken as The Right Way to do it. These are notes I took about what I did to just get a bitmap out of a vector and onto the screen.
Building mc4ka.cpp and mc4kb.cpp under Windows The current GLFW release is 3.0.3: - download the source archive (glfw-3.0.3.zip) from http://www.glfw.org/download.html and unzip it - build GLFW as described in README.md - download cmake installer from http://www.cmake.org/cmake/resources/software.html and install it (I used the Windows (Win32 Installer) version 220.127.116.11) - I used the cmake GUI to build the GLFW.sln file to build the GLFW static library - then open the GLFW.sln in Visual Studio 10 and build the whole GLFW solution in both Release and Debug - build and link mc4ka: I borrowed one of the GLFW example solutions, but then I made a batch file: mkawin.bat: cl /nologo /MD /EHs /O2 /W4 /I C:\Projects\glfw-3.0.3\include mc4ka.cpp ^ /Fmc4ka /link C:\Projects\glfw-3.0.3\src\Release\glfw3.lib ^ user32.lib gdi32.lib glu32.lib opengl32.lib - ditto for mc4kb Building mc4ka.cpp and mc4kb.cpp under OS X - download the source archive (glfw-3.0.3.zip) from http://www.glfw.org/download.html and unzip it - build GLFW as described in README.md - download cmake installer from http://www.cmake.org/cmake/resources/software.html and install it - I used the cmake GUI to build the makefiles to build the GLFW static library - then run make in the build directory to build GLFW - then sudo make install - to compile and link mc4ka.cpp I used this Shell script: mkaosx: #!/bin/bash # build mc4ka.cpp with i686-apple-darwin11-llvm-g++-4.2 under OS X g++ -O3 -ffast-math -g -o mc4ka mc4ka.cpp -lglfw3 -framework Cocoa -framework OpenGL -framework IOKit - ditto for mc4kb Building mc4ka.scm with Racket under Windows and OS X Racket comes with OpenGL support, so once you've installed Racket you're ready to go. To install Racket you do pretty much the same thing under both Windows and OS X: - download Racket from http://racket-lang.org/download/ - I installed Racket v5.3.6 (x86_64) on my Windows 7 box and Mac. I also ran the code under DrRacket v5.2.1 on the Mac. (They have binaries for 32- and 64-bit Windows, OS X and Linux. Or download the source and build it yourself.) - start DrRacket and File|Open... mc4ka.scm - to run it click the green Run button - to compile it goto Racket|Create Executable... and choose Type: Stand-alone, Base: GRacket
Appendix - Notch's original code
“A quick port of Minecraft4k to test what's possible in JS and HTML5.
Because of the nature of this project (it was originally meant as an entry for the Java4k competition, which focuses on executable size), the code is HORRIBLE, but fairly small.
You may use the code in here for any purpose in any way you want, at your own risk.”- Marcus Persson