Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 22 Aug 2001
Offline Last Active Mar 07 2016 04:10 AM

#5050204 Why can I call a nonconst function with a const object?

Posted by on 04 April 2013 - 10:07 PM

Because temporaries returned from functions are r-values and considered const. You are not supposed/allowed to modify a temporary variable.


You are also wrong about the lifetime. The lifetime of a temporary doesn't extend to the end of the surrounding block. It ends with the expression it is used in. One big and good to know exception is having a const reference to it, which will keep the temporary alive for as long as the reference exists.


//temporary dies here
     const Temp& temp = createTemporary();
     //do stuff
//temporary dies here, because reference goes out of scope

#5044788 Am I a bad programmer?

Posted by on 19 March 2013 - 11:45 PM

Finally, if you launch an application in Visual studio with CTRL + F5 ( I believe thats the key combo ), it will automatically prompt for a keypress before closing the console window.


That shortcut is extremely useful, but it's important to remember that it means "run without debugging". You can't step through your code or hit breakpoints. Of course that shouldn't be an issue, because if you ARE debugging, just set a breakpoint at the end of main. Also, it only works if you configure the project to "system" console (if you created an empty project, you have to do that manually).


Writing a good tutorial has two requirements. You don't just need a good grasp of the subject at hand, but you also need the ability to teach and explain. We had plenty of tutors at university who really knew their stuff, but absolutely sucked at conveying that knowledge. So the tutors where happy to get their money and the students stopped showing up, because it was a waste of time.


So essentially the number of people qualified and willing to write a really good tutorial is rather limited.


In terms of diary, I remember doing that when I felt like rewriting JA2. I gave up after 5 days, because I spent more time writing than programming. Of course if you write about it, you get ideas or notice mistakes, so you always constantly change between coding and blabbering. Technically a good thing for your code, but also very time consuming. Looking at it now, it just makes me cringe and go "why didn't you just use TBB and boost instead of rolling your own?" However, it had the advantage of not hurting anyone. Not only because nobody ever read it, but because it never had the intention of "teaching how it's done".


I'd still suggest doing that instead, because explaining why you do something forces you to think about it, which will typically lead to research and understanding.


While I'd like to think I'm good enough at C++, I still wouldn't write tutorials, because I suck at explaining things in a concise way while still being "complete". Also, there already are a million books and tutorials about all the basic stuff, so I would just add to the noise. Maybe if I ever come up with something that I feel is "new" or important enough to be shared.


But heads up, the price for worst C++ tutorial ever goes to whoever wrote that the "int" in "int main" means "start program execution here" and that the "return 0" at the end doesn't really mean anything, but just has to be there. That looked like somebody just read the back cover of "C++ for Dummies" and felt like writing a tutorial about all the things that mystified him.

#5043254 Way to pre-declare standard templated class types?

Posted by on 14 March 2013 - 11:11 PM

Usually precompiled headers are brought up a lot with template heavy code to reduce compile times. Is that not an option or are build times still too long?

#5030299 New c++11 video tutorials, tell me what you think.

Posted by on 08 February 2013 - 11:56 PM

After having seen stuff like "MyClass" and "myInt" in actual production code (map<...> theMap), I don't think it matters what he uses. If the variable has absolutely no meaning besides being there to demonstrate its existence, the name will ultimately be pointless and people will copy that, no matter what. At least one person would probably even copy it if it was named purelyForDemonstrationAndForGodsSakeDontNameYourVariablesLikeThis.

#5029301 Rule of Three, and const-correctness questions

Posted by on 05 February 2013 - 11:26 PM

Since const correctness still comes across as something that's "nice but not mandatory", let's look at things that will fail if you don't write const correct code.


First, the one thing that can really get me mad: people writing interfaces/APIs using char* instead of const char*.

void parseString(char* str) { ... }
std::string text;
parseString(text.c_str()); //Fail, as c_str() returns const char*



While these have a simple workaround, it can still be annoying

void analyseObject(MyClass& obj) { ... }
analyseObject( MyClass(a,b,c) ); //Fail, temporary variables are r-values and const


