August 22, 2012

What Is A Right Answer?

I find that modern culture is often obsessed with a concept of wrongness. It is a tendency to paint things in a black and white fashion, as if there are simply wrong answers and right answers and nothing in-between. While I have seen this in every single imaginable discipline (including art and music, which is particularly disturbing), it is most obvious to me in the realm of programming.

When people aren't making astonishingly over-generalized statements like trying to say one programming language is better than another without context, we often try to find the "best" way to do something. The problem is that we don't often bother to think about exactly what makes the best answer the best answer. Does it have to be fast? If speed was the only thing that was important, we'd write everything in assembly. Does it have to be simple? I could list a thousand instances were simplicity fails to account for edge-cases that render the code useless. Does it have to be easy to understand? If you want something to be easy to understand, then the entire C standard library is one giant wrong answer that's being relied upon by virtually every single program in the entire world.

For a concept taken for granted by most programmers, defining what exactly makes an implementation "optimal" is incredibly difficult. A frightening number of programmers are also incapable of realizing this, and continue to hang on to basic assumptions that one would think should hold everywhere, when very few of them actually do. Things like "the program should not crash" seem reasonable, but what if you want to ensure that a safety feature crashed the program instead of corrupting the system?

The knee-jerk reaction to this is "Oh yeah, except for that." This phrase seems to underlie many of the schisms in the programming community. Virtually every single assumption that could be held by a programmer will be wrong somewhere. I regularly encounter programmers who think you should do something a specific way no matter what, until you ask them about making a kernel. "Oh yeah, except for that." Or a sound processing library. "Oh yeah, except for that." Or a rover on mars. Or a video decoder. Or a raytracer. Or a driver. Or a compiler. Or a robot. Or scientific computing.

All these except-for-that's betray the fundamental failure of modern programming culture: There is no right answer. The entire concept of Right and Wrong does not belong in programming, because you are trying to find your way to a solution and there are billions of ways to get there, and the one that works best for your particular situation depends on hundreds of thousands of independent variables. Yet, there is a "right answer" on Stack Overflow. There are books on writing "proper code". There are "best practices". People talk about programming solutions that are "more right" than others. There are black and white, right and wrong, yes or no questions pervading the consciousness of the majority of programmers, who foolishly think that you can actually reduce an engineering problem into a mathematical one, despite overwhelming evidence that you simply cannot escape the clutches of reality and how long it takes an electron to reach the other side of a silicon wafer.

If you ask someone how to do something the right way, you are asking the wrong question. You should be asking them how to solve your problem. You didn't do something the wrong way, you simply solved the wrong problem.

August 19, 2012

An Artist Trapped Inside A Software Engineer

Almost a decade ago, I thought I wanted to make games. I began building a graphics engine for that purpose, since back then, there were almost no open-source 2D graphics engines using 3D acceleration. It wasn't until later that I discovered I liked building the graphics engine more than I liked building games.

Times have changed, but I continue to tinker away on my graphics engine while going to college and learning just how dumb the rest of the world is. In the most recent bout of astonishing stupidity, my country has decided it doesn't recognize political asylum for people it doesn't like. It wasn't until reality had begun a full-scale assault on my creativity and imagination that I truly understood why artists feel compelled to lose themselves in their imaginations.

My imagination. It is something I could not possibly describe in any meaningful way. Art exists because some things can't be described, they must be shown. And yet, few things in my imagination are my own. I hunt down talented artists and visionaries, lose myself in the worlds they constructed, then take everything out of context and reconstruct my own worlds, perhaps based on another artist's vision, using the same concepts. I construct multiple visualizations, art styles, and game elements. My mental stage is fueled by awesome music, music that launches my imagination into incredible creative sprees. Sometimes I craft incredible melodies of my own, but rarely are they ever truly expressed in any satisfactory way in my music.

My life is one of creative frustration. I became obsessed with computer graphics as a way to realize my vision, but I wasn't interested in simply learning how to 3D model (which I happen to be terrible at, like everything else). I don't see the world as CGI, I see the world through the lens of a GPU. I look at things and ask, how might I render that? My imagination is not a static picture or movie, its a world that is meant to be explored. Sometimes I play games for the storyline, or the gameplay, but the one thing that has always grabbed me is the ability to explore. I played Freelancer for 5 years, installed hundreds of mods, and was constantly enthralled simply by the exploration, the enormous universe, finding new systems, and discovering new places.

