Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    68
  • comments
    177
  • views
    82392

About this blog

Save your forks, there's pie!

Entries in this blog

 

Getting started with Node.JS part 1: Setup

I had been hearing about Node.JS for a while. "It's JavaScript on the server!" I mostly ignored it, as ASP.NET was forced on me at the time and I hadn't yet given employed life the finger and a flaming bag of poo on its doorstep[1]. What does "JavaScript on the server" even mean?

Well, it's a little more than just the bare meaning of a JS execution environment outside of a browser. Think of it like JS finally making something out of itself. All those years in college. Getting stuck in low paying design jobs. Now it commands respect! It can connect to databases!

Basically, start with V8--Google's JavaScript engine, not the salty-disgusting-juice that tricks you into eating vegetables when you were expecting a fruit smoothy instead. Just like the JavaScript that runs in their Chrome web browser. Then, throw away DOM--or rather--never add it because you didn't add WebKit into the sauce. Finally--and here comes the important part--throw on top a reliable package manager and a core set of libraries that make building a stand-alone Web server nothing more than a few lines of configuration code.

I should probably just shut up now and get to the point, because I'm the one late to the party and you, dear reader, probably know all this junk already.

What kept me away for so long was Django. And Ruby On Rails. And Leinenkugel, or Lemonysnickets, or whatever the hell those people in [s]ScalaClosure[/s]Clojure land are calling it. See, I have been trying for many years to get out of ASP.NET, and having heard the call of all of these programming-language-plus-web-environment-plus-package-manager combos[2], I had tried them out, to much dismay. These things were a pain in the ass! This was what everyone on HackerNews was raving about and telling me I was the idiot for sticking to ASP.NET? Half this junk wouldn't run on Windows without at least a day and a half of tracking down obscure patches and packages and talismans, of which you're on your own finding because the communities are hostile towards Windows users. Yes, I know, you don't like "Micro$oft". But not helping me and not spending the extra effort to make your software compatible with Windows, you're also not helping me get one step closer to using Linux full-time.

But Node.JS isn't like that.

First of all, you install one thing. You go to http://nodejs.org/download/ and you pick the version that is right for your system. Or, you open your terminal and type "apt-get install nodejs" or "emerge nodejs" or "yum install npm" or "brew install node" or whatever, you can probably figure it out, it's out there in your package manager of choice. And it's done. You have it. It's even installed on your PATH now.

Next, you don't "django-admin.py startproject mysite" or "rails new mysite" and then watch as it does a ton of stuff that nobody has explained yet and aren't anywhere close to explaining, because apparently you should be happy that it just dumped half a megabyte of text on your hard drive when all you want to do is give the thing a spin. If you want someone to make a project template for you later, you can do that, but up front, when you're just trying it out, there is no necessity.

And finally, when you install new libraries through the package manager, NPM, you also don't go hunting for obscure C libraries that maybe didn't get included in your particular Linux distro because the package maintainer is a masochist who compiled his own Gentoo from scratch and you're on a base config of Linux Mint, or because you're on Windows still and would really rather not have to install that bastard child Cygwin.

So let's try it out now. Open your command line. Type "node". Hit enter. I'll wait. If you installed it like I said, it should work. They realized people don't like to take more than one step to use new software, so they setup reasonable defaults for everything. You'll be presented with a REPL[3]. Then, just type sometimg. Sometimes I type "hello", a methaphorical call out into the dark, searching for a response. It comes in the form of evaluation.



Try a few more things, quit out of it by hitting CTRL+C twice[4].


If you've ever done anything with the HTML, this is probably no big surprise. And that's the brilliance of Node.JS! It's a programming language you already know.

Okay, one more example, to show off how easy it is to get a Web server going, because REPLs are great and all but they don't a project make. Particularly clever students with well refined bullshitting skills will find everything they need in the next screenshot to make a successful consultancy. If you've never done web development before, you have no clue how much I didn't have to do here. This is not a specially contrived example with 10MB of configuration files in a Turing-complete config format. I did this from a bare install as I described in the article and you see everything in this image necessary to replicate it.



That's it for now. Stay tuned for my next article, which will cover WebSockets with AJAX fall-back through Socket.IO. What does that even mean!? LOLGIBBERISH! It means lower overhead for requests back to the server, which means faster updates from the server, which means we can start writing networked games in JavaScript and deploy them through the browser in a way that Java never seemed to be able to pull off.

[1] for the record, I still haven't, but I have stopped returning its calls.
[2] the good, ol' PLPWEPPMC, as my pappy used to call it
[3] Read-Eval-Print-Loop, a new brand of cereal to compete with Fruit-Loops
[4] or CMD+C on OS X, but I suspect you probably know to make the mental translation on your own by now

capn_midnight

capn_midnight

 

Getting started with Node.JS part 2: Socket.IO

A few days ago, I talked about how easy it is to get Node.JS installed, regardless of your platform, and get code running that shows something in your browser. Whether you're on Windows or OS X or Linux, there is only one package to install that gives you access to an easy-to-configure web server running in a language you probably already know: JavaScript.

Today, we're going to jump feet first into Socket.IO: a library for Node.JS that supports WebSockets[1] between your server-side code and your client-side code, all the way back to IE5.5. Yeah[2].

To start, we'll need a basic web server that can load static files and send them to the user. I'm jumping ahead here and assuming that I'm going to eventually want to serve up some HTML, CSS, client-side JavaScript, PNG, and MP3 files, considering the goal is to make a game here. That's a lot of different types of content, so I'm going to cheat and take a library someone else wrote for handling it: Mime. This will also give me a chance to show you what happens when you install a dependency through NPM.

I'm going to make a new directory for a project, then install the Mime library through NPM. I'm making a new directory because NPM is going to download some files for me and I want it to stick them somewhere that won't junk up my harddrive. Installing the library is just simple "npm install mime" statement.


And there it goes. NPM knows where to download the code for Mime because someone registered Mime on the NPM website. The library gets copied to a directory called node_modules.

Now, let's throw down some code into a text file:


I hope this is pretty clear on what it does. There is not a lot to cover. Probably the most surprising part of it is the http.createServer call. It's registering a callback function that will be called whenever an HTTP request is made to the server. In general, Node.JS does a lot of stuff through callbacks, to make up for its lack of multi-threading primitives of any type. It's basic HTTP from there. I save this to a file called "server.js" and run it with a simple "node server" (Node adds the ".js" file extension for me), I open my browser and head over the http://localhost:81/ and this is what I get:File not found. / reason: {"errno":28,"code":"EISDIR"}
Aaaah, yes, I didn't actually tell it what file I want. That's pretty easy to fix though. Let's kill the server with CTRL+C (webServer.listen will keep Node running until we explicitly kill it) and make the code default to loading an "index.html" file if the URL specified indicates it was a directory name.


I've also created a file named "index.html" that just contains the text "Hello, world!". Now, when I restart the server and load the page, I see this:


"But capn_midnight", you say, "Why don't we just use Express and weeooeeooeeeoooooo". Because we're making a Single-Page Application (SPA) that will have mostly static files for making an extremely basic front end, with most of the logic residing on the server side. If we need more out of our static content delivery than this, then we can figure that out later. Also, this article series isn't really about Node.JS or Socket.IO or Express or any thing in particular, it's about getting to make a multiplayer game very quickly.

