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/Line.hh>
38 #include <Moof/Log.hh>
39 #include <Moof/Math.hh>
40 //#include <Moof/Octree.hh>
41 #include <Moof/Script.hh>
42 #include <Moof/Settings.hh>
44 #include "Character.hh"
49 struct Scene::Impl
: public Mf::Library
<Impl
>
51 struct Quad
: public Mf::Entity
61 Quad(const Mf::Vector3 vertices
[4], const std::string
& texture
,
62 Tilemap::Index tileIndex
) :
68 for (int i
= 0, num
= 0; i
< 4; ++i
)
70 for (int j
= 0; j
< 3; ++j
, ++num
)
72 mVertices
[num
] = vertices
[i
][j
];
76 if (!mTilemap
.getTileCoords(tileIndex
, mTexCoords
))
78 Mf::logWarning("no index %d in texture %s", tileIndex
,
81 mTexCoords
[0] = mTexCoords
[1] =
82 mTexCoords
[3] = mTexCoords
[6] = 0.0;
83 mTexCoords
[2] = mTexCoords
[4] =
84 mTexCoords
[5] = mTexCoords
[7] = 1.0;
87 mAabb
.encloseVertices(vertices
, 4);
88 mSphere
.point
= mAabb
.getCenter();
89 mSphere
.radius
= (mAabb
.min
- mSphere
.point
).length();
92 void setBlending(bool blending
)
102 void setSurface(SURFACE type
)
107 SURFACE
getSurface() const
112 void draw(Mf::Scalar alpha
= 0.0) const
117 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
123 glFogi(GL_FOG_MODE
, GL_LINEAR
);
126 //glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
129 glVertexPointer(3, GL_SCALAR
, 0, mVertices
);
130 glTexCoordPointer(2, GL_SCALAR
, 0, mTexCoords
);
132 glDrawArrays(GL_TRIANGLE_FAN
, 0, 4);
138 bool isVisible(const Mf::Frustum
& frustum
) const
140 return mSphere
.isVisible(frustum
);
144 Mf::Scalar mVertices
[12];
145 Mf::Scalar mTexCoords
[8];
156 Mf::Matrix4 mTransform
;
157 std::string mTexture
;
159 //Mf::Octree<Quad>::Ptr mOctree;
160 std::list
< boost::shared_ptr
<Impl::Quad
> > mObjects
;
161 std::list
< Mf::Line
<2> > mLines
;
174 explicit Impl(const std::string
& name
) :
175 Mf::Library
<Impl
>(name
) {}
177 void importSceneBindings(Mf::Script
& script
)
179 script
.importFunction("SetBounds",
180 boost::bind(&Impl::setBounds
, this, _1
));
181 script
.importFunction("ResetTransform",
182 boost::bind(&Impl::resetTransform
, this, _1
));
183 script
.importFunction("Translate",
184 boost::bind(&Impl::translate
, this, _1
));
185 script
.importFunction("Scale",
186 boost::bind(&Impl::scale
, this, _1
));
187 script
.importFunction("Rotate",
188 boost::bind(&Impl::rotate
, this, _1
));
189 script
.importFunction("SetTexture",
190 boost::bind(&Impl::setTexture
, this, _1
));
191 script
.importFunction("DrawTilemap",
192 boost::bind(&Impl::drawTilemap
, this, _1
));
193 script
.importFunction("DrawTile",
194 boost::bind(&Impl::drawTile
, this, _1
));
197 Mf::Settings::getInstance().get("detail", detail
);
198 script
.push(detail
); script
.set("detail");
200 script
.push(1); script
.set("LOW");
201 script
.push(2); script
.set("MEDIUM");
202 script
.push(3); script
.set("HIGH");
204 script
.push(X
); script
.set("X");
205 script
.push(Y
); script
.set("Y");
206 script
.push(Z
); script
.set("Z");
208 script
.push(Quad::LEFT
); script
.set("LEFT");
209 script
.push(Quad::RIGHT
); script
.set("RIGHT");
210 script
.push(Quad::TOP
); script
.set("TOP");
214 Mf::Script::Status
load(Mf::Script
& script
)
216 std::string filePath
= Scene::getPath(getName());
217 if (filePath
== "") return Mf::Script::FILE_ERROR
;
219 importSceneBindings(script
);
220 return script
.doFile(filePath
);
224 static int loadBox(Mf::Script
& script
, Mf::Aabb
<3>& aabb
)
226 Mf::Script::Value table
[] =
228 script
[1].requireTable(),
229 script
[2].requireTable()
232 for (int i
= 0; i
<= 1; ++i
)
234 for (int j
= 1; j
<= 3; ++j
)
237 table
[i
].pushField();
241 script
[3].get(aabb
.min
[0]);
242 script
[4].get(aabb
.min
[1]);
243 script
[5].get(aabb
.min
[2]);
244 script
[6].get(aabb
.max
[0]);
245 script
[7].get(aabb
.max
[1]);
246 script
[8].get(aabb
.max
[2]);
251 int setBounds(Mf::Script
& script
)
253 int ret
= loadBox(script
, mBounds
);
254 //mOctree = Mf::Octree<Quad>::alloc(mBounds);
258 int resetTransform(Mf::Script
& script
)
260 mTransform
.identity();
264 int translate(Mf::Script
& script
)
266 Mf::Script::Value x
= script
[1].requireNumber();
267 Mf::Script::Value y
= script
[2].requireNumber();
268 Mf::Script::Value z
= script
[3].requireNumber();
275 Mf::Matrix4 translation
;
276 cml::matrix_translation(translation
, vec
);
277 mTransform
= translation
* mTransform
;
282 int scale(Mf::Script
& script
)
284 if (script
.getSize() == 3)
287 script
[1].requireNumber().get(vec
[0]);
288 script
[2].requireNumber().get(vec
[1]);
289 script
[3].requireNumber().get(vec
[2]);
292 cml::matrix_scale(scaling
, vec
);
293 mTransform
= scaling
* mTransform
;
295 else if (script
.getSize() == 1)
297 Mf::Scalar value
= 1.0;
298 script
[1].requireNumber().get(value
);
301 cml::matrix_uniform_scale(scaling
, value
);
302 mTransform
= scaling
* mTransform
;
306 script
.getTop().throwError("wrong number of arguments");
312 int rotate(Mf::Script
& script
)
314 Mf::Script::Value axis
= script
[1].requireNumber();
315 Mf::Script::Value angle
= script
[2].requireNumber();
323 cml::matrix_rotate_about_world_axis(mTransform
, index
, cml::rad(value
));
328 int setTexture(Mf::Script
& script
)
330 script
[1].requireString().get(mTexture
);
334 int drawTilemap(Mf::Script
& script
)
336 Mf::Script::Value table
= script
[1].requireTable();
337 Mf::Script::Value top
= script
[-1];
339 Quad::SURFACE surface
;
340 table
.pushField("surface");
347 table
.pushField("width");
353 //table.pushField("tiles");
354 Mf::Script::Value tiles
= script
.getTop();
355 nTiles
= tiles
.getLength();
357 if (nTiles
% width
!= 0) table
.throwError("invalid number of tiles");
359 std::vector
< std::vector
<Tilemap::Index
> > indices
;
363 height
= nTiles
/ width
;
364 indices
.resize(height
);
366 // the indices are stored upside-down in the scene file so that they are
367 // easier to edit as text, so we'll need to load them last row first
370 for (h
= height
- 1; h
>= 0; --h
)
372 std::vector
<Tilemap::Index
> row
;
374 for (w
= 0; w
< width
; ++w
, ++i
)
376 script
.checkStack(2);
380 Tilemap::Index index
;
383 row
.push_back(index
);
389 Mf::Vector4 vertices
[height
+1][width
+1];
391 Mf::Matrix4 transposedTransform
= mTransform
;
392 transposedTransform
.transpose();
394 for (int h
= 0; h
<= height
; ++h
)
396 for (int w
= 0; w
<= width
; ++w
)
398 vertices
[h
][w
] = Mf::Vector4(w
, h
, 0.0, 1.0) * transposedTransform
;
402 for (int h
= 0; h
< height
; ++h
)
404 for (int w
= 0; w
< width
; ++w
)
406 if (indices
[h
][w
] == Tilemap::NO_TILE
) continue;
408 Mf::Vector3 demotedVertices
[4];
410 demotedVertices
[0] = Mf::demote(vertices
[h
][w
]);
411 demotedVertices
[1] = Mf::demote(vertices
[h
][w
+1]);
412 demotedVertices
[2] = Mf::demote(vertices
[h
+1][w
+1]);
413 demotedVertices
[3] = Mf::demote(vertices
[h
+1][w
]);
415 Quad
* quad
= new Quad(demotedVertices
, mTexture
, indices
[h
][w
]);
416 quad
->setSurface(surface
);
418 if (surface
!= Quad::NONE
)
420 // need a 2d line for collisions
421 // assuming the camera always looks directly to -z when the
422 // scene is built, simply demoting the vector again should
423 // project the points to the xy-plane
426 boost::shared_ptr
<Quad
> quadPtr(quad
);
427 //mOctree->insert(quadPtr);
428 mObjects
.push_back(quadPtr
);
435 int drawTile(Mf::Script
& script
)
437 Mf::Script::Value param
= script
[1];
438 Mf::Script::Value top
= script
[-1];
440 Tilemap::Index index
= 0;
442 bool blending
= false;
451 param
.pushField("u_scale");
454 param
.pushField("blend");
457 param
.pushField("fog");
460 else if (param
.isNumber())
465 Mf::Vector4 vertices
[2][width
+1];
467 Mf::Matrix4 transposedTransform
= mTransform
;
468 transposedTransform
.transpose();
471 Mf::Scalar increment
= 1.0 / Mf::Scalar(width
);
473 for (int h
= 0; h
<= 1; ++h
)
476 for (int w
= 0; w
<= width
; ++w
, xf
+= increment
)
478 vertices
[h
][w
] = Mf::Vector4(xf
, Mf::Scalar(h
), 0.0, 1.0) *
483 for (int w
= 0; w
< width
; ++w
)
485 Mf::Vector3 demotedVertices
[4];
487 demotedVertices
[0] = Mf::demote(vertices
[0][w
]);
488 demotedVertices
[1] = Mf::demote(vertices
[0][w
+1]);
489 demotedVertices
[2] = Mf::demote(vertices
[1][w
+1]);
490 demotedVertices
[3] = Mf::demote(vertices
[1][w
]);
492 Quad
* quad
= new Quad(demotedVertices
, mTexture
, index
);
493 quad
->setBlending(blending
);
496 boost::shared_ptr
<Quad
> quadPtr(quad
);
497 //mOctree->insert(quadPtr);
498 mObjects
.push_back(quadPtr
);
506 Scene::Scene(const std::string
& name
) :
508 mImpl(Scene::Impl::getInstance(name
)) {}
511 Mf::Script::Status
Scene::load(Mf::Script
& script
)
514 return mImpl
->load(script
);
518 void Scene::draw(Mf::Scalar alpha
) const
520 //mImpl->mOctree->draw(alpha);
521 std::list
< boost::shared_ptr
<Impl::Quad
> >& objects
= mImpl
->mObjects
;
522 std::list
< boost::shared_ptr
<Impl::Quad
> >::const_iterator it
;
524 for (it
= objects
.begin(); it
!= objects
.end(); ++it
)
529 mImpl
->mBounds
.draw();
532 void Scene::drawIfVisible(Mf::Scalar alpha
, const Mf::Frustum
& frustum
) const
534 //mImpl->mOctree->drawIfVisible(alpha, frustum);
535 std::list
< boost::shared_ptr
<Impl::Quad
> >& objects
= mImpl
->mObjects
;
536 std::list
< boost::shared_ptr
<Impl::Quad
> >::const_iterator it
;
538 for (it
= objects
.begin(); it
!= objects
.end(); ++it
)
540 (*it
)->drawIfVisible(alpha
, frustum
);
543 mImpl
->mBounds
.draw();
547 bool Scene::checkForCollision(Character
& character
)
550 //std::list< boost::shared_ptr<Impl::Quad> > objects;
551 //std::list<Mf::Octree<Impl::Quad>::InsertableP> objects;
552 //mImpl->mOctree->getNearbyObjects(objects, character);
554 std::list
< boost::shared_ptr
<Impl::Quad
> >& objects
= mImpl
->mObjects
;
555 std::list
< boost::shared_ptr
<Impl::Quad
> >::const_iterator it
;
558 Mf::Sphere
<3> sphere
= character
.getSphere();
560 for (it
= objects
.begin(); it
!= objects
.end(); ++it
)
562 Impl::Quad::SURFACE type
= (*it
)->getSurface();
563 if (type
== Impl::Quad::NONE
) continue;
565 if (Mf::checkCollision(sphere
, (*it
)->getSphere()))
569 Mf::Vector2
impulse(0.0, 0.0);
570 Mf::Vector2 p
= character
.getState().momentum
;
572 Mf::State2 state
= character
.getState(1.0);
573 sphere
= character
.getSphere();
574 Mf::Scalar alpha
= 1.0;
575 while (Mf::checkCollision(sphere
, (*it
)->getSphere()))
578 state
= character
.getState(alpha
);
581 character
.setPosition(state
.position
);
585 //case Impl::Quad::TOP:
586 //if (p[1] < 0.0) impulse[1] = -p[1];
588 //case Impl::Quad::LEFT:
589 //if (p[0] > 0.0) impulse[0] = 1.5*-p[0];
591 //case Impl::Quad::RIGHT:
592 //if (p[0] < 0.0) impulse[0] = 1.5*-p[0];
596 //character.addImpulse(impulse);
602 Mf::logInfo("collisions: %d", collisions
);
609 std::string
Scene::getPath(const std::string
& name
)
611 return Mf::Resource::getPath("scenes/" + name
+ ".lua");
615 /** vim: set ts=4 sw=4 tw=80: *************************************************/