I can't draw a leaf. But I can create a mathematical model of it. I can calculate the textures and patterns, the branching veins and how each has their own specular, diffuse and transfer lighting functions. I can build abstractions and simulations, genetic recombinations and simplex noise algorithms. After I build tools to procedurally generate all the elements of a world, maybe then I can bring my imagination to life. But then, it's not really my imagination, it's what other artists inspire in me. I want to get as close to an artistic vision as possible, and beyond. I want to expand their artistic ideas and make them into something that is truly beautiful and inspiring, a clear extension of their vision, where it's soul shines like a beacon instead of being buried under bureaucratic bullshit.

I am an artist who cannot draw. I'm a musician incapable of painting the sonic landscape of my imagination. I am a dreamer who has no dreams of his own. If I am a programmer, it is because programming is the only way for me to express my creativity. But programming itself is not simply a means to an end. Programming is my paintbrush, my canvas, and my palette. I know how to read x86 assembly. I have abused C++11 lambdas to create temporary closures that hold a mutable state. I've crafted architectures and APIs and object-inheritance schemes and functional undo/redo stacks and lockless queues and kd-trees. Programming is my art and my music, and every new language or algorithm I explore is another instrument for me to use when building my symphony.

Yet, many programmers hold little respect for alternative opinions. People who don't conform to strict guidelines are viewed as either terrible programmers or "cowboy" programmers destined to bring ruin to every project they touch. Everything must follow protocol, everyone must do things this way or that way. Instead of celebrating our diversity in programming languages, we viciously attack each other for using a "terrible language". Perhaps I have simply been inside a strange anomaly where everyone is obsessed with corporate practices and coding standards instead of building things.

Or perhaps I'm an artist trapped inside a software engineer.

July 25, 2012

Coordinate Systems And Cascading Stupidity

Today I learned that there are way too many coordinate systems, and that I'm an idiot (but that was already well-established). I have also learned to not trust graphics tutorials, but the reasons for that won't become apparent until the end of this article.

There are two types of coordinate systems: left-handed and right-handed coordinate systems. By convention, most everyone in math and science uses right-handed coordinate systems with positive x going to the right, positive y going up, and positive z coming out of the screen. A left-handed coordinate system is the same, but positive z instead points into the screen. Of course, there are many other possible coordinate system configurations, each either being right or left-handed; some modern CAD packages have y pointing into the screen and z pointing up, and screen-space in graphics traditionally has y pointing down and z pointing into the screen.

If you start digging through DirectX and OpenGL, the handedness of the coordinate systems being used are ill-defined due to its reliance on various perspective transforms. Consequently, while DirectX traditionally uses a left-handed coordinate system and OpenGL uses a right-handed coordinate system, you can simply use D3DPerspectiveMatrixRH to give DirectX a right-handed coordinate system, and openGL actually uses a left-handed coordinate system by default on its shader pipeline - but all of these are entirely dependent on the handedness of the projection matrices involved. So, technically the coordinate system is whichever one you choose, but unlike the rest of the world, computer graphics has no real standard on which coordinate system to use, and so its just a giant mess of various coordinate systems all over the place, which means you don't know what handedness a given function is for until things start getting funky.

I discovered all this, because today I found out that, for the past 6 or so years (the entire time my graphics engine has ever existed in any shape or form), it has been rotating everything backwards. I didn't notice.

This happened due to a number of unfortunate coincidences. For many years, I simply didn't notice because I didn't know what direction the sign of a given rotation was supposed to rotate in, and even if I did I would have assumed this to be the default for graphics for some strange reason (there are a lot of weird things in graphics). The first hint was when I was integrating with Box2D and I had to reverse the rotation of its bodies to match up with my images. This did trigger an investigation, but I mistakenly concluded that it was Box2D that had it wrong, not me, because I was using atan2 to check coordinates, and I was passing them in as atan2(v.x,v.y). The problem is that atan2 is defined as float atan2(float y, float x), which means my coordinates were reversed and I was getting nonsense angles.

Now, here you have to understand that I was currently using a standard left-handed coordinate system, with y pointing up, x pointing right and z into the screen. The thing is, I wanted a coordinate system where y pointed down, and so I did as a tutorial instructed me to and reversed all of my y coordinates on the low-level drawing functions.

So, when atan2(x,y) gave me bad results, I mistakenly thought "Oh, i forgot to reverse the y coordinate!" Suddenly atan2(x,-y) was giving me angles that matched what my images were doing. The thing is, if you switch x and y and negate y, atan2(x,-y)==-atan2(y,x). One mistake had been incorrectly validated by yet another mistake, caused by yet another mistake!