Alright, let's move on to the Socket.IO stuff. Do yourself an "npm install socket.io" in your project directory. You'll notice that there is a lot more spewed out than when we did it for Mime. This is because Socket.IO has its own dependencies and NPM went ahead and got them for us. If you've done any reading about NPM installs, you might ask if we would want to install Socket.IO with the -g switch, for "global". Typically, global installs are for installing Node software that we are going to use, not libraries that our project is going to use. If we wanted to use the TypeScript translator, that would be done with "npm install -g typescript" (and you would have to have admin rights, so you probably need to sudo that if you're on a Unix-like OS). Then, we would have the TypeScript compiler, tsc, installed into our PATH, and we could use it directly from the command line. But that's not necessary here.

For code, I'm going to first push most of the Web server stuff into it's own file, just to try to keep everything tidy. The only thing left in my original source file is the call to create the server and start listening. It's important at this point to point out a point of interest in Node's import system. When you call the require() function, the parameter to it is actually specifying a search string, not exactly a library. It iteratively searches from the current directory all the way up to the root directory of your system, looking for a "node_modules" folder that has a file that matches the name you're looking for. And if you didn't add a file extension to the file, require() automatically assumes ".js" for you.

But, if you don't want to put your files into a folder named "node_modules" (or pollute your NPM installation directory), then you need to tell require to look in a specific directory for the file. It's a lot simpler than it sounds, just use the "." single-dot name for the "current directory" and apply your filename to that.

So in this particular case, I've moved my code to a file named "httpRequestHandler.js". I've put it in the same directory as my "server.js" file. So to import it, I must "require('./httpRequestHandler.js')" or "require('./httpRequestHandler')" for a little-bit shorter version.

Anyway, now that we've had that little bit of a side-quest, back to the task at hand. I add code to my server.js file for creating a WebSockets listener. It's very simple. If you've done any sort of network programming before, I'm sure you'll be as flabbergasted as I was.


Look at that! It's all of four additional lines of code to listen, respond to new connections, and do some basic communication. In other words, it's one more freaking line of code than things we're freaking doing.

So what is going on here? Well, lines 5 and 6 get our web server going again, to be able to serve up the index.html file that will represent the client side of our client-server modeled program. And lines 8 through 14 setup the server side of our client-server modeled program.
Line 8: Socket.IO needs to know what socket it's going to listen on. You can give it a specific port number, or you can give it a reference to your webServer object and it will listen on the same port as the Web server is running on. That's pretty neat.
Line 9: Registers a callback function that will execute whenever a new connection is made. At this point, we're officially ready-and-waiting for connections. The callback receives a parameter that is the socket object with which we'll communicate with the connected client. No polling for new connections, no needing to worry that work done to accept a connection is blocking IO with all of the other clients. It's the very picture of "just works".
Line 10: To send data to the client, we use the emit() method on the socket object. It takes two parameters, an event name and a data package to include with the event. The names can be anything of your choosing. Any event issued with emit() can be consumed with on(). The data package can be anything as well. Typically, we'll send a plain Javascript object, but for now I'm just sending a string.
Line 11: To receive data from the client, we use the on() method on the socket object. It takes two parameters, an event name and a callback function to execute when the event occurs. The callback function receives a parameter of its own, which will be the data package that was emit()ed at the server from the client.
Line 12: And then, for this example, just to prove to the client that we heard it, we echo back a message.

Finally, we need a little bit of UI code to provide a user a physical interface with which to interact with server:


By now, there shouldn't be anything surprising here. We using an HTML SCRIPT tag to import the Socket.IO library for the client side[3]. It specifies an object called "io" that has a method connect(). Connect takes an address and does all the handshaking necessary to establish a connection[4]. From there, it's exactly the same as wiring up the events and handlers as we did on the server side. Exactly the same. Networking code really can't get any simpler than this.

Start it up, click the button a few times, and you should see this:


By this point, if you know HTML, CSS, and JavaScript already, you can be off to the races on making a multiplayer game with Node.JS and Socket.IO. But I'm not going to leave you out in the rain just yet. Next time[5], I'll show you a very simple chat program using what we've learned so far. And this very simple chat program will grow legs and eventually become a Multi-User Dungeon, or MUD for short.


[1] strictly speaking, it's only WebSockets if you're on a browser that supports WebSockets, but they smooth over the details for you with some fallback options. By default, you probably won't have to worry about it.
[2] I know. Sploosh. Okay, the IE5.5 support isn't that mind blowing considering that it's done through a Flash plugin. But it points to a larger issue of dedication to cross-platform compatability in the Socket.IO dev team. This works whether you're on a 3 year old iPhone or a 10 year old laptop. In other words, if your code has platform compatability issues, it's probably not Socket.IO.
[3] The location of which is a closely guarded secret. Actually, it's just coming out of your node_modules directory. But Socket.IO is hijacking the HTTP requests a little bit to look for requests to the client JS file. Anyway, this is mostly out of scope here.
[4] There is a seriously heavy amount of code in this connect() method. It has to figure out what the client browser is capable of doing, be it true WebSockets, AJAX long-polling, or eventually just giving up and using a Flash-based fallback. And then it has to make the connection to the server and communicate those details so that the server knows how to respond. Again, not really that important.
[5] Which unfortunately might be a couple of weeks. I'm going on a two-week-long trip to the Galapagos Islands with my wife, my camera, and distinctly not my computer.

capn_midnight

capn_midnight

 

HTML5 audio for games made easy

Audio in the browser is deceptively tetchy. It's easy to get a basic sound to play with the tag.[code=html:1] If you can read this, your browser is not fully HTML5 compatible.
But there are several problems with this:
First of all, good luck navigating this compatibility chart. Until Mozilla finally caved and decided to support MP3, there was no single file format supporting Chrome, Firefox, Safari, and IE. Opera is still a painful holdout on file formats, and the situation on mobile is disgusting.
You can't programmatically trigger the audio playing on mobile devices without direct user action in your game loop. You basically have to put up a "start game" button that tricks the user into playing a silent audio file, then you have free reign to trigger that particular audio element.
You get almost no control over how the file plays. There is a volume setting, but it hasn't always been reliable on all platforms. There's no mixing. There are no effects.
It's super difficult to rewind and replay an audio file. Honestly, I still don't really know how to do it correctly, and I'm a goddamn salty pirate.

In short, the tag is for one thing and one thing only: for NPR to post their podcasts directly on their site.

Okay, let's get out of this malarky. What else do we have? Well, there's the Web Audio API:
Granted, formats still aren't great. Strangely, the compatibilities don't exactly match the tag. But MP3 is universally there, as is AAC. And technically, you could write a decoder if you wanted. I wouldn't suggest it, but it is possible.
You can play audio whenever you want, as many times as you want, on desktop and mobile, without buggering around with stupid hacks.
It's a fairly-well featured signal processing system. That's great if you know what you're doing, murder if you don't.

It's a little difficult to program. And the MDN tutorial gets far too into crazy effects for me to bother if all I want to do is make a few blips, bloops, and gunshot sounds.

