2 /*******************************************************************************
4 Copyright (c) 2009, Charles McGarvey
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
10 * Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *******************************************************************************/
32 #include <Moof/Aabb.hh>
33 #include <Moof/Camera.hh>
34 #include <Moof/Entity.hh>
35 #include <Moof/Exception.hh>
36 #include <Moof/Library.hh>
37 #include <Moof/Log.hh>
38 #include <Moof/Math.hh>
39 //#include <Moof/Octree.hh>
40 #include <Moof/Script.hh>
41 #include <Moof/Settings.hh>
43 #include "Character.hh"
48 struct Scene::Impl
: public Mf::Library
<Impl
>
50 struct Quad
: public Mf::Entity
60 Quad(const Mf::Vector3 vertices
[4], const std::string
& texture
,
61 Tilemap::Index tileIndex
) :
67 for (int i
= 0, num
= 0; i
< 4; ++i
)
69 for (int j
= 0; j
< 3; ++j
, ++num
)
71 mVertices
[num
] = vertices
[i
][j
];
75 if (!mTilemap
.getTileCoords(tileIndex
, mTexCoords
))
77 Mf::logWarning("no index %d in texture %s", tileIndex
,
80 mTexCoords
[0] = mTexCoords
[1] =
81 mTexCoords
[3] = mTexCoords
[6] = 0.0;
82 mTexCoords
[2] = mTexCoords
[4] =
83 mTexCoords
[5] = mTexCoords
[7] = 1.0;
86 mAabb
.encloseVertices(vertices
, 4);
87 mSphere
.point
= mAabb
.getCenter();
88 mSphere
.radius
= (mAabb
.min
- mSphere
.point
).length();
91 void setBlending(bool blending
)
101 void setSurface(SURFACE type
)
106 SURFACE
getSurface() const
111 void draw(Mf::Scalar alpha
= 0.0) const
116 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
122 glFogi(GL_FOG_MODE
, GL_LINEAR
);
125 //glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
128 glVertexPointer(3, GL_SCALAR
, 0, mVertices
);
129 glTexCoordPointer(2, GL_SCALAR
, 0, mTexCoords
);
131 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
137 bool isVisible(const Mf::Frustum
& frustum
) const
139 return mSphere
.isVisible(frustum
);
143 Mf::Scalar mVertices
[12];
144 Mf::Scalar mTexCoords
[8];
155 Mf::Matrix4 mTransform
;
156 std::string mTexture
;
158 //Mf::Octree<Quad>::Ptr mOctree;
159 std::list
< boost::shared_ptr
<Impl::Quad
> > mObjects
;
172 explicit Impl(const std::string
& name
) :
173 Mf::Library
<Impl
>(name
) {}
175 void importSceneBindings(Mf::Script
& script
)
177 script
.importFunction("SetBounds",
178 boost::bind(&Impl::setBounds
, this, _1
));
179 script
.importFunction("ResetTransform",
180 boost::bind(&Impl::resetTransform
, this, _1
));
181 script
.importFunction("Translate",
182 boost::bind(&Impl::translate
, this, _1
));
183 script
.importFunction("Scale",
184 boost::bind(&Impl::scale
, this, _1
));
185 script
.importFunction("Rotate",
186 boost::bind(&Impl::rotate
, this, _1
));
187 script
.importFunction("SetTexture",
188 boost::bind(&Impl::setTexture
, this, _1
));
189 script
.importFunction("DrawTilemap",
190 boost::bind(&Impl::drawTilemap
, this, _1
));
191 script
.importFunction("DrawTile",
192 boost::bind(&Impl::drawTile
, this, _1
));
195 Mf::Settings::getInstance().get("detail", detail
);
196 script
.push(detail
); script
.set("detail");
198 script
.push(1); script
.set("LOW");
199 script
.push(2); script
.set("MEDIUM");
200 script
.push(3); script
.set("HIGH");
202 script
.push(X
); script
.set("X");
203 script
.push(Y
); script
.set("Y");
204 script
.push(Z
); script
.set("Z");
206 script
.push(Quad::LEFT
); script
.set("LEFT");
207 script
.push(Quad::RIGHT
); script
.set("RIGHT");
208 script
.push(Quad::TOP
); script
.set("TOP");
212 Mf::Script::Status
load(Mf::Script
& script
)
214 std::string filePath
= Scene::getPath(getName());
215 if (filePath
== "") return Mf::Script::FILE_ERROR
;
217 importSceneBindings(script
);
218 return script
.doFile(filePath
);
222 static int loadBox(Mf::Script
& script
, Mf::Aabb
& aabb
)
224 Mf::Script::Value table
[] =
226 script
[1].requireTable(),
227 script
[2].requireTable()
230 for (int i
= 0; i
<= 1; ++i
)
232 for (int j
= 1; j
<= 3; ++j
)
235 table
[i
].pushField();
239 script
[3].get(aabb
.min
[0]);
240 script
[4].get(aabb
.min
[1]);
241 script
[5].get(aabb
.min
[2]);
242 script
[6].get(aabb
.max
[0]);
243 script
[7].get(aabb
.max
[1]);
244 script
[8].get(aabb
.max
[2]);
249 int setBounds(Mf::Script
& script
)
251 int ret
= loadBox(script
, mBounds
);
252 //mOctree = Mf::Octree<Quad>::alloc(mBounds);
256 int resetTransform(Mf::Script
& script
)
258 mTransform
.identity();
262 int translate(Mf::Script
& script
)
264 Mf::Script::Value x
= script
[1].requireNumber();
265 Mf::Script::Value y
= script
[2].requireNumber();
266 Mf::Script::Value z
= script
[3].requireNumber();
273 Mf::Matrix4 translation
;
274 cml::matrix_translation(translation
, vec
);
275 mTransform
= translation
* mTransform
;
280 int scale(Mf::Script
& script
)
282 if (script
.getSize() == 3)
285 script
[1].requireNumber().get(vec
[0]);
286 script
[2].requireNumber().get(vec
[1]);
287 script
[3].requireNumber().get(vec
[2]);
290 cml::matrix_scale(scaling
, vec
);
291 mTransform
= scaling
* mTransform
;
293 else if (script
.getSize() == 1)
295 Mf::Scalar value
= 1.0;
296 script
[1].requireNumber().get(value
);
299 cml::matrix_uniform_scale(scaling
, value
);
300 mTransform
= scaling
* mTransform
;
304 script
.getTop().throwError("wrong number of arguments");
310 int rotate(Mf::Script
& script
)
312 Mf::Script::Value axis
= script
[1].requireNumber();
313 Mf::Script::Value angle
= script
[2].requireNumber();
321 cml::matrix_rotate_about_world_axis(mTransform
, index
, cml::rad(value
));
326 int setTexture(Mf::Script
& script
)
328 script
[1].requireString().get(mTexture
);
332 int drawTilemap(Mf::Script
& script
)
334 Mf::Script::Value table
= script
[1].requireTable();
335 Mf::Script::Value top
= script
[-1];
337 Quad::SURFACE surface
;
338 table
.pushField("surface");
345 table
.pushField("width");
351 //table.pushField("tiles");
352 Mf::Script::Value tiles
= script
.getTop();
353 nTiles
= tiles
.getLength();
355 if (nTiles
% width
!= 0) table
.throwError("invalid number of tiles");
357 std::vector
< std::vector
<Tilemap::Index
> > indices
;
361 height
= nTiles
/ width
;
362 indices
.resize(height
);
364 // the indices are stored upside-down in the scene file so that they are
365 // easier to edit as text, so we'll need to load them last row first
368 for (h
= height
- 1; h
>= 0; --h
)
370 std::vector
<Tilemap::Index
> row
;
372 for (w
= 0; w
< width
; ++w
, ++i
)
374 script
.checkStack(2);
378 Tilemap::Index index
;
381 row
.push_back(index
);
387 Mf::Vector4 vertices
[height
+1][width
+1];
389 Mf::Matrix4 transposedTransform
= mTransform
;
390 transposedTransform
.transpose();
392 for (int h
= 0; h
<= height
; ++h
)
394 for (int w
= 0; w
<= width
; ++w
)
396 vertices
[h
][w
] = Mf::Vector4(w
, h
, 0.0, 1.0) * transposedTransform
;
400 for (int h
= 0; h
< height
; ++h
)
402 for (int w
= 0; w
< width
; ++w
)
404 if (indices
[h
][w
] == Tilemap::NO_TILE
) continue;
406 Mf::Vector3 demotedVertices
[4];
408 demotedVertices
[0] = Mf::demote(vertices
[h
][w
]);
409 demotedVertices
[1] = Mf::demote(vertices
[h
][w
+1]);
410 demotedVertices
[2] = Mf::demote(vertices
[h
+1][w
+1]);
411 demotedVertices
[3] = Mf::demote(vertices
[h
+1][w
]);
413 Quad
* quad
= new Quad(demotedVertices
, mTexture
, indices
[h
][w
]);
414 quad
->setSurface(surface
);
416 boost::shared_ptr
<Quad
> quadPtr(quad
);
417 //mOctree->insert(quadPtr);
418 mObjects
.push_back(quadPtr
);
425 int drawTile(Mf::Script
& script
)
427 Mf::Script::Value param
= script
[1];
428 Mf::Script::Value top
= script
[-1];
430 Tilemap::Index index
= 0;
432 bool blending
= false;
441 param
.pushField("u_scale");
444 param
.pushField("blend");
447 param
.pushField("fog");
450 else if (param
.isNumber())
455 Mf::Vector4 vertices
[2][width
+1];
457 Mf::Matrix4 transposedTransform
= mTransform
;
458 transposedTransform
.transpose();
461 Mf::Scalar increment
= 1.0 / Mf::Scalar(width
);
463 for (int h
= 0; h
<= 1; ++h
)
466 for (int w
= 0; w
<= width
; ++w
, xf
+= increment
)
468 vertices
[h
][w
] = Mf::Vector4(xf
, Mf::Scalar(h
), 0.0, 1.0) *
473 for (int w
= 0; w
< width
; ++w
)
475 Mf::Vector3 demotedVertices
[4];
477 demotedVertices
[0] = Mf::demote(vertices
[0][w
]);
478 demotedVertices
[1] = Mf::demote(vertices
[0][w
+1]);
479 demotedVertices
[2] = Mf::demote(vertices
[1][w
+1]);
480 demotedVertices
[3] = Mf::demote(vertices
[1][w
]);
482 Quad
* quad
= new Quad(demotedVertices
, mTexture
, index
);
483 quad
->setBlending(blending
);
486 boost::shared_ptr
<Quad
> quadPtr(quad
);
487 //mOctree->insert(quadPtr);
488 mObjects
.push_back(quadPtr
);
496 Scene::Scene(const std::string
& name
) :
498 mImpl(Scene::Impl::getInstance(name
)) {}
501 Mf::Script::Status
Scene::load(Mf::Script
& script
)
504 return mImpl
->load(script
);
508 void Scene::draw(Mf::Scalar alpha
) const
510 //mImpl->mOctree->draw(alpha);
511 std::list
< boost::shared_ptr
<Impl::Quad
> >& objects
= mImpl
->mObjects
;
512 std::list
< boost::shared_ptr
<Impl::Quad
> >::const_iterator it
;
514 for (it
= objects
.begin(); it
!= objects
.end(); ++it
)
519 mImpl
->mBounds
.draw();
522 void Scene::drawIfVisible(Mf::Scalar alpha
, const Mf::Frustum
& frustum
) const
524 //mImpl->mOctree->drawIfVisible(alpha, frustum);
525 std::list
< boost::shared_ptr
<Impl::Quad
> >& objects
= mImpl
->mObjects
;
526 std::list
< boost::shared_ptr
<Impl::Quad
> >::const_iterator it
;
528 for (it
= objects
.begin(); it
!= objects
.end(); ++it
)
530 (*it
)->drawIfVisible(alpha
, frustum
);
533 mImpl
->mBounds
.draw();
537 bool Scene::checkForCollision(Character
& character
)
540 //std::list< boost::shared_ptr<Impl::Quad> > objects;
541 //std::list<Mf::Octree<Impl::Quad>::InsertableP> objects;
542 //mImpl->mOctree->getNearbyObjects(objects, character);
544 std::list
< boost::shared_ptr
<Impl::Quad
> >& objects
= mImpl
->mObjects
;
545 std::list
< boost::shared_ptr
<Impl::Quad
> >::const_iterator it
;
548 Mf::Sphere sphere
= character
.getSphere();
550 for (it
= objects
.begin(); it
!= objects
.end(); ++it
)
552 Impl::Quad::SURFACE type
= (*it
)->getSurface();
553 if (type
== Impl::Quad::NONE
) continue;
555 if (Mf::checkCollision(sphere
, (*it
)->getSphere()))
559 Mf::Vector2
impulse(0.0, 0.0);
560 Mf::Vector2 p
= character
.getState().momentum
;
562 Mf::State2 state
= character
.getState(1.0);
563 sphere
= character
.getSphere();
564 Mf::Scalar alpha
= 1.0;
565 while (Mf::checkCollision(sphere
, (*it
)->getSphere()))
568 state
= character
.getState(alpha
);
571 character
.setPosition(state
.position
);
575 //case Impl::Quad::TOP:
576 //if (p[1] < 0.0) impulse[1] = -p[1];
578 //case Impl::Quad::LEFT:
579 //if (p[0] > 0.0) impulse[0] = 1.5*-p[0];
581 //case Impl::Quad::RIGHT:
582 //if (p[0] < 0.0) impulse[0] = 1.5*-p[0];
586 //character.addImpulse(impulse);
592 Mf::logInfo("collisions: %d", collisions
);
599 std::string
Scene::getPath(const std::string
& name
)
601 return Mf::Resource::getPath("scenes/" + name
+ ".lua");
605 /** vim: set ts=4 sw=4 tw=80: *************************************************/