Colours of the rainbox, rainbow sprite! (You have not yet felt the full horror that is strawberry shortcake hour)
My First 3d Sprite
I am so not comfortable with the concept of calling a 3d model a sprite, but that's what CS calls 'em.
Now, if you were good and did your homework, then you know that the tutorial ends up with you making a square room containing a litte box floating in one corner. The box has a natty little star drawn on it.
That's your sprite.
Now, for those of you who didn't do your homework, stand in the corner and write out the following lines:
- The tutorial is in CS\apps\tutorial\simple1
- You ought to edit it as the manual tells you to
- To compile it, you type 'make tutsimp1' (That's a one, not an L) in the DOS window (and hit enter, of course)
- The program that gets made is called 'simple1'
- I loathe makefiles, especially huge overcomplicated ones like crystal space uses.
On the subject of loathing makefiles, to get around them, all I'm doing is editing the 'simple1' project forever more - and copying old versions to other names so that I can go back to them when I break stuff.
Right, rather than trying to understand exactly why things work the way they do, I next decided to twiddle with it. First I changed the lights around - made them brighter.
This was easy, the line seemed self explanatory (and the manual backed me up)
light = engine->CreateLight ("Red", csVector3 (0, 0, 0), 40, csColor (1, 1, 1), false);
"Red" is just a name, in case I want to refer to it later. The vector is where in the room the light goes - changing those numbers works as you'd expect it to. 40 is a brightness (the manual refers to it as a radius, same difference) And the colour is RGB (values range from 0-1, I'll remember that) The false? Dunno, but don't touch it.
As you can see, I changed that light to be white, and a lot brighter. Recompile, re-run and YAY! Our first very own change! (I hope you made the light blue or something, otherwise you've just followed someone elses instructions still)
So. What about a moving light? Hummm.. 'dynamic light' that sounds like what we want.
Just before the 'light->DecRef()' I add in:
flashyDyn = engine->CreateDynLight (csVector3 (3, 5, -3), 35, csColor (1, 1, 1) );
flashy = flashyDyn->QueryLight();
ll->Add (flashy);
And it breaks everything, because I've not defined stuff. Including dynlight.h helps - and editing the simple.h file a bit helps more. { struct iDynLight; iLight *flashy; iDynLight *flashyDyn; }
Doesn't seem very dynamic. Bright, yes, but not dynamic. Still, we've not told it to do anything yet.
I decided to make the light turn on and off with the same keys as movement (ok, so I decided that because I'm not totally sure how the keys work yet)
In the CSKEY_UP bit, I added: flashyDyn->QueryLight()->SetRadius ( 1 ); flashyDyn->Setup();
According to the manual, you need to call 'setup' after you've finished moving the light around, in order to redo the lighting.
And... it works! Homework time - make going backwards turn the light ON again.
Now, the problem we've got is that the lighting isn't really showing up too well on the mostly black cuboid that is our sprite. Let's fix that.
The sprite itself is stored in /CS/data/standard.zip It's called sprite1
Pull it out into a text editor, and get confused.
Well, there's a couple of things there that look like names - a bit to say it's a sprite, then what looks like the name of the texture, and a bunch of numbers.
Let me enlighten you, by building our own sprite. It's gonna be a spaceship!
Inside the frame, is a bunch of V(a,b,c:d,e) stuff. Those represent the vertices of the mesh. a,b,c is the xyz of the point - d,e is where that point goes on the texture skin (we'll ignore that for now) Everything goes from 0 to 1.
The next section is the 'action' and has a bunch of TRIANGLE(p,q,r) in it. Triangles are what models are made from, and the numbers are the numbers of the vertices used - so 0 is the first V(a,b,c:d,e) 1 is the next one, etc.
Now, in the 3d modelling world, triangles are one sided. If you look at a triangle from behind, you see straight through it. And the rule for deciding is that if the points go clockwise, you can see it. Use your left hand, curl your fingers, and stick your thumb out. Now, move your hand about until the points on the triangle go along on of your fingers (sorta, curl in that direction, anyway) if your thumb is now pointing towards you - so will the triangle be.
That probably made no sense. Let's make our spaceship and see if it makes more sense.
Get a bit of paper out. You'll need paper. Draw an isoceles triangle with the long bit pointed down. Now make it 3d by drawing a short line up/left from the middle of the top line, and join the end of it to the other 3 points.
Number your vertices, 0 top left, 1 bottom pointy bit, 2 other bit on the base triangle, 3 the middle of the top line and 4 the one you made stick up.
Now we have to decide where these points are in 3d. I decided that the left of the model should be at -1, the right at +1, the top at -0.4 and the bottom at +1
And then I filled in the vertex table:
V (-1,-0.4, 0 :0, 0.6) ;0
V (0, 1, 0 :0.5,1 ) ;1
V (1, -0.4, 0 :1, 0.6) ;2
V (0, -0.4, 0 :0.5,0.6) ;3
V (0, 0, 0.2:0.5,0.4) ;4
Consider the last two numbers in each entry to be magic that makes it come out right, for now. (They're actually placement on the skin, as I said before)
Now - one VERY nice thing is that you don't have to recompile the project every time you change something. Just save the file back. (I actually renamed it sship, saved it in \data\temp\ and told the project to use that, rather than crisk corrupting the origional files. That might be a good idea for you, too)
I actually added the triangles one at a time making sure each one came out right, and was facing the right way. But these are the triangles I added:
TRIANGLE (0,1,2)
TRIANGLE (2,1,4)
TRIANGLE (4,3,2)
TRIANGLE (3,4,0)
TRIANGLE (0,4,1)
TRIANGLE (1,4,2)
Now, none of this has actually fixed the problem that the texture is mostly black. Even changing the line to MATERIAL ('green') didn't fix it. (It stopped it from running though)
It turns out that the sprite on disk is just a template. It wants to have a skin with the name 'spark' (or green, which I changed it to) - this doesn't mean that it has to be made from the spark.png file.
So, back to the code, and edit the bit that loads the texture onto the sprite.
iTextureWrapper* txt = loader->LoadTexture ("green", "/lib/std/portal.jpg");
That brings the file portal.jpg into memory as a skin named 'green' and then we can give that to the sprite... and it works!
Looking at the manual, it turns out that the reason for this is that skins (materials, it calls them) can have multiple layers, extra shiny effects, bumpmaps etc.
So, we now have a viper with an odd skin (go on, find a skin that looks a bit more like a spaceship to use) {I just did, and discovered that my :d,e numbers are all wrong}
By keeping a reference to the sprite around for later, we can make it move around. Either sliding, or rotating, or any of the things that you expect entities to do.
mySprite->GetMovable()->GetTransform ().RotateThis (VEC_ROT_LEFT, speed);
mySprite->GetMovable()->UpdateMove();
mySprite->DeferUpdateLighting (CS_NLIGHT_STATIC|CS_NLIGHT_DYNAMIC, 10);
Might be useful to you when you try this...
Maybe I'll include my full code later, but for now, back to playing around.
Closing
I'll close with a breif discusison of their SCF system. Basically, it's an object interface - but you have to do AddRef and DecRef so that it knows whether anything is pointing at it, and so whether or not it can throw it away because you're done with it. At least in theory. I'm trying to include an fps indicator (like walktest) but I can't get the innterface to load in - I think it needs something else loaded in first, but it won't tell me what.