That's why I wrote this: Audio3DOutput.js. Here's what you do:[code=js:1]// to start, create the audio contextvar audio = new Audio3DOutput();// then, check if your system supports itif(audio.isAvailable){ // if you want to play a specific sound file every time a user clicks a mouse button: audio.loadBuffer("click.mp3", null, function(buffer){ window.addEventListener("mousedown", function(evt){ audio.playBufferImmediate(buffer, 0.25); // 25% volume gain }); }); // if you want progress notifications while the audio is loading and processing: audio.loadFixedSound("song.mp3", /* looping */ true, function(op, file, numBytes){ console.log(op, file, numBytes); }, function(snd){ snd.source.start(); }); // if you want to position the sound in 3D space: var sourceX = 10, sourceY = -4, sourceZ = 3; audio.load3DSound("ambient-sound.mp3", true, sourceX, sourceY, sourceZ, null, function(snd){ snd.source.start(); setTimeout(moveListener, 5000); // 5 seconds }); function moveListener(){ audio.setPosition(x, y, z); audio.setVelocity(vx, vy, vz); audio.setOrientation( ox, oy, oz, upz, upy, upz); } // if you want to take the first file of a list that successfully loads: audio.loadFixedSoundCascadeSrcList(["song.aac", "song.ogg", "song.mp3"], null, function(snd){ snd.source.start(); }); // or if you want to synthesize the raw PCM data yourself: // in monaural var data = [], seconds = 0.25; for(var i = 0; i
There you go. If you find a need for more than these basic functions, please drop me a line and let's discuss adding it!

capn_midnight

capn_midnight

 

VR Lessons Learned So Far

[color=rgb(77,79,81)][font=Helvetica]
This is a loosely organized list of things I've noticed while using and developing virtual reality applications for the smartphone-in-headset form factor. It is specific to my experience and may not reflect anyone else's personal preference, such that VR is apparently quite dependent on preference. But I think that steadfast rules of design are necessary for the impending VR bubble, to convey an aesthetic and unified design such that users may expect certain, common idioms and adapt to VR software quickly. Thus, this is list a roadmap of my current aesthetic for VR. It is a living document, in the sense that future experiences may invalidate assumptions I have made and force me to recognize more universal truths. Proceed with caution.[/font][/color]
Presence is the ability to feel like you are in the scene, not just viewing a special screen. You'll hear a lot of people talk about it, and It is important, but ultimately I believe it to be a descriptor of an end result, a combination of elements done well. There is no one thing that makes "presence", just as there is no one thing that makes an application "intuitive", "user friendly", "elegant", or "beautiful". They either are or they are not, and it's up to the individual experiences of the users to determine it.
Presence is a double-edged sword. [font=inherit]I've found that, once I feel "present" in the application, I also feel alone, almost a "ghost town" feeling. Even if the app has a single-user purpose, it seems like it would be better in an "arcade" sort of setting. To be able to see other people may help with presence.[/font]
The hardware is not yet ready for the mass market. That's good, actually, because the software and design side of things are a lot worse off. Now is the time to get into VR development. I'll say nothing more about the hardware issues from a performance side. They are well known, and being worked on [font=inherit]fervently [/font]by people with far more resources than I.
Mixing 2D and 3D elements is a no-go. Others have talked about not placing fixed-screen-space 2D heads-up-display elements in the view for video game applications, but it extends much further than that. The problem is two-fold: we currently have to take off the display to do simple things involving any sort of user input, and there is no way to manage separate application windows. We're a long way off from getting this one right. For now, we'll have to settle for being consistent in a single app on its own. A good start would be to build a form API that uses three-space objects to represent its controls.
Give the user an avatar. This may be a personal preference, but when I look down, I want to see a body. It doesn't have to be my body, it just needs something there. Floating in the air gives me no sense of how tall I stand, which in turn gives me no sense of how far away everything is.
Match the avatar to the UI, and vice versa. If your application involves a character running around, then encourage the user to stand and design around gamepads. If you must have a user sit at a keyboard, then create a didactic explanation for the restriction of their movement: put them in a vehicle.
Gesture control may finally be useful. I'm still researching this issue, but the experiments I've done so far have indicated that the ability to move the view freely and see depth make gestures significantly easier to execute than they have been with 2D displays. I am anxious to finish soldering together a device for performing arm gestures and test this more thoroughly. This demo makes it clear that this is at least an extremely lucrative path of study.
Use all of the depth cues. Binocular vision is not the only one. Place familiar objects with well-known sizes in the scene. Use fog/haze and a hue shift towards blue at further distances. But most importantly, do not give the user long view distances. Restrict it with blind corners instead. Binocular vision is only good for a few feet before the other depth cues become more important, and we are not yet capable of making a convincing experience without the binocular cue.
Object believability has more to do with textures and shading than polygon count. Save on polygon count in favor of more detailed textures and smooth shading.
Frame rate is important. I remember being perfectly happy with 30FPS on games 10 years ago. That's not going to cut it anymore. You have to hit 60FPS, at least. Oculus Rift is targeting 75FPS. I'm sure that is a good goal. Make sure you're designing your content and algorithms to maintain this benchmark.
Use lots of non-repetitive textures. Flat colors give nothing for your eyes to "catch" on to make the stereo image. The design of these viewer devices is such that the eyes must actually fight their natural focus angle to see things in the display correctly. It will be easier for the user if you make it as hard as possible to not focus on object surfaces. Repetitive textures are only slightly better than flat colors, as they provide a chance to focus at the wrong angle, yet still achieve what is known as the "wallpaper effect". And do not place smaller objects in any sort of pattern with regular spacing.
Support as many different application interactions as possible. If the user has a keyboard hooked up, let them use the keyboard. If they have a gamepad, let them use the gamepad. If the user wants to use the app on their desktop with a regular 2D display, let them. Do not presume to know how the user will interact with the application. This early in development, not everyone will have all of the same hardware. Even into the future, it will be unlikely that an app will be successfully monetizable with a user base solely centered on those who have all of the requisite hardware to have a full VR experience. [font=inherit]Be maximally accessible.[/font]
[font=inherit] Make the application useful. This seems like it shouldn't be said, but ask yourself what would happen if you were to rip out the "VR" aspect of the application and have people use it with traditional IO elements. Treat the VR aspect of it as tertiary. Presence by its very definition means forgetting about the artifice of the experience. If the experience is defined by its VR nature, then it is actively destroying presence by reveling in artifice.[/font]
[font=inherit] Much research needs to be done on user input especially for large amounts of text. Typing on a keyboard is still the gold standard of text entry, but tying the user to the keyboard does not make for the best experience, and reaquiring a spatial reference to the keyboard after putting the headset on and moving away from the keyboard is nearly impossible. Too often, I find myself reaching completely behind in the wrong direction.[/font]
[font=inherit] 3D Audio is essential. We could mostly get away without audio in 2D application development, but in VR it is a significant component to sensing orientation and achieving presence. I believe it works by giving us a reference to fixed points in space that can always be sensed, even if they are not in view. Because you always hear the audio, you never lose the frame of reference.[/font]
[color=rgb(77,79,81)][font=Helvetica]
I may add to this later.[/font][/color]

capn_midnight

capn_midnight

 

Announcing Psychologist.js, a RAD HTML5 VR framework

I've written a little bit about this project for a little while, and I've finally decided on a name.

Psychologist.js is a framework for rapidly prototyping virtual reality applications using standard HTML5 technologies. It keeps you sane while bending your mind.

You can view a demo of the framework in action here.

You can access the repository on Github here.

Features:
Google Cardboard compatible: use your smartphone as a head-mounted display,
Multiplayer: share the experience and collaborate in cyberspace,
Leap Motion support: control objects with natural movement,
Game pad support: create fast-action games,
Speech recognition: hands free interactions,
Peer-2-peer input sharing: use devices connected to your PC with your Google Cardboard,
3D Audio: create fully immersive environments,
App Cache support: save bandwidth,
Blender-based workflow: no proprietary tools to learn,
Cross-platform: works in Mozilla Firefox and Google Chrome on Windows, Linux, and Android,
Oculus Rift support (coming soon): the cutting edge of head-mounted display technology.