struct MyClass {
   void print() {...}
MyClass(a,b,c).print(); //Fail, temporary = const



To clarify the observable effects of ignoring the Rule of Three, because unlike missing const correctness, this won't conveniently fail to compile in the first place:


struct MyClass
    int* data;
    MyClass() : data(new int) {}
    ~MyClass() { delete data; }
vector<MyClass> v;
v.push_back(MyClass()); //Fuse is lit
cout << v.front().data; //Fail
v.clear(); //Fail
void function(MyClass a) { ... }


Let's ignore compilers optimizing out the temp variable or using move semantics, since you can't rely on it.


First example creates a temporary instance, then creates a copy in the vector (which just stupidly copies the pointer). The temporary goes out of scope and deletes data. The next line accesses data that was just deleted. You will see either garbage (kind of helpful), crash with an access violation (very helpful) or it will just seem to "work fine" (dangerous), as the memory will most likely not have been overwritten yet.


Then we clear the vector and delete the instance in it. Now data is deleted a second time. If you are lucky, your application will crash.



The second example looks harmless, but does pretty much the same. To call the function, you create a copy. When the function returns, this copy is destroyed and deletes your data. The original object is now in an invalid state with data pointing to deleted data. Any access will hopefully crash and when the original object goes out of scope, the memory is attempted to be deleted a second time.



Why is crashing the best case scenario? Because it is hard to miss and clearly tells you there is a bug. The same bug could result in working "just fine" most of the time, but returning strange values on every odd Thursday during full moon. This can cost you days or weeks just trying to reproduce the bug and tracking it down.

#5028540 First person camera and matrix transforms

Posted by on 03 February 2013 - 11:02 PM

You already are doing the inversion in the last block of your lookAt function, when you transpose the rotation part and invert the translation part. This method only works for special cases, but unless you "break" things by adding scaling to your matrix, you have that special case.

#5028277 Timing seconds per frame in C++

Posted by on 03 February 2013 - 02:13 AM

Using microseconds gives even more accuracy, however there are not any standard microsecond timers in C++, so you have to use third party or OS-specific timers, unless you are using the new C++11 standard's <chrono> library, which has a high precision timer that might be microsecond or better, but falls back to milliseconds if microsecond precision isn't available.


If you are using VS 2012, you should use the boost implementation of the chrono library (unless they updated it in the meantime). Why? I basically picture the conversation like this:


Marketing: "We already put chrono support on the website."

Devs: "But we can't make it in time!"

Marketing: "We don't give a damn."

Devs: "Let's base all clocks on the standard timer, pretend we implemented it and just deal with the bug reports later."

Marketing: "See, was that so hard?"


I'd definitely use some chrono implementation, though. It's the new standard, it's platform independent and you don't have to worry about the potential pitfalls of using QueryPerformanceCounter on multi-core CPUs.

#5028270 First person camera and matrix transforms

Posted by on 03 February 2013 - 01:40 AM

The problem is that by storing a target position, you are making something that is conceptually really simple a lot more messy. For one, you can't simply rotate a target position, because it would rotate around the origin instead of the camera position. You can't just linearly move it around either, as you might have noticed from things not working. So stop dealing with "which point am I looking at" and think about "which direction am I looking in".

For an fps camera, you probably want to limit your up/down rotation to +/-89°, so in your case, the otherwise ugly Euler Angles are the easiest approach. Why not 90° you might ask? Because of something many people don't quite understand about the lookAt helper function. "Up" must be roughly your local up (ie. imagine sticking a pencil in the top of your head, that's the "up" lookAt needs. Now, simply using (0,1,0) works great, until you rotate exactly +/-90° up/down (where it should be (0,0,1) or (0,0,-1)) or more than 90° (where it has to be (0,-1,0)).

So what you really need for lookAt is your position, a point to look at (or the direction to look in) and a vector pointing "up". That just happens to be the 4th, 3rd and 2nd column of the cameras transformation matrix, but we just want fps style and take some shortcuts:


//Don't try to use this for a flight simulator without stocking up on aspirin first
float pitch = 0;
float yaw = 0;
if (left) yaw -= rotationSpeed * mouseDelta;
if (right) yaw += rotationSpeed * mouseDelta;
if (up) pitch -= ...
while (yaw < 0) yaw += 360;
while (yaw > 360) yaw -= 360;
if (pitch > 89) pitch = 89;
matrix rotation = createRotationMatrix(pitch, 1,0,0) * createRotationMatrix(yaw, 0,1,0);
//At this point, you can either transform some default view direction or just have the camera look right by default and extract the columns of this matrix.
//For simplicity, we use lookAt
viewMatrix = lookAt(cameraPosition, cameraPosition + rotation.3rdColumn, rotation.2ndColumn);


Probably a lot more reusable and not really much more complicated:


matrix rotation;
vector translation;
//Note that left/right and up/down are a different order to use the global "up" and the local "right"
if (left/right) rotation = rotation * createRotation(mouseDelta, 0,1,0);
if (up/down) rotation = createRotation(mouseDelta, 1,0,0) * rotation;
if (forward/backward) translation += distance * rotation.3rdColumn;
if (strafeLeft/Right) translation += distance * rotation.1stColumn;
matrix transformation = rotation;transformation.4thColumn = translation;
viewMatrix = inverse(transformation); //Use the simple version (same as in lookAt)

You can also keep it all in one matrix, which makes translation easier, but requires extra steps when rotating around a global axis.


matrix transformation;
if (left/right) {
     vector position = transformation.4thColumn;
     transformation = transformation * createRotation(yaw, 0,1,0); //This will also rotate our position around the origin
     transformation.4thColumn = position;
if (up/down) transformation = createRotation(mouseDelta, 1,0,0) * transformation;  //This will rotate around our current position
if (movement) transformation = createTranslation(x,y,z) * transformation; //This will use local x,y,z
if (gettingPushed) transformation = transformation * createTranslation(x,y,z); //This will use local x,y,z
viewMatrix = inverse(transformation);


This is obviously pseudo code. Since 3D graphics is basically nothing but vector and matrix math, there simply is no way to get around learning and embracing them. The absolute minimum to start out is getting familiar with rotation and translation matrices and getting an intuitive grasp of what the components represent and what multiplication will do to them.

You might notice that the last versions will also work just fine for all your other game objects and won't fall apart when you start turning things upside down. So it's pretty much the most generic way if you stay away from scaling (or keep it separated). There is also no lookAt, because most of what that does would be completely redundant.

One thing to keep in mind is that you need to occasionally reorthonormalize the rotation/transformation matrix, as floating point errors will accumulate and start creating some trippy effects. When using lookAt, that happens automatically, since it is reconstructing the whole matrix every frame.

Eventually people will tell you how quaternions are essentially the "one true way of rotation" or even the second coming, but in the end they are completely equivalent to rotation matrices and the only important thing is to know when they are more efficient. There is however absolutely no reason to worry about them at this point (and no, they are not the "only solution to gimbal lock", that's "don't use frigging Euler angles").


edit: ok, great. Never edit a post with code, unless you want every single line break to disappear...

#5028034 First person camera and matrix transforms

Posted by on 01 February 2013 - 11:25 PM

Judging from your code the very simple reason why your rotation isn't working is because you aren't rotating at any point. Shifting the point to look at left and right has nothing to do with rotation and a very simple question should make it obvious: "how do you expect to look behind your position?"


Rotation involves trigonometry, either used directly (I wouldn't) or hidden away (constructing a rotation matrix). Look at the graphs for sin and cos, remember that an angle of 0° is straight to the right and you should notice how x = cos and y = sin for any given angle.

#5027242 First person camera and matrix transforms

Posted by on 30 January 2013 - 11:56 AM

Personally I would absolutely avoid storing angles, though it works fine for a simple FPS style camera (just make sure you always rotate around "up" first and "right" second). The simple fact is that the order in which your rotations are applied is important and completely lost if you just accumulate angles.


Also, pleaaaase don't abuse scaling to zoom. Zooming is a perspective effect and the result of focusing your lens to show a smaller area, ie. what you get by reducing your field of view. Scaling will scale your objects, can make them grow beyond your near plane or even behind your camera and suddenly zooming turns into a wall hack.


My usual camera class is using my own vector/matrix stuff, so it would be mostly useless to you, but the basic setup is that it stores a transformation matrix (4x4). All rotations and translations are directly applied and accumulated in that matrix when processing the users input. Since matrix math is neat, applying a rotation around (1,0,0) will always look up/down around your current "right", just like a translation along (1,0,0) will always strafe left/right. For the rare situations where you want to move/rotate using the world axes, you just multiply the new transformation from the other side (to visualize it, one way the rotation happens after the previous transformations, the other way it happens before... while all local axes are still aligned with the world axes).


Btw., your typical lookAt function will just build a transformation matrix from the passed vectors and then invert it, so it becomes extremely superfluous if you store the transformation matrix in the first place. Inverting it is simple, as long as you stay away from scaling.


viewMatrix = Matrix44(
        Transform[0], Transform[4], Transform[8], 0,
        Transform[1], Transform[5], Transform[9], 0,
        Transform[2], Transform[6], Transform[10], 0,
        -(Transform[0]*Transform[12] + Transform[1]*Transform[13] + Transform[2]*Transform[14]),
        -(Transform[4]*Transform[12] + Transform[5]*Transform[13] +    Transform[6]*Transform[14]),                        
        -(Transform[8]*Transform[12] + Transform[9]*Transform[13] + Transform[10]*Transform[14]), 1);

#5027085 First person camera and matrix transforms

Posted by on 29 January 2013 - 11:38 PM

Most of the "easy, convenient and beginner friendly" stuff was removed to clean up the API, because it was kind of silly to have three or more ways of doing the same thing. They are still around through the compatibility extension, though.


The easiest way to handle any camera to me is to treat it like any other object. Give it a transformation matrix, understand that the columns of that matrix are right/up/forward/position vectors (depending on your setup) and that to turn it into a "view matrix" you just have to invert it. Every frame you add the new transformations depending on your input and set the inverted matrix as view matrix.


It also means that "attaching" a camera to an object or moving it for cut scenes is literally straight "forward", compared to trying to keep the inverted matrix and apply everything "in reverse".

#5025988 Clashing Enemies

Posted by on 27 January 2013 - 12:56 AM

I'd very much go with the AI approach, because trying to solve this with physics in a tight crowd sounds like an awful mess. Yes, it's trivial to have _two_ objects and resolve their collision by moving one to the side. Except that in a crowd it might then hit someone else and you end up with a recursion that takes forever to resolve. The only solution would then be "if your movement would cause a collision, don't try to move at all".

#5024606 A star

Posted by on 22 January 2013 - 11:23 PM

What's worrying me even more is that I can't tell if this is a header or source file (the former would basically result in a lot of crying and forehead to table contact, because of the "using" and all the static variables). And even worse is the fact that the code looks like you really need to take a step back and understand memory management in C++. It's not just the abuse of the word "garbage collection" (which is a concept that is basically the exact opposite of what you're doing), but all the pointless new and delete calls in combination with leaking memory like crazy and apparently thinking that somehow "push(*pointer)" would not still create a copy of your object, making it very pointless to do an expensive allocation on the heap.

#5022435 Problem with creating a class for drawing....

Posted by on 16 January 2013 - 10:59 PM

One kind of obvious thing that jumps at me is your constructor. Take a good look at it and if you don't notice it, describe to me in detail what it does ,-)

#5022059 Problem with creating a class for drawing....

Posted by on 15 January 2013 - 11:20 PM

The code for all the setup isn't shown. What does your viewport, view and projection look like?


Since you don't clear the depth buffer, did you make sure that depth testing is disabled?


Are you sure that based on your view/projection "front" is where you think it is?


Why are you setting alpha to 0 (100% transparent, depending on blend mode)?