You see, by inverting those y coordinates, I was accidentally reversing the result of my rotation matrices, which caused them to rotate everything backwards. This was further complicated by how the camera rotates things - if your camera is fixed, how do you make it appear that it is rotating? You rotate everything else in the opposite direction! Hence even though my camera was rotating backwards despite looking like it was rotating forwards, it was actually being rotated the right way for the wrong reason.

While I initially thought the fix for this would require some crazy coordinate system juggling, the actual solution was fairly simple. The fact was, a coordinate system with z pointing into the screen and y pointing down is still right-handed, which means it should play nicely with rotations from a traditional right-handed system. Since the handedness of a coordinate system is largely determined by the perspective matrix, reversing y-coordinates in the drawing functions was actually reversing them too late in the pipeline. Hence, because I used D3DXMatrixPerspectiveLH, I had a left-handed coordinate system, and my rotations ended up being reversed. D3DXMatrixPerspectiveRH negates the z-coordinate to switch the handedness of the coordinate system, but I like positive z pointing into the screen, so I instead hacked the left-handed perspective matrix itself and negated the y-scaling parameter in cell [2,2], then undid all the y-coordinate inversion insanity that had been inside my drawing functions (you could also negate the y coordinate in any world transform matrix sufficiently early in the pipeline by specifying a negative y scaling in [2,2]). Suddenly everything was consistent, and rotations were happening in the right direction again. Now the Camera rotation actually required the negative rotation, as one would expect, and I still got to use a coordinate system with y pointing down. Unfortunately it also reversed several rotation operations throughout the engine, some of which were functions that had been returning the wrong value this whole time so as to match up with the incorrect rotation of the engine - something that will give me nightmares for weeks, probably involving a crazed rabbit hitting me over the head with a carrot screaming "STUPID STUPID STUPID STUPID!"

What's truly terrifying that all of this was indirectly caused by reversing the y coordinates in the first place. Had I instead flipped them in the perspective matrix itself (or otherwise properly transformed the coordinate system), I never would have had to deal with negating y coordinates, I never would have mistaken atan2(x,-y) as being valid, and I never would have had rotational issues in the first place.

All because of that one stupid tutorial.

P.S. the moral of the story isn't that tutorials are bad, it's that you shouldn't be a stupid dumbass and not write unit tests or look at function definitions.

June 22, 2012

How Joysticks Ruined My Graphics Engine

It's almost a tradition.

Every time my graphics engine has been stuck in maintenence mode for 6 months, I'll suddenly realize I need to push out an update or implement some new feature. I then realize that I haven't actually paid attention to any of my testing programs, or their speed, in months. This is followed by panic, as I discover my engine running at half speed, or worse. Having made an infinite number of tiny tweaks that all could have caused the problem, I am often thrown into temporary despair only to almost immediately find some incredibly stupid mistake that was causing it. One time it was because I left the profiler on. Another time it was caused by calling the Render function twice. I'm gearing up to release the first public beta of my graphics engine, and this time is no different.

I find an old backup distribution of my graphics engine and run the tests, and my engine is running at 1100 FPS instead of 3000 or 4000 like it should be. Even the stress test is going at only ~110 FPS instead of 130 FPS. The strange part was that for the lightweight tests, it seemed to be hitting a wall at about 1100 FPS, whereas normally it hits a wall around 4000-5000 due to CPU⇒GPU bottlenecks. This is usually caused by some kind of debugging, so I thought I'd left the profiler on again, but no, it was off. After stepping through the rendering pipeline and finding nothing, I knew I had no chance of just guessing what the problem was, so I turned on the profiler and checked the results. Everything seemed relatively normal except-
PlaneShader::cEngine::_callpresent       1.0    144.905 us   19%        145 us   19%
PlaneShader::cEngine::Update             1.0     12.334 us    2%        561 us   72%
  PlaneShader::cEngine::FlushMessages    1.0    546.079 us   70%        549 us   71%