capn_midnight

capn_midnight

 

I used to be a member here

This was me back then, in the year 2002:



And this is me now, 12 years later:





So what happened in between?

Well, after getting my degree in Computer Science, I ended up bouncing around between jobs. I've had--depending on how you count--6 to 8 jobs in the last twelve years. Most of them sucked. I got depressed from this, thinking it was my fault, that my work problems were because I didn't have the discipline to get out of bed in the morning. Turns out that there was a global conspiracy to give the middle class the shaft and I couldn't get out of bed in the morning because my bosses were universally assholes.

I flitted around the Mid-Atlantic region for a while. Living at home with my parents, renting a place with coworkers, living at home with my parents again, forcing myself out by moving to a completely different city, losing everything I owned in a flood, breaking up with almost all of my friends from childhood, getting fired for the first time from a job (for not looking like I was busy enough, despite the fact that my work provided most of the revenue to the company), living on friends couches and basements and spare rooms for a while, tusling with the decision of whether or not to become a fulltime alcaholic, experimenting with online dating--an experience that got too close to receiving violence on too many occasions for my liking--and just generally kissing the nose of complete destruction.

So I resolved I would always do things my own way and not have a boss ever again. I took about a 4 month sabbatical (and by that, I mean that is all the longer my unemployment benefits lasted, thus forcing me to find gainful employment) where I taught myself how to motivate myself for work. I sold t-shirts for a while. I made props for museums. I got some consulting gigs. I now have one major client who pays all my bills. I'm completely out of debt--no cars, no student loans, no credit cards.

And I got married to a woman who fills me with so much love and provides me with such an amazing base of rationality and sanity that it almost seems like the 10 years prior to her never even happened.

I now live with her just outside of our nation's capitol. I could be healthier, but overall, my life is really great now. I'm writing a lot lately, and I do a lot of photography and artwork when I'm not programming and actually finishing projects on a regular basis. I work from home, frequently not putting pants on all day. Most people in Northern Virginia either works for the government or works for a company that works for the government, people who I get to make extremely jealous with my beard, long hair, and carefree spirit. And that feels like winning.

So am I back? Sure, I guess you can call it something like that. Why am I here? I can't predict the future and know that I will post here regularly again. I only post this now because I see there are still some people here who would presumably remember my name and might have wondered what happened to me. I don't want to come in acting like "I'm an old, wisened master, bow before my wisening". I guess I'm here to learn again.

Here, this place, where I first learned.

capn_midnight

capn_midnight

 

Why I turned down a great job offer.

I recently received a very generous job offer from a rather prestigious company. I didn't even apply, they contacted me through LinkedIn. To say that I was honored to even receive a cold-contact from such a company is an understatement. "Flabbergasted" is a much more appropriate term.

The salary was great. There was an additional cash bonus of approximately "holy crap" dollars. There was also a stock grant of even more "are you freaking serious" dollars. The projects sounded right up my alley. And the managers sounded like good people. All around, it sounded great.

But I had to say no, for two specific reasons completely unrelated to compensation packages.

I'm an east-coast guy and they wanted me to move to the left coast.

My family is here and my wife's family is here. We specifically live in a place that is convenient for seeing our families on a regular basis. We had considered the possibility of moving, if the job presented a clear opportunity for significant career advancement. But we'd also like to have kids soon, and that's going to peg us even harder to only a few hours' drive from where the grandmas and grandpas live.

Also, I've spent the last two--almost three years working as a freelancer. The term "free-lance" comes from the great Scottish author Sir Walter Scott, referring to a sort of medieval mercenary, one whose "lance" was free of any sworn allegiance to any feudal lords. I've been incredibly productive during that time. The corporate desire to have people "on site" grows more and more alien to me every day. I know what work I'm capable of, and I think being self-directed and independent has markedly improved my output. To be asked to go to a specific place to do work in our now rather aged era of telecommuting feels like being asked to intentionally hobble myself for nothing more than someone else's convenience. I think the work is more important than that.

I'm not done with my current path.

I started freelancing for a reason. I was dissatisfied with my work-life relationship and I hoped I could one day create the sort of company that I have always wanted to work for. Freelancing is not an end to itself, but it is hopefully a means. The flexibility it affords is much closer to that ideal work life that I envisioned for myself than I've ever encountered before. I'm able now to work on my own R&D projects in addition to the freelancing with a focus and effort for which I had never had the adequate time while I was working as a 9-to-5 stiff. To take the job would be to give up on those plans, just as they are starting to show promise.

I take the mercenary notion of freelancing very seriously. I operate by my own ethic, one that places doing the right thing and doing the most important things above doing what I'm told. When a client hires me, they don't just buy my time, tapping on a keyboard at whatever they want. They buy my opinions and my taste regarding how work should be organized. Sometimes that can come across as defiance, but I do it out of respect for their needs as I see them, not as they are expressed in the heat of the moment.

Freelancing is a system that explicitly maintains that--at the end of the day--I own my own labor. It is the nature of corporate non-compete and non-disclosure agreements to capture and monopolize my labor as much as possible, for as little compensation as possible--indeed, why would a contractual agreement be necessary if the compensation were enough? And to make "my" company, I need to own my labor. While the NDA and Non-Competes weren't a major deciding factor in themselves to turning down the job, the prospect of what they meant for my personal projects certainly helped the decision along. It would essentially mean cancelling most of my projects. Their offer, while generous, was not quite that compelling.

I just couldn't do it.

Through out the interviewing process, I had this voice in the back of my head, chiding me, "it's a great job, you don't turn down such a good job." I'm sure working for this company would have been very rewarding. But I don't want a "job". I think I can do more. And I think I owe it to everyone involved to do so.

capn_midnight

capn_midnight

 

Icon pics

[disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed][disturbed]
[disturbed][disturbed][disturbed][disturbed]

capn_midnight

capn_midnight

 

Week of Awesome 2 - The Toys are Alive - #1

So Week of Awesome 2 starts on the day I have a half-day of job interviews and a demo of a product I'm working on. From 10:30am to about midnight tonight, I'm either driving somewhere or trying to present myself as awesome and totally not a slob at all. But tomorrow, I should be free for the rest of the week.

The theme is "The Toys are Alive". A title comes to mind, "Adult Toy Story". Nah, that's too obvious.

The key to a good game competition entry is to have a simple concept, executed well, completed early, to which "polish" is added with the remaining time. Yes, polish is a positive addition of things, like sprinkles on a cake. Also, to not neglect sound. Even the most basic sound instantly increases the quality of a submission 10-fold. One should stick to things one knows well. Venturing into new territory is a good way to get "stuck in the weeds" and fail to complete a submission.

With that in mind, I should probably be making a business intelligence suite, perhaps a series of reports demonstrating the effectiveness of a hospital full of toys. "Toy Hospital Administrator Simulator". I'm sure to win[1]!

Since I still don't have a real concept in mind after half an hour of typing, I'm going to continue to fill space with useless junk about strategy.

Ideas:
HTML5/JS game. I'm going to reuse my growing project template for doing HTML5 web apps. It's all just boilerplate stuff for loading bars, rounded corners on buttons, that sort of junk. Other people might use something like Angular or Bootstrap, but I am too old for that shit.
2D graphics. I'm still learning Three.js in my WebGL Virtual Reality[2] project, so I'm going to stick to what I know and do Canvas 2D instead of WebGL 3D.
3D audio. It's just so easy to do in modern browsers, why the hell not?
Mix of procedural and static content: Maybe a static level-select map and procedural levels.

