Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Everything posted by aregee

  1. I thought I would tip you off to these excellent videos that explains what you are asking about.  You will see why the data probably is already in the processor by the time the CPU executes the instructions needing those registers.    
  2. aregee

    Too clever...?

    Just writing a simple string tokeniser from scratch, when I came to a "clever" realisation when it comes to bounds checking.   Say you have a string of a certain length, and you want to find a token within a section of the string, you would provide an index for the first character position you want to search from and another index for the last character in the string you will be looking.   Then you need to verify the sanity of these values.   The immediate way to do that would be to just check each first and last bounds to the length of the string and check that the last bound index is not before the first.   Then I came up with the following optimisation: static inline int findToken(const int firstIndexInclusive, const int lastIndexExclusive, const std::string string, const std::string oneOfChars) { unsigned long stringLength = string.length(); if ((firstIndexInclusive < 0) || (lastIndexExclusive > stringLength) || (lastIndexExclusive < firstIndexInclusive)) { return -1; } //searching for occurence of any of the 'oneOfChars' here return 0; } Just three tests accounts for all the boundaries that you would normally check against, which in normal cases I would probably have 5 checks for.   After the first bit of cleverness subsided, it came to me that the readability goes down, the optimisation is rather minor unless if I process a lot of text, although the time I spent making this was not much.  Besides, I think that if you do obvious optimisations while you write code, that is a good thing, but the readability factor is an issue to me.   What do you think?  Is this premature optimisation?
  3. aregee

    When you realize how dumb a bug is...

      Why the heck would somebody declare a variable that is a lowercase 'L'?  I'd be mad at the single letter variable name declaration.      I'm more curious to know why one would type the lowercase L instead of the 1 in the first place, given that at least on a QWERTY keyboard they're practically on opposite sides of the keyboard.     I was thinking the programming world's version of a troll.  :D
  4. aregee

    Too clever...?

      Oh dear.  :D  Yes, that is overly clever.  Not sure if it is any more efficient though.  The first one seems to even have a bit more overhead than 5 if tests, the second one gives me a feeling to be at best just as good.  I don't know the underlying behaviour of either is_sorted or the Python style chained comparisons, though.
  5. aregee

    Too clever...?

      Yes, you are right.  I was thinking to myself that if I made them unsigned, I wouldn't even need the test for 'less than 0', since that would never happen in that case anyway.   EDIT: Sometimes I just mindlessly write code, but today I just had an epiphany.       Yes, I have had my dose of try..catch with Java back in the day.  It is something I try to avoid, unless something really bad happens in the code, but I do see its use.  Not sure why, but even 25 years back in time when I first learned Pascal, I tended to stick with the functions that didn't throw exceptions if for instance a file could not be found.  Really never been a fan of exceptions.  I think the main reason is that I think it clutters the code too much.   In java you even have to wrap string to integer conversions in a try...catch clause...  I always was amazed by that even the "simplest" of operations has to be wrapped in exception handling in Java.  You can probably guess that it is not my favourite programming language.  If I were to rank, it would be c#, and Swift looks promising too, but both are (or have been) traditionally been tied to a single platform.  So here I am with my second or third best: c/c++.   EDIT 2: Oh, yes, I get why you mentioned exceptions now.  You are probably right that it is better to throw an exception rather than returning an arbitrary 'negative 1', or pass a value by reference to see if the operations succeeded or not.  I still have a bad feeling about using too much exceptions though.   I know I am not alone in feeling this way.  The whole Objective-C setup that Apple provides, is built on the assumption that excessive exception handling is evil.  Having pass by reference error values is the rule rather than the exception there.   Then you have the reversed way where you return an ok/error code and pass the returned index as a reference.   What is best practice?  Is there even such a thing in this regard?  Swift can return tuples.  That is a nifty thing.  Too bad I am reluctant to be tied to a system that is so locked to one platform and one platform only.
  6. Thanks for your suggestions.  I went with forward declaration.  I did actually try to forward declare the template class, but it didn't occur to me that I needed to forward declare the Point class too.  After I did both of those, everything compiles fine, and now I have lots of nice points showing up on my screen.   Now I will move on to make a scripted math library to move those dots around plus researching how I can make a fast 2D picking algorithm for a massive point cloud.  Probably will be much fun to see it all in action.   EDIT: Strewya: Thanks for best practices.  I always do forward declare functions, but that I in certain cases need to forward declare classes is a fairly new thing to me.  
  7. I am trying to make a circular doubly linked list, and thought it was a good idea to implement it as a template, since I will be using this kind of lists in my project.   The problem is, that while I think to my understanding that I have done everything right, my compiler beg to differ.   The error messages I get are:   - "Unknown type name 'node'" - "Expected member name or ';' after declaration specifiers"   I get these two messages for each of the offending lines, and everything seems right to me.  I am sure there is something I am lacking in understanding or something.   My template class: #include <stdio.h> template <typename T> class Node { private: T *mData; Node<T> *mPreviousNode; Node<T> *mNextNode; Node<T> *mChildNode; protected: public: Node(); ~Node(); }; template <typename T> Node<T>::Node() { mData = nullptr; mPreviousNode = nullptr; mNextNode = nullptr; mChildNode = nullptr; } template <typename T> Node<T>::~Node() { } The header class with the offending lines: #include <stdio.h> class Path { private: Node<Point> *mPointListHead; // <<---- THIS LINE, Node<Point> *mPointListTail; // <<---- AND THIS LINE protected: public: Path(); ~Path(); void addPoint(float x, float y, float z); }; The Implementation for the class: #include "Node.h" #include "Point.h" #include "Path.h" Path::Path() { mPointListHead = nullptr; mPointListTail = nullptr; } Path::~Path() { } void Path::addPoint(float x, float y, float z) { printf("Adding point\n"); } The header file for the Point class just for reference: #include <stdio.h> class Point { private: float mX, mY, mZ; float mR, mG, mB, mA; protected: public: Point(); Point(float x, float y, float z); Point(float x, float y, float z, float r, float g, float b, float a); ~Point(); }; The implementation of Point: #include "Point.h" Point::Point() : Point(0.0f, 0.0f, 1.0f) { } Point::Point(float x, float y, float z) : Point(x, y, z, 1.0f, 1.0f, 1.0f, 1.0f) { } Point::Point(float x, float y, float z, float r, float g, float b, float a) { mX = x; mY = y; mZ = z; mR = r; mG = g; mB = b; mA = a; } Point::~Point() { } Thanks for any help with this, and yes, I know that classes are private by default.   EDIT: The weird thing is that the "intellisense" (*) kind of thing sometimes seem to colour the keywords like it understand the names, but when I try to compile again, it forgets them again.  When the names are in the colours that shows that the IDE knows the class names, I can also start typing and get the correct autocomplete suggestions.  Also this goes away if I try to compile.  I am using the latest Xcode by the way, but I am pretty sure it is me goofing up, not the IDE/compiler.   (*) I don't know what name Apple has for the "intellisense".
  8. I had a feeling that the order or place I included header files had something to do with this issue.  I tried to move the following lines from the implementation file to the header file: #include "Node.h" #include "Point.h" It solved the problem  even though everything should really be in scope anyway.  That makes for a different question that I tried to research the other day:   I noticed that Xcode likes to put include files in the header file.  I thought that they should be put in the implementation file, so I did look it up.  It seems that most people agree that they should indeed be in the implementation file, but...   That leaves me two questions: 1. Why does Xcode put the #includes in the header file when they seemingly should be in the implementation file? 2. Can anyone kind, please link me to a good explanation what is 'best practice'?
  9. aregee

    Architecture copyright

    This:   http://www.gamespot.com/articles/student-transferred-for-making-counter-strike-map-based-on-school/1100-6235913/
  10. aregee

    "simple" equation confusion (a - b = c)

    This video should give you a thorough explanation on the matter:  
  11. I am by no means any expert on the topic, but I think you have a lot to learn, if HTML is all you know.  Just client side, I would add that you would need to learn JavaScript too, in addition to the other technologies you have already mentioned.   Unless it is a client based game where nothing is stored between sessions, you will also need a web server with a database system and a server side scripting system. In the past, I have used Apache, PHP and MySQL, but that is starting to be quite a while ago, so have a look around.   Other buzzwords you may have a look into is JSON, JQuery.   Security is a must, so make sure you understand the dangers and pitfalls of a poorly designed system for handling logins and sessions (how you store your passwords, for instance), and data that is sent to the server from the client (it can not be trusted without validation), and SQL security as well (SQL injection, for instance).   All these suggestions are based on what you mentioned in your original post, and there are other choices you can make too, like scrapping everything mentioned above and go for something like FLASH, for instance, client side. You will still need what I mentioned on the server side if you want persistence.
  12. aregee

    Demo scene 90's, anastasia song

    Never heard of the group or demo, but I am pretty sure it is this one:   "Toys" by "Gods" (PC demo, "Trip" party, March 1999, 1st place):   http://www.pouet.net/prod.php?which=710   I couldn't find any YouTube video of the demo.
  13.   I won't repeat what Álvaro said, but please...   Write sensible names.   Name 'dyn' and the likes more like 'isDynamic' (If that is even what you mean).  Then you can test like this, assuming it is actually a boolean: if (isDynamic) { ... } Instead of: if (isDynamic == true) { ... } Try to make your code as readable like a book that you can.   Always use brackets, even if your if, for, while, do..while, etc is having only one line.   'currentLineCount', or 'CurrentLineCount' is MUCH easier to read than 'CurLnCnt'.   What is 'IsPastEOS'?  'EOF' is so common, I guess most people would understand, but 'EOS'?  End of stream?  I would spell it out in either case.   I know that you have an assembler background, and labels like this were common back then.  I also think you actually was limited to 8 chars on certain assemblers too, and that didn't help.  It really feels like reading assembler code written in C.   And I will also point back to Álvaros comments again.
  14. I think exceptions have no place other than in the case of a fatal, unrecoverable failure in a program.  When I was learning Java way back, I was encouraged to use exceptions as the default way of reporting and handling errors.  I always felt that was a bit clunky, and it made for code that was filled with blocks that I felt never belonged in the code at all.  I always favoured explicit error checking over exceptions.  Who thought it was a great idea to throw a NumberFormatException when you feed bogus data to convert a string to an integer in Java??  That pretty much sums it up...
  15.     That's an arbitrary blanket rule. Early returns are a good thing. Breaks and continues have their places. Goto has its place too when you need some kind of control flow that improves readability (like the error handling example) and no other language construct naturally lends itself to that (admittedly, that is rare even in languages like C, and basically nonexistent for higher level languages). And when I see this kind of rule being repeated blindly all I can think of is the programmer who, told not to use goto, wrapped up his error handling code in a dreadful do{}while(0); loop to obtain the same control flow without writing 'goto' and obfuscating his code in the process. And that is far worse than any amount of gotos (well, almost any amount).   I'm not saying goto is good. Here the use of goto for error handling is justifiable because goto naturally lends itself to a rather elegant, very low boilerplate resource cleanup implementation in C. Clearly jumping all over your code, to labels hundreds of lines away, is nothing short of insane. But simply outright banning goto because there is a paper called 'goto considered harmful' without even considering the possibility that maybe, just maybe, goto could be used in a controlled manner (it is a tool, and just like any other tool it can be abused; break and continue are also tools which can be abused) simply shows a lack of intellectual depth in my opinion.     The cascade model is just plain ugly.  The goto way is actually really elegant.  In those cases I would probably go for a function in the past to avoid goto, but your arguments have convinced me.  There are definitively reasons for goto in certain cases, and the function way is not good either.   Regarding the blanket rule, I am not at all preaching the "flow chart" model, since I am obviously not following those rules myself, just wanted to hear some arguments, and I got a lot of good ones.  I am a follower of clean and elegant code, and that is for me more important than any other strictly (and blindly) enforced idioms.  Hearing comments like this also eases my insecurities/discomforts when I am breaking out of learned/taught conventions to make things more readable/elegant too, but the goto one has really got stuck in me for some reason. 
  16.   Oh dear!  I happen to do the opposite on occasion, moving local variables to member variable in cases where I have tight loops and want to optimise a bit, and now you are telling me that?  Seems I have a lot of work learning my own compilers behaviours...
  17.   I just noticed this... If your use of goto is to return, why don't you just put an return in place of the goto?  Then the intention will be much clearer.  With goto to exit, you are just camouflaging the real intent.  You are adding one more level of "complexity" that is unnecessary.  You are still breaking the flow with return, but it is still cleaner than a goto in this case.  Besides, I am not so sure it is all that bad to break the flow in this manner.  The intent with a return statement is clear: I am done with this function.   If you want to think about this in a real technical way, you should be able to draw a flow chart of your function.  This should be done in advance, but who does that?  The rules of a flow chart is: that you are having only one entry point, and only one exit point, and that absolutely no lines are crossing each other.  No, you can't cheat and draw a flow chart that branches to the right side, and then to the left side to avoid a crossing on the right side.  If you are ever using any of goto, break, continue or early returns, then you are breaking this flow.   According to these rules, I can't claim that I am being correct myself, since I am using all but the goto one.  However, there really aren't many cases where goto will be needed.  I am repeating myself a little bit now, because I am curious what view other people have about break, continue and early returns, if they see goto as evil.  I sure do see goto as evil, but realise that break, continue, and early returns kind of falls in the same drawer, so that would theoretically make those too evil, even though they seem to be seen as more acceptable.   Edit:     Why would you feel guilty about using language constructs in a completely idiomatic way, making the code more readable?     Álvaro snuck in and answered my question.  Regarding "If the alternative to the goto is using boolean variables to control flow, I'd rather take the goto." It is sure the dilemma I have when I am breaking out of multi level loops.  I think I actually used boolean values in the case I had to solve this, and I considered goto for the first time in my life.  I somehow felt dirty either way.  None of the solutions felt really clean.  I think I need to be cured of goto-phobia then.   And regarding the other case, I don't feel guilty over those language constructs, that is why I am using them. It is just that they are technically gotos too, just a bit cleaner since the intention is clearer.  I always want to get better at what I am doing, that is why other people's opinions matters, and for me discussions like this is brilliant.
  18.   I really agree with this.  I have never had the need to use a GOTO in my whole life.  There is only one case I can remember where I was tempted to use a GOTO, and that was when I needed to BREAK out of a multi level FOR/WHILE loop.  I don't remember how I solved that problem, but I have so much aversion against GOTO, that I am sure I didn't fall for my temptation.  On the other hand, I am feeling a bit guilty, because I write code like this all the time:      for (uint8_t channel = 0; channel < module->ChannelCount; channel++) {                  currentChannel = &module->ChannelList[channel];                  if (currentChannel == NULL) {             printf("Current channel is null...\n");             isErrorStatus = true;             return 0;         }                  if (!currentChannel->status.isPlaying) {             continue;         }                  if (currentChannel->status.isMuted) {             continue;         }                  if (currentChannel->delaySample != 0) {             continue;         }                  if (currentChannel->lengthInBytes == 0) {             currentChannel->status.isPlaying = false;             printf("Tried to play an empty sample.\n");             currentChannel->volume = 0;             currentChannel->status.isPlaying = false;             continue;         } Well...  This is maybe the most extreme example I could find, but I think it is cleaner to use a few breaks and continues than lots of levels of nested ifs.  Here I break the flow with both returns and continues.
  19. When I had a Pascal course back in 1991, the teacher we had enforced strict prohibition to gotos, arguing that you should be able to draw a flow chart from top to bottom with no crossing line of flow.  Goto obviously breaks this.  I never used goto since then, and I actually never had any need to use goto either, but I do break the flow according to flow charts every day:   Break and continue breaks the flow, so does early exits with return, so as far as I am concerned, if goto is considered evil, so is break, continue and premature returns too.   Edit:   Multi level break is a problem of course.  I think Swift has solved that by labelling the loops so you could name the loop you wanted to break, ie. 'break columnLoop', for instance.
  20. aregee

    Data Struct for 2D map with barracades

    Another point to add to what Glass_Knife is saying, is that you may discover the need for things you haven't thought of yet, and if that does not fit with the structure you decided today, you may have to change things further down the road anyway.   If you still want another idea, I just thought of something else just now.  If you instead of putting the data itself in a map array, you could put pointers to some class or struct or whatever you prefer, and you will have something that is easy to extend in the future.  (That is not light-weight though.)   There is no given answer, however...
  21. aregee

    core i5 running at 101 degrees C, as if nothing...

      Ambient temperature actually has a massive impact on the ability of the fans to cool down the system.  Just one degree up, can make the CPU run several degrees hotter.
  22. aregee


    In a careless thought to make the data type as small as possible, the compiler complained (naturally) of me using a constant that was too big for the type I was testing against:     for (uint8_t j = 0; j < (1 << 8); j++) {        ...     } Which gave me the idea to come up with this masterpiece:     for (uint8_t test = 0; test <= 255; test++) {       printf("%i\n", test);     }
  23. aregee


      Xcode did certainly not complain.  Let me double check that.   Nope.  No complaints.  Xcode is happy...  I even tried the static analyzer, and it just replied "Build Succeeded".  "No Issues".
  24. For the non-expert: DSP = Digital Signal Processing PDM = Pulse Density Modulation PCM - Pulse Code Modulation   I am struggling with what is sounding like an evenly distributed hiss on top of otherwise very good sounding audio when decoding pulse density modulated audio to pulse code modulated audio.   The bitstreams I am working with are 1 bit 2.8225 Mhz PDM, and I am "resampling" it to 16 bit 44.1 kHz PCM.  That translates to about 64 one bit samples per 16 bit PCM samples at 44100, thus I am using a 64 order window function to make PCM out of PDM.   How I am processing the audio is like this:   First I am making a precalculated window function like this:           for (int i = 0; i < 64; i++) {             fir64Coff[i] = (double_t)(1 << 10);             //Hanning Window (less noise than hamming?             fir64Coff[i] *= 0.5 * (1 - cos((2 * M_PI * i)/ (64 - 1)));             //Hamming Window //            fir64Coff[i] *= 0.54 - 0.46 * cos((2 * M_PI * i) / (64 - 1));                          //Nuttall Window //            fir64Coff[i] *= 0.355768f - 0.487396*cos((2*M_PI*i)/(64 -1)) + 0.144232*cos((4*M_PI*i)/(64-1))-0.012604*cos((6*M_PI*i)/(64-1));                //Cosine Window //            fir64Coff[i] *= sin((M_PI * i)/(64-1));    //Blackman Harris             //            double_t w = (2 * M_PI * i) / 64; //            fir64Coff[i] *= 0.422323 - 0.49755 * cos(w) + 0.07922 * cos(2 * w);         }   Hamming/Hanning sounds the best of the window types I have tried.   Here is how I generate PCM from PDM:  (Be warned this is just some pilot tinkering.)   - (uint64_t)getBytes:(void *)buffer sampleCount:(long unsigned)count {     if (mIsEndOfSong) {         return 0;     }     [mutex lock];     int16_t *sampleBuffer = (int16_t *)buffer;          for (uint32_t currentSample = 0; currentSample < count; currentSample++) {         uint64_t testLeft = 0;         uint64_t testRight = 0;         int64_t sumLeft = 0;         int64_t sumRight = 0;         uint8_t coefficientIndex = 0;                  for (uint8_t i = 0; i < 8; i++) {             if (currentBufferPos >= blockSize) {                 if (![self readChunk]) {  //Here I fetch left and right channel blockSize bytes (Usually 4096)                     [mutex unlock];                     return currentSample;                 }             }                          testLeft = bufferLeft[currentBufferPos];             testRight = bufferRight[currentBufferPos];                          for (uint8_t i = 0; i < 8; i++) {  //Two nested for loops, 8 * 8 = 64 bits, lsb first per byte                 if ((testLeft & 0x01) == 0x01) {                     sumLeft += fir64Coff[coefficientIndex];  //These are the pre-calculated window values                 }                 else {                     sumLeft -= fir64Coff[coefficientIndex];                 }                                  if ((testRight & 0x01) == 0x01) {                     sumRight += fir64Coff[coefficientIndex];                 }                 else {                     sumRight -= fir64Coff[coefficientIndex];                 }                                  testLeft >>= 1; //Next bit                 testRight >>= 1;                                  coefficientIndex++;             }                          currentBufferPos++;  //next byte         }         sampleBuffer[(currentSample << 1) + 0] = (int16_t)sumLeft;         sampleBuffer[(currentSample << 1) + 1] = (int16_t)sumRight;     }          [mutex unlock];     return count; }   Pretty simple, actually, and it sounds great - except for the noise.  I am not sure what I am doing wrong.  I am sure super audio is not supposed to have varying degree of noise in them.  I have read that when audio is being sampled, a noise shaping function is being used, and noise generated during this process is pushed up into the inaudible frequency range.  I am wondering if the noise I am hearing can be this high frequency noise being aliased back into the perceptible frequency area.   Does anyone have any tips for me, how to get rid of the noise?  I tried to make a low pass filter too, but that made the noise even louder and with no music at all, so there is probably something I did wrong.   Here is the function I made for that, if it can be of any help:   - (void)lowPassFIR:(double_t*)firBuffer withSampleRate:(uint64_t)Fs cutOffFrequency:(uint64_t)Fc filterLength:(uint64_t)M {     M = M -1;     double_t Ft = (double_t)Fc / (double_t)Fs;     double_t sum = 0.0f;          for (uint64_t i = 0; i < M; i++) {         if (i != ((double_t)M / 2)) {             firBuffer[i] *= sin(2.0f * M_PI * Ft * (i - ((double_t)M / 2.0f))) / (M_PI * (i - ((double_t)M / 2.0f)));         }         else {             firBuffer[i] *= 2.0f * Ft;         }                  sum += firBuffer[i];         printf("%f\n", firBuffer[i]);     }     printf("Sum: %f\n", sum); }   Edit: it is worth mentioning that I am trying to learn DSP, but I am an utter noob in this area.  I have a vague understanding, but not all the pieces are in place yet, so I think I have done pretty well, considering I have just jumped into this.  This is also something I am doing just for fun and to learn, and weirdly something as recognised as VLC can't play either.   Edit2: I have a feeling the noise comes because I am not properly "moving" the window, just taking a weighted average starting at every 64 bits, but I am trying to reduce the massive amount of processing I need to do if I would do a moving average of every 64 bit bits before I have produced even one PCM sample.  That would make 64 * 64 = 4096 loop iterations for each PCM sample, 4096 * 44100 = 180.633.600 iterations per second...  I think my computer would have hiccups long before that.   Another theory I have, is that I am just discarding the remainder of the double after a full integer, and that is generating some dithering noise.   Edit3: Just got an idea to get completely rid of the if-sentences in the inner loop.  I can just make a lookup table for that as well...  That means I can get rid of the whole inner loop completely.
  25. Oops... Seems I am getting sidetracked again... Fun to have something that has "flawlessly" been working for weeks crash like this: STAAudioCoordinator: could not fill entire buffer, will clear the rest of the buffer for now. Read 512. Block Size: 3383413356 Last Sample: 7302926928557966667 objc[6886]: Hash table corrupted. This is probably a memory error somewhere. (table at 0x7fff72991490, buckets at 0x1009ea600 (4096 bytes), 256 buckets, 31 entries, 87 tombstones, data 0x84e54b0084ce8b 0x8512d10084fc0d 0x85405f00852997 0x856df400855729) Hiding progress bar. objc[6886]: Hash table corrupted. This is probably a memory error somewhere. (table at 0x7fff72990e10, buckets at 0x100a03200 (4096 bytes), 256 buckets, 26 entries, 82 tombstones, data 0xa92bea00a9124f 0xa95f2700a94588 0xa9926c00a978c8 0xa9c5b700a9ac11) Pretty obvious what happened here, but why?  Time to put some sanity checking into the DSF-player at least, but those values are just insane...   Edit:   Found one error that contributed, but I don't think this is the whole story:   Before:     if ([iStream read:bufferLeft maxLength:blockSize] == 0) {mIsEndOfSong = YES; return NO;}     if ([iStream read:bufferRight maxLength:blockSize] == 0) {mIsEndOfSong = YES; return NO;} After:     if ([iStream read:bufferLeft maxLength:blockSize] != blockSize) {mIsEndOfSong = YES; return NO;}     if ([iStream read:bufferRight maxLength:blockSize] != blockSize) {mIsEndOfSong = YES; return NO;} Sometimes I just shake my head of the silly errors I make...   Edit 2:   Seems I located the source for the error.  I have postponed refactoring the bit file reader for too long.  Time to solidify and complete all the functionality I have planned for this class.  Seems it get hiccups at end of file situations sometimes.  Also the weird thing that it tends to sometimes cut the end of songs, not only on FLAC but also on DSF indicates that it is the bit file reader that is buggy and needs some more work.
  • Advertisement

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!