What the FUCK?! Why is 70% of my time being spent in FlushMessages()? All that does is process window messages! It shouldn't take any time at all, and here it is taking longer to process messages than it does to render an entire frame!
bool cEngine::FlushMessages()
{
  PROFILE_FUNC();
  _exactmousecalc();
  //windows stuff
  MSG msg;

  while(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
  {
    TranslateMessage(&msg);
    DispatchMessageW(&msg);

    if(msg.message == WM_QUIT)
    {
      _quit = true;
      return false;
    }
  }
  
  _joyupdateall();
  return !_quit; //function returns opposite of quit
}
Bringing up the function, there don't seem to be many opportunities for it to fail. I go ahead and comment out _exactmousecalc() and _joyupdateall(), wondering if, perhaps, something in the joystick function was messing up? Lo and behold, my speeds are back to normal! After re-inserting the exact mouse calculation, it is, in fact, _joyupdateall() causing the problem. This is the start of the function:
void cInputManager::_joyupdateall()
{
  JOYINFOEX info;
  info.dwSize=sizeof(JOYINFOEX);
  info.dwFlags= [ Clipped... ];

  for(unsigned short i = 0; i < _maxjoy; ++i)
  {
    if(joyGetPosEx(i,&info)==JOYERR_NOERROR)
    {
      if(_allbuttons[i]!=info.dwButtons)
      {
Well, shit, there isn't really any possible explanation here other than something going wrong with joyGetPosEx. It turns out that calling joyGetPosEx when there isn't a joystick plugged in takes a whopping 34.13 µs (microseconds) on average, which is almost as long as it takes me to render a single frame (43.868 µs). There's probably a good reason for this, but evidently it is not good practice to call it unnecessarily. Fixing this was relatively easy - just force an explicit call to look for active joystick inputs and only poll those, but its still one of the weirdest performance bottlenecks I've come up against.

Of course, if you aren't developing a graphics engine, consider that 1/60 of a second is 16666 µs - 550 µs leaves a lot of breathing room for a game to work with, but a graphics engine must not force any unnecessary cost on to a program that is using it unless that program explicitly allows it, hence the problem.

Then again, calculating invsqrt(x)*x is faster than sqrt(x), so I guess anything is possible.

May 29, 2012

Answers To All The Questions I Asked As A Kid

When I was growing up and trying to figure out what was going on in this crazy planet I was born on, there were several important questions I asked that took many, many years to find answers to. What was frustrating is that almost every single answer was usually extremely obvious once I could just find someone who actually knew what they were talking about. So here are the answers to several simple life questions that always bugged me as a kid, based on my own life experiences. Many people will probably disagree with one or two things here, which is fine, because I don't care.

1. What is the purpose of Math?

Math is simply repeated abstraction and generalization. All of it. Every single formula and rule in mathematics is derived by generalizing a simpler concept, all the way down to the axioms of set theory. It was invented to make our lives easier by abstracting away annoying things. Why count from 2 to 6 when you can simply add 4? Adding is simply repeated counting, after all. But then, if you can add 4 to 2 and get 6, you should be able to generalize it so you can add 4 to 2.5 and get 6.5, and what about adding 2 to 4 over and over and over? Well that's just multiplication. What about multiplying 2 over and over and over? Well that's just exponentiation. What's that funky Gamma Function I see every now and then? That's simply the factorial ($5! = 5\cdot 4\cdot 3\cdot 2\cdot 1$) generalized to real and complex numbers, so it can evaluate 5.5!, its just written Γ(5.5 - 1) = Γ(4.5). Math is generalization.

Usually smart people figured all the generalizations out for you, so in some cases you can simply memorize a formula or look it up, but its much easier to simply remember the rules that the smart people figured out for you so you can rederive everything you need without having to memorize it. When you understand the rules (which are all carefully constructed to be consistent with each other), you can then use Mathematics as a language to express problems in. By abstracting the problem into mathematics, the answer becomes much easier to obtain. The only thing math does is make thing easier to do by abstracting them. That's all.

2. Why does college think high grades in math correspond to programming ability?

This is because programming is math. Programming is all about abstracting a problem to automate it. Think of it as a lingual descendant of Math. The problem is that in high school they teach you calculus and programming at the same time and try to tell you that they are related. They aren't. Calculus doesn't have anything to do with programming. Set Theory does. The mathematical constructs of logic are what programming derives from, not calculus. Naturally, they don't teach you any of that. Even though you can consider programming a sub-discipline of mathematics, ones programming ability is not connected to your test-taking abilities.

3. How do you compose music?

First, you come up with a melody. The best way to do this is to find a song you like, and figure out its melody. Knowing basic music theory will help, because then you know what a chord progression is, so you can find that too. Simply rip off all the common chord progressions you like - you'll come up with your own later. Rhythm is important too, so take note of that - be careful to focus on notes that seem to carry the beat.

Great, that was the easy part. But how do you make techno music? How do you record things? How does it get on a computer? All I have is this stupid electric piano I can record things off of, there has to be a better way! The answer is DAWs and VSTi, or Digital Audio Workstations and their virtual instrument plugins. A great DAW to start with is FL Studio, and there are a lot of free VSTi plugins floating around. VSTi plugins are simply synths or effects or other tools that you drop into your DAW and use to play notes or modify the sound. If you want natural sounding instruments, use samples. Soundfonts are widely supported, have an extension .sf2 and there are gigabytes upon gigabytes of free samples everywhere. You should try to hunt down an independent artist whose music you like, they'll often be willing to give on advice on how they create their style.

But now I've made a song, where do I post it? Soundcloud, newgrounds, last.fm, and bandcamp lets you sell it for moneys. Don't worry if you're terrible, just keep doing it over and over and over and paying attention to advice and constructive criticism.

4. How do you draw clean art?

Clean digital art is commonly done using vectorization and gradients. There are multiple photoshop techniques that can be combined with tablets to create very nice looking lines by doing fake-tapering and line adjustments, but more commonly the tablet is simply pressure sensitive. There are many different techniques for doing various styles, so its more appropriate to ask the artist themselves.

5. Why do adults kiss?

I say instinct but no one really knows yet (only 90% of humans kiss). Provided you are in a culture that does kiss, you'll grow up to be around 16-17 and suddenly you'll feel this inexplicable urge to kiss whomever you've fallen in love with for no apparent reason. It's theorized to have arisen due to needing to evaluate certain proteins in a potential partner, which requires physical contact, along with various other things. I say instinct because I always thought it wasn't instinct and I wouldn't fall for it and then why am I fantasizing about kissing girls CRAP.

6. Why do adults fall in love in the first place?

Instinct. By the time you are 20, if you haven't yet found an intimate partner, you will feel crushing loneliness regardless of how many friends you have. Do not underestimate just how badly Nature wants you to have babies. This is why people get desperate - the desire to be in an intimate, loving relationship can be extremely powerful. It also leaves a giant hole that often explains various other bizarre things adults do in apparent attempts to kill themselves in the most amusing way possible.

7. Why don't popular people respond to fan mail very often?

This usually only comes up if you are using a bad medium. Artists often want to talk to their non-retarded fans, but the majority of people are incredibly stupid (see below), and thus in certain cases the signal-to-noise ratio is so high they simply can't justify spending the time to find you in a sea of insane idiocy when they have better things to do, like be awesome. Some artists simply don't want to be bothered, and this is usually the result of being disillusioned with how utterly stupid most people are, so it's hard to blame them, but unfortunate. Usually there will be a way to at least throw a meaningful thank you to the artist, possibly by e-mail or twitter if you look hard enough, and they will always appreciate it if they can just find your message. Never assume an artist is too stuck up and full of themselves to answer you. They just can't find you. Although quite a few of them actually are assholes.

8. Why is everything I do always wrong?

Because people are idiots and have no idea what they're talking about. Only ever listen to someone telling you that you are doing something wrong if you know they have extensive experience in exactly what you are trying to do. Otherwise, take the advice with a mountain-sized lump of salt, because people in specialized professions almost always take advice out of context and inappropriately simplify it to the point of it actually being completely wrong. There is always a catch. This is taken up to eleven in programming - I once had someone who did networking tell me my choice of language for my graphics engine was completely wrong and insisted I was so bad at programming I should just stop, because it would make the world a better place. He is an asshole, and he is completely wrong. Don't listen to those people, ever.

9. Why does everyone call everyone else an idiot?

BECAUSE EVERYONE IS AN IDIOT. Trying to comprehend just how unbelievably stupid people can be is one of the most difficult things to learn while growing up. It's far too easy to disregard someone as evil when in fact they really are that dumb. "Never attribute to malice that which is adequately explained by stupidity" - Hanlon's Razor. The best you can hope to do is dedicate your life to not being an idiot in your choice of profession and don't think it makes you qualified to give advice on vaguely related fields (see networking programmer above).

10. Why do adults argue about everything?

Because they are 10-year-olds that have to pay taxes, and nobody really knows how to pay taxes properly. They don't know what they're doing. Common sense is not common, people are not rational, and people are idiots. They don't care if they're wrong, and they don't care if you're right. They just don't care, because life sucks, and life isn't fair, and they didn't get the memo until after they wasted their youth either being too drunk to remember anything, or studying in a library all day to get a useless scrap of paper.

Do something that matters to you, and know this: Life isn't fair, so you have to make it fair. You have to do things the hard way. You have to fail miserably hundreds of times and keep on trying because you aren't going to let life win. You have to do what matters to you, no matter what anyone else thinks. You have to fight for it, and you have from now until you die to win. Go.

Cheat Codes

1. If you don't know how to properly socialize with someone, ask them about themselves. There is nothing people love more than talking about themselves.
2. If you like programming, bury yourself in it. It is, by far, the most useful skill you can have right now.
3. Read the instructions.
4. Bunnies make everything better =:3