Issues:
Figure out a proper concept to meet the theme
I don't currently have a good system for easily specifying and running keyframed 2D animations. Will have to figure something out here. Might be where I spend most of my time on this project.
I have simple boilerplate code for doing multiplayer stuff, but I feel like only a really good concept should have it. To add it as a gimmick would be detrimental.


Okay, that is all for now. I'll update this post here if I think of any concepts.



[1] Only if there is a "biggest Poindexter" award.

[2] Check it out. Star it. Follow it. Fork it and make contributions. Ask nicely and get direct commit access!

capn_midnight

capn_midnight

 

Optical Illusions in Computer Graphics #10

This is the last update!

The paper is finished. All done. Waiting on a grade.

In summary, the hypothesis that optical illusions could be used in a utilitarian fashion was correct. Using optical illusions I was able to convey information that users were able to effectively use to complete a task. Read the paper for more.

I had a lot of fun working on the project. Going out to Philladelphia for the research symposium was great. I will be submitting my paper to a research conference in the next week or so, my professor thinks it has a good chance of being accepted, so that's cool.

The project has already impressed quite a few important people. I recently talked with the President of a local software development company, who saw my project poster, and he was very interested in some of the things that I proposed from it.

I want to thank the staff of Gamedev for stickifying my Survey Thread (Oluseyi is the one who did it, I believe). Because of that, I collected 550 data points, which really made my data look nice and complete.

Things I learned from the project:

stretching out into other fields of expertise is recommended
test driven development ALWAYS saves time. You may feel like you are writing twice the code, but the truth is that you are spending half the time (total) writing it. ALWAYS test, THEN code. NEVER code before you test. Even if you think it's small. Just don't do it.
regression testing is kind of dirty, but it can get the job done in a pinch. For 2D applications, it may not be necessary in most cases, you should try to find a way around it.
never write java applets. applications are okay (but only just so), applets are garbage. I wonder how good flash is for web apps?
pace yourself and work is a breeze! keeping this journal over the course of the project really made the poster and the final paper a simple task.

So, if anyone out there has a job for a graduating computer science student that involves 2D graphics and making people dizzy, send me an email!

capn_midnight

capn_midnight

 

3H-GDC base code

The issue of base-code in the 3H-GDC. Here's why I think it should stay:


cheaters cheat, and I don't know how to stop them. So, allowing the base code elliminates their advantage.
beginners don't know how to code basic graphics, but they can probably figure out the logic. Complete noobs (dare I say, "nooblets"), can't figure out either, so they won't finish anything at all. With base code, perhaps it will encourage beginners (distinctly different than noobs) to stretch out and participate
I want the contest to be more about design and concepts than to be about coding prowress. I want some coding to occur, but one needn't be the next topcoder grand champion in order to win.


thoughts?

capn_midnight

capn_midnight

 

is that better?

The Greatest Scientific Genius in the Universe Washu doesn't like it that I don't ever mention him in my journals. Well guess what, NOW I HAVE! Mr. Hyperbole! Now you can't say I *never* mention you!

capn_midnight

capn_midnight

 

The Future of the 3H-GDC

Alright, so we just finished another wonderful contest, with the highest contestant participation yet. A total of 10 contestants and 8 submissions that came in on time. The submissions were actually all rather impressive for only 3 hours of work.

But where to take the 3H-GDC from here? It's starting to get really popular, and the prizes that were donated for this fourth one were really freaking expensive. I'm beginning to think it's time to get serious about the 3H-GDC.

How serious? Well, holding it regularly, having real corporate sponsors with really, really expensive prizes, having a real website with a real submission process. Basically, fixing everything that I do rather off the cuff right now.

Comments, suggestions? Please don't discuss the base-code issue here, I'm starting a new journal thread for it, as I do think it is a very important issue to get "right".

capn_midnight

capn_midnight

 

Enterprise Game Design - week 1 update

Got some work done. I've deleted the empty sections without renumbering the sections, so don't get confused when it jumps from section 4 to section 8.

1 Introduction
1.1 Purpose
This is a general software design for character-oriented, story-driven games, as distinctive from sports games, puzzle games, etc. The resulting game framework will be suitable for developing open-ended worlds with story-centric interactions. The primary emphasis is on interactive story telling, with a secondary emphasis on multiplayer interaction as an enhancement to the story telling system.
1.2 Document Conventions
As deterministic computers are incapable of true randomness, the distinction between pseudo-random and random is ignored. For this reason, the terms pseudo-random and random are used interchangeably throughout the document to refer to predictably repeatable pseudo-random sequence generation.
1.4 Suggested Reading and Game Playing

Plots Unlimited, Tom Sawyer, Arthur David Weingarten, 2004
The Writer's Journey: Mythic Structures for Writers, 2nd Edition, Christopher Vogler, 2007
Noctis v4.0, by Alessandro Ghignola.
The Elder Scrolls IV: Oblivion, from Bethesda Softworks.

2 Scope
2.1 Identifications
2.1.1 Need
Content creation is an expensive, time consuming process. Scripted content is also not as satisfying as "real content" to the consumer. The current state of the art in pseudo-random content generation has solved these problems for physical objects and environments. The problems of random story generation and robust interactive story telling have yet to be conquered.

By utilizing mathematical formulae to generate and reliably re-generate data that appears convincingly natural and organic, random content generation saves on content creation time in trade for research and development time. However, the trade is more than economical, as the random content generator is limited only by the restraints of computer memory systems. A good random content generator is able to generate quantities of data so vast that the user may reasonably assume it to be infinite.

Scripted content has the capacity to feel realistic during the user's initial experience, but quickly grows stale. Scripted content turns the game into a sort of "Game World Amusement Park", where the game attempts to provide each individual player with the same, repeatable experience. This is comparable to the way a roller coaster provides every amusement park customer with an identical, repeatable experience.

Conflict is the basis for plot and story progression. Conflict in reality is not scripted; it comes about through the clashing of opposing motivations. By creating a system in which story is dynamically generated through the simulation of the interaction between player characters and artificial intelligence actors, the system eliminates the "Amusement Park" aspect of game world interaction. It is the difference between riding through a constructed park of robotic animals and embarking on a real safari through untamed land.
2.1.5 Assumptions
The distinction between "client" and "server" are relative terms. Sinking the server into the client and removing the network stack should be sufficient to make a single-player game.
2.1.6 Constraints
The specific details of game play mechanics unrelated to story progression are left unanswered, to permit the story telling mechanic to be adaptable to any style of game play. Graphics, audio, and other user interface considerations will also not be covered in great detail, again for the sake of modularity. UI features will be a bare-minimum system necessary to demonstrate the capabilities of the framework.

For the sake of security and portability, and because of the lack of emphasis on UI, the Game Client portion of the design will be relative thin compared to the Game Server portion.
2.3 Known Risks
The creation of a gaming framework for any purpose, let alone a general purpose framework, is a monumental undertaking. Having no distinct game play or user interface characteristics requirements to limit the scope of the project greatly enhances the scale of the project. As this is being developed as a side project, time resources for it are very limited. Project failure due to stagnation, even after very significant resources have been spent on the project, is a distinct risk.

Currently, no dynamic story generation system of the scale proposed in this document exists on the market. While basic, automated story generation systems exist, they are far too simplistic for the purpose of this project. While more complex story generation processes also exist, they require far too much human interaction to be readily adaptable to an automated system. There is no evidence that such a large-scale dynamic story generation system is even possible. Striking out into new territory is always risky.
3 Requirements
3.9 Server
Server tasks are game-play-agnostic. The server has a semantic understanding of the game content, but does not care how that content is rendered.

. Maintain position in server cluster
. Manipulate data in a single dataset for the entire cluster
. Enforce game play rules
. Provide data to user on request
. Allow users to interact with each other
. Simulate other users as NPCs
. Take hot-updates - fixes while the server is still running
4.2 Server Environment
4.2.2 Microsoft Solution
Operating System: Microsoft Windows Vista 64 bit Ultimate Edition
Runtime Environment: Microsoft .NET v3.5
Database: [Microsoft SQL Server 2008| PostgreSQL 8.3.3]
4.2.3 Open Source Solution
Operating System: FreeBSD 7.0
Runtime Environment: [Java SE 6.0|Mono 1.9]
Database: PostgreSQL 8.3.3
8 Appendix B: Areas for Further Research

. Pen-and-paper RPGs
o GURPS
o DND 3.0, 3.5
o other
. Game Maker applications
o RPG
o MMO (does one exist)
o FPS
. Network Development
o As relates to MMOs
o How FPS shooters differ
o Encryption
. Games
o RPGs
? Neverwinter Nights
? The Elder Scrolls: Morrowind + Oblivion
? Mass Effect
? Etc.
o Sandbox Games
? GTA
? CrackDown
? Etc.
o Mod-able FPSes
? Half-Life 1+2
? Battlefield
. Scripting Systems
. AI Techniques for games
o Strategic vs. Active
. Pseudo-random content generation
o Terrain
o Cities
o Characters
o Stories
. Story-writing
. Spatial servers for game world data

capn_midnight

capn_midnight

 

Power Outage Fried My Computer

Yup, my main desktop was dead for about two weeks thanks to a power outage. I originally thought that it was just the hard drive, because I could boot it up, but it would die whenever I got to a certain point in loading Windows. After closer inspection, I have determined that the outage actually fried my graphics card (Radeon 9800 something something). The fan on the card's heat sink is siezed and the chip under the heat sink is charred around the edges. I've got an old 9200 SE in it's place right now, but it's giving me weird scanline issues and I can't change my display settings. Eh, whatever. I got my documents backed up to an external USB hard drive now, and I got the important documents burnt off to CD, so everything is safe.

Right now the desktop is operational, but I'm concerned that the reason the GPU was fried was because the mobo is faulty. This computer has always had problems of some type, from frying parts to never being able to properly handle a warm OS restart. If I perform a restart instead of a full shutdown cycle, it loses its secondary IDE channel and halts processing for about half a second about every 5 seconds. This isn't an OS issue, it did it to Linux and BSD, too. That, coupled with the fact that it has become prohibitively expensive to upgrade the memory (Rambus RDRAM, wooo), and it's clear that this computer just has to go.

I had been considering rebuilding it to a usable configuration and gifting it to a family member, but given the restart issue I don't think that is a workable solution as none of them will understand what is going on or how to fix it (just shut it down). It took me a year to figure out exactly what was going on, I don't want to leave that kind of bug for my grandmother or someone.

Incidentally, my laptop has hit a brick wall, too. It's running fine, but it's just not powerful enough to do the things I want to do. It's an old P3 1.2Ghz machine, but it uses an integrated Intel graphics chip, so it doesn't support the minimum specs for doing XNA development. When I got the laptop, even though it was literally half the specs of my desktop in every way (512mb of ram instead of 1gb, and a 1.2ghz processor instead of 2.4ghz, a 20gb hard drive instead of a 40gb hard drive, etc, etc), it had almost completely replaced my desktop because I could use it in the livingroom instead of having to retreat to the basement where I keep the desktops. Since XNA has replaced Hardware Accelerated Java2D for me, in everything from ease of development to support to performance, if my lappy can't do XNA, then it's pretty much worthless to me.

So right now, the only computer I have at my disposal is my work laptop. At least it seems to be working ok. Knock on wood.

capn_midnight

capn_midnight

 

WebRTC device syncing

WebGL VR

Big update today. When you use your PC in conjunction with your Smartphone, the two devices will communicate over your local network, rather than having to take a round trip through the game server. This reduces latency, so when you move your mouse, it updates in the display almost immediately.

capn_midnight

capn_midnight

 

incompetence

At work, I'm tasked with fixing some bugs in a pre-existing application. We didn't write the app, but our client really likes us, so they gave us the work. Also, the company that originally did the work went bankrupt, so there is that issue. Somehow, they stay in contact with the lead developer, even though he's now on his second new job since the bankruptcy.

This web app is a simple ledger accounting thing for all of the various local groups in the state to use to track taxing for our client. It's basically an online version of quickbooks for these groups. They can enter in a few different types of data. All told, it's actually rather small, the database is only about 20MB total.

First, it's written in Java. This isn't horrible, Java on the server is nowhere near as bad as Java on the desktop (at least the toolchain is mature). Whoever originally wrote this application must have been tripping on LSD. It's a bunch of JSP files that all include each other in one way or another. It's a lot like some hackish PHP (is there any other kind?) that I've seen.

Second, it's written for Java 1.3. We run it succesfully on Java 1.4, but I first have to rewrite a sizable portion of the data access code.

So far, none of this is really that bad. Well, what I mean is, it seemed really bad when I first started on the project, but recent events really take the cake.

About four weeks ago, we got to a point where we had to move to the client site to continue working, so that we had access to their infrastructure and development databases. When we get there, the one machine they have for the three of us to work on (luckily we rotate days) is literally falling apart. I hit the power button and the face plate fell off. The red and blue phosphours in the monitor are starting to die, so everything has a greenish tint. Oh, there's also some banding on the display as well. The space bar on the keyboard only works half of the time. I just reallized today that there is not a padded cushion on the side of the mouse, that's a thick layer of grime.

It's running Windows 2000 that probably hasn't been reimaged in 6 years. Internet Explorer can't open new windows, meaning we can't use Exchange Webmail to access or work email. The Windows Find utility won't open, it just sits there looking at you like you're some kind of retard. The security policies won't let me open the run prompt, but I can navigate to CMD and run that. We can't get certain plugins to install for Eclipse, because for some unknown reason the installer thinks we're running an incompatible version of Eclipse (yes,I've verified we have the right version, as well as verified on another machine that the plugins install properly).

My first task is to get the app running on this workstation. Tomcat is already installed, my boss did that the day before. He spent a few hours n vain trying to get it to run, though. I get there and find out that he doesn't have the required environment variables set, but only after spending a few hours crawling over the configuration files that I don't rightly understand (we have other people in the company to handle deployment, I just write the damn code).

My second task is to get the application running off of the IBM DB2 development database. I contact the DBA and ask him for the connection details. He is a bit reluctant at first, "why do you need to know that info?" but I explain to him that I'm working on bug fixes for the application. Okay, so he relents and gives me the info. I spend the next hour crawling the internet trying to figure out how to properly create a JDBC connection to a DB2 database (we are primarly an Oracle house, we've never used DB2 for anything, and I've certainly never touched it before). I finally find a very, very good walk through and start fiddling around. First things first, I use the command line tools to connect to the DB and look at the data. Great, everything's good. I write up the JDBC connection string (I'm starting to get the hang of this), slap it into my code to replace the in-memory database I had been using as a fill in, and restart the application server. Every time the app tries to connect to the DB, the damn thing stalls.

Crawling google, crawling google. I start to think that maybe my connection string is wrong, so I fiddle around with it. Unfortunately, I determine that I had it *right*, because any time it was explicitly *wrong," the app would throw an Exception (as one would expect, actually). It's only when I have the correct connection details that the app hangs on me.

I went out on the web looking for bug info on the jdbc drivers. So, I start by looking up version numbers. Excellent, the database is running v8.2.2 and my workstation has the v7.2.3 client installed. Google revealse that the 7.2.3 *thin client* driver has a bug that causes the application to hang when one attempts to connect to a higher version database. The *thick client* driver does not have this bug. The thick client driver is not well suited to the task (the second user to visit the site will not be able to use it because the next application context will not be able to load the drivers, as the thick client locks them once they are loaded), but for development I can work with it until we upgrade the client on the workstation.

After a while of working in this way, suddenly it stops working, I'm getting Access Denied errors. I can't even use the command line tools anymore, either. It's getting pretty late though, so I went home.

The next day, I get an angry call from the DBA, chewing me out for using the production database for development. Apparently it through a security flag and locked itself down, which prompted a few hundred managers across the state to call this them and complain when they couldn't login to do their daily work. I appologize profusely, and ask for the connection details to the development database. He replies "I still have to set it up." The project manager behind me turns to me and says "that was supposed to have been done weeks ago" and I agree, it was one of the conditions that had to be met before we would come work on site. So, I call my boss (well, I try to, I never reached him, but that's a different story), and we stop work. For the next week. It took the DBA an entire week to get the development database up and running. Luckily it was the week I was on vacation, so I didn't miss much.

At this point, I need to back up and take you down another branch in the story. Before the database locked itself down, I was able to get a good amount of work done. I came to a defect in the list that I couldn't quite figure out how to reproduce. So, after half an hour of phone calls, I eventually located someone that knew how to reproduce the bug. He showed me on the live application. While he is doing this, I'm noticing certain things, like the lack of certain bugs that I had made mental notes to fix. It's a little confusing, but I chalk it up to the fact that we hadn't been running on the DB2 database yet, maybe that was the source of the bugs. If only it were that simple.

While on vacation, I get a call from my boss. He has noticed the same thing, did a little checking on some file dates here and there, and reallized that *we didn't get the latest cut of the code*. Another work stop while the lackeys hunt down the latest code. They have no source control, and the last work done on the app was almost 2 years ago. After another week, they locate a number of different folders labeled as "backups". My boss looked through them briefly (he was heading out for a business trip, another client in North Dakota), and figured that one particular one looked like it might be the full code.

I get there today and start looking at it. There are 5 folders, and not a single one of them have the entire application. The full app is there, spread out in bits and pieces, but not all together. Additionally, some of the backup folders have newer files than others, all the changes overlap between the 5 folders. There are so many badly named backup folders and renamed files (main.jsp, main0.jsp, main.jsp.old, copy of main.jsp, you get the idea) that some files have as many as 9 distinct versions running around. All of the files have at least 3 versions, judging from file size and time stamp. So, I start piecing together a full application from the files with the latest time stamps (shit, windows find utility won't open). I get them all together, setup the application, and then reallize that these various backup folders might represent numerous different "forks" of the app from the LAST time they lost the latest source code.

I'm now in the process of trying to figure out what is the "real code." I started by comparing file sizes in bytes and time stamps. If both values are equivalent, then it's a pretty good bet that they are two copies of the same file. I now have anywhere from 3 to 9 copies of each file. I'm going through and running a file comparison utility (actually, I didn't know CMD had one until now, called FC.EXE) on them to see if files with different time stamps aren't duplicates. 9 versions of one file needs at most 8+7+6+5+4+3+2+1 = 36 comparisons (#1 to #2, #1 to #3, #1 to #4, ..., #7 to #9, #8 to #9). Multiply out by a few hundred files. It took me 6 hours to get through half of them. I still have the other half to go. I need to do it tonight so that the code is ready for the one other developer that is going to work on Saturday to try to make up some lost time.

capn_midnight

capn_midnight

 

3H-GDC Prize organization

So far:
1 month GDNet+ from capn_midnight
3 months GDNet+ from Fruny
1 year GDNet+ or an Amazon item of equal or lesser value from Prozac
1 year GDNet+ or a programming-related book retailing less than $100 (wow) from kSquared

capn_midnight

capn_midnight

 

AAGHH!

I am so pissed off right now, and this is why:



MOTHER OF PEARL! LINE THE HELL UP!!!

This is a mapping application that we are customizing for a client. They have a format of data called RPF that ESRI MapObjects is particularly bad at cacheing. However, we found an open source project called OpenMap that handles RPF data very well. So it should be a whiz-bang process to create a custom MobObjects layer (the MapObjects API supports this) that uses the OpenMap code to spit out images. Making a small application that did nothing but spit out images given a path to RPF data and the extents of the image was nothing, simple task. Writing custom MapObjects layers is also not a big deal, we do it all the time.l

EXCEPT OPENMAP DOESN'T DEFINE MAP EXTENTS IN ANY SANE MANNER!!!!

Typically, a map extent is defined as the min/max latitude and longitude. OpenMap on the other hand expects a center latitude and longitude, along with a map scale. Fine, whatever, except it completely ignores any concept of aspect ratio! But let's ignore that, let's just calculate the damn scale... wait, you CAN'T because a monitor's pixel-per-inch ratio is not fixed!

So, after much trial and error, I've come up with something that is a reasonable scale factor... I think. Panning the map left-right is good, panning it up-down is okay, but if you pan it diagonally you get this freaking fracturing of the image.

GHAKGHAKALHGAH!!!!!!!

capn_midnight

capn_midnight

 

Metal

So, I'm driving in my Fiji Blue 2008 Honda Civic Si to work at the Conservatory for Bad-Assery one morning along this really sick-ass section of road that runs along a cliff face plummeting down into this deep ravine full of rocks and trees and shit like out of a movie like Lord of the Rings or something, when this giant, fire-breathing dragon comes screaming in from deep, dark corner of the chasm, like it's some kind of chasm of despair, and starts hovering right in front of me on the road. I'm like, "ohshitohshitohfuckohshit" and really starting to freak out when I remember, "hey, I've got a fucking rocket launcher, I mean seriously, who doesn't amiright?" So, I hoist this rocket launcher up on my shoulder as I'm standing up out of my sunroof and blast a billboard on the side of the road, the billboard falls down, I punch the gas on my car and totally use the billboard to ramp up and over this gigantic dragon, like whoa, and the dragon is looking up at me as I'm flipping through the air and I can see the look in its eye, and the dragon is totally saying, "hoooolyyyyy shiiiiiit," and I'm all, "oooooh shiiiiit," and as I'm just over the dragon I say "yooooou shall not paaass" and I shoot my biggest heat seeking rocket right at the dragon's tonsils. The rocket flies right down his throat and EXPLODES in his stomache, raining down this mass of blood and guts and bubbles and jet fuel and shit everywhere.


It was fucking metal.

capn_midnight

capn_midnight

 

IEEE Float Suck

IEEE standard floating point numbers, at any bit depth, should not be used to define color spaces. Specifically, one should not use floats or doubles (henceforth collectively "floats") as color components when rendering High Dynamic Range Imagery (HDRI). Due to the nature of the representation of floats, they cannot be used to define uniform color spaces.

The IEEE standard for floating point numbers defines a 32 bit float as a 1 bit sign value, an 8 bit biased exponent value, and a 23 bit fraction value. The exponent is "biased" in that it represents an integer value from which the value 127 is subtracted, to give a real range of exponent values from -127 to +127. The fraction is the fraction portion of a number expressed in "floating point binary notation".

There are 6 reserved values

0 00000000 00000000000000000000000 = 0
1 00000000 00000000000000000000000 = -0

0 11111111 00000000000000000000000 = Infinity
1 11111111 00000000000000000000000 = -Infinity

0 11111111 00000100000000000000000 = NaN
1 11111111 00100010001001010101010 = NaN

Any value that uses a full bit field for the exponent value is a non-number with the IEEE representation. With this exponent, and a 0 fractional value, it is interpreted as signed infinity. With a non zero fractional value, it is interpreted as Not A Number. Because of this interpretation, there are a full 2**24 unusable values when using floats as color components.

For example, the number -32.5625 would be converted as

S = 1, as the number is negative
temp = 100000.1001, "floating point binary representation"
= 1.000001001 x 2**5
E = 5 + 127 = 132
= 10000100
F = 000001001, drop the "1." from representation
= 00000100100000000000000, padded with zeros

Full number:
1 10000100 00000100100000000000000

The problem with color spaces lies in calculating the difference between two "consecutive" floats, i.e. floats that differ only in their least significant bit. Color is equally dependant on the relationship between two very similar colors as it is on the absolute value of a single color. Without thinking about the problem, one might think that this difference is very small, as floats are capable of representing very small numbers. However, once we start calculating the exact decimal value of the float representation boundary cases, we see that the difference between "consecutive" floats is dependant on the actual value of the numbers.

As an example, I've constructed a "4bit IEEE-like floating point number." It has no sign bit; a positive, 2 bit, unbiased exponent (so translating the exponent is not necessary, as with 32 or 64 bit floats); and a 2 bit fraction. Otherwise, calculating the value follows the same rules as regular IEEE floats. The purpose of using such a limited example is to allow us to see the full range of values that can occur for a specific representation.

bin | sci not |fp bin| dec | delta
========================================
0000 | 1.00 x 1 | 1.00 | 1 | -
0001 | 1.01 x 1 | 1.01 | 1.25 | 0.25
0010 | 1.10 x 1 | 1.10 | 1.5 | 0.25
0011 | 1.11 x 1 | 1.11 | 1.75 | 0.25
0100 | 1.00 x 2 | 10.0 | 2 | 0.25
0101 | 1.01 x 2 | 10.1 | 2.5 | 0.5
0110 | 1.10 x 2 | 11.0 | 3 | 0.5
0111 | 1.11 x 2 | 11.1 | 3.5 | 0.5
1000 | 1.00 x 4 | 100 | 4 | 0.5
1001 | 1.01 x 4 | 101 | 5 | 1
1010 | 1.10 x 4 | 110 | 6 | 1
1011 | 1.11 x 4 | 111 | 7 | 1
1100 | 1.00 x 8 | 1000 | 8 | 1
1101 | 1.01 x 8 | 1010 | 10 | 2
1110 | 1.10 x 8 | 1100 | 12 | 2
1111 | 1.11 x 8 | 1110 | 14 | 2

What this shows us is that the difference in values in the range of floating point numbers is not fixed.

Next, we will calculate the exact decimal value that two "consecutive" floats represent. These numbers are the 2nd-largest and largest possible, positive floats.

2nd largest 32 bit float
Binary: 01111111011111111111111111111110
Sign: 0
Exponent: binary 11111110 - 01111111 = 254 - 127 = 127
Fraction: 11111111111111111111110 = 2**24 - 2
Binary scientific notation: 1.11111111111111111111110 x 2**127
Decimal: 3.4028232635611925616003375953727e+38
Equivalent: 2**128 - 2**105

largest 32 bit float
Binary: 01111111011111111111111111111111
Sign: 0
Exponent: binary 11111110 - 01111111 = 254 - 127 = 127
Fraction: 11111111111111111111110 = 2**24 - 1
Binary scientific notation: 1.11111111111111111111111 x 2**127
Decimal: 3.4028234663852885981170418348452e+38
Equivalent: 2**128 - 2**104

Difference: (2**128 - 2**104) - (2**128 - 2**105) = 2**105 - 2**104 = 2**104 = 20282409603651670423947251286016
or roughly
2.0282 x 10**31

We can do the same calculations for the difference between the two smallest numbers and come up with a difference of 2**-150, or an extremely small number.

Using floats to define a color space will result in a non-uniform color space. There will be a lot of subtlety in the middle of the range, and giant leaps between values at the ends of the range. In the end, there are really only 2**32 - 2**24 unique and usable 32 bit floats (as was previously demonstrated) unique and usable 32 bit floats, because of the 5 "special values" that the IEEE float specification defines for values such as plus or minus infinity. Just these special values alone limit the expressive power of floats in defining a color space.

Unsigned integers work much better for defining color spaces, as there are a full 2**32 unique and usable values, and the difference between the largest two integers is the same as the difference between the smallest two integers: only 1.

capn_midnight

capn_midnight

 

so busy

well, I've been quite busy lately.

Two weeks ago, I started a new job working on a GIS web portal. Right now, I'm running through QA testing, oh joy, oh rapture, take me now. I HAVE NEVER BEEN SO FREAKING BORED IN MY LIFE!!!

On occasion, I get to write some code. It's funny, I was hired because I knew how to program C# using the features of .Net, and I had some experience with the eXtreme Programming methodology, which they are transitioning to (from what, I don't know, maybe CBTSOYP).

Transitioning to XP, my ass. They are flat out RESISTING it. Absolutely NO pair programming. Tasks are assigned, not volunteered. Strangely, we ARE doing the morning standup meetings. Almost no unit testing, and certainly no test driven development. I wrote a single class the other day and quadrupled the number of unit tests in the entire project, and it wasn't a large class (it handled adding and retrieving URLs from a DB). And yet, they find themselves with the problems that XP is meant to prevent (breaking large portions of functionallity when refactoring, ensuring that components integrate properly, etc), and wonder why.

(I need to cut this short, at work *right now*)

Some of you have probably already read "wasting time, but getting paid for it, so it's okay". So you'll know that little bit of code that I got to write is basically 50% wasted. I can reuse the DB code, since it's essentially the same data, I can reuse the data retrieval module (thankfully, that's the class that quadrupled the number of tests). But I have to completely rewrite the UI and the business logic, and add on top of that an RSS aggregator. Oh, did I mention that our "client" stipulates that we cannot use any OSS of any kind? (not that *I* mind, but I think the VP won't like the fact that I'm going to have to spend a few days reimplementing something that could be just dropped in).

I went to Miami, Florida to visit a friend and just generally party for 5 days. It was great, I took pictures.

I've gotten no work on projects done since starting this new job. It's about an hour drive to and from work, so by the time I get home I just want to eat, relax, and get to bed by 10pm so that I can get up at 5am and start over again. I hope it doesn't stay like this.

My flipping computer died. I think it's the hard drive. Luckily I keep all my docs on the secondary drive. And I don't have any money... I still need to buy a car and pay off my student loans. Someone kill me now.

capn_midnight

capn_midnight

Sign in to follow this  
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!