GRIM: Better handling of the bounding boxes for the actors' text objects.

This commit is contained in:
Giulio Camuffo 2011-12-12 18:57:17 +01:00
parent 54e3b584fa
commit e6ccad7657
11 changed files with 207 additions and 161 deletions

View file

@ -1165,20 +1165,6 @@ void Actor::draw() {
}
}
int x1, y1, x2, y2;
int *px1, *py1, *px2, *py2;
if (_mustPlaceText) {
px1 = &x1;
py1 = &y1;
px2 = &x2;
py2 = &y2;
x1 = y1 = 1000;
x2 = y2 = -1000;
} else {
px1 = py1 = px2 = py2 = NULL;
}
if (!_costumeStack.empty()) {
Costume *costume = _costumeStack.back();
for (int l = 0; l < 5; l++) {
@ -1196,11 +1182,20 @@ void Actor::draw() {
}
// normal draw actor
g_driver->startActorDraw(_pos, _scale, _yaw, _pitch, _roll);
costume->draw(px1, py1, px2, py2);
costume->draw();
g_driver->finishActorDraw();
}
if (_mustPlaceText) {
int x1, y1, x2, y2;
x1 = y1 = 1000;
x2 = y2 = -1000;
if (!_costumeStack.empty()) {
g_driver->startActorDraw(_pos, _scale, _yaw, _pitch, _roll);
_costumeStack.back()->getBoundingBox(&x1, &y1, &x2, &y2);
g_driver->finishActorDraw();
}
TextObject *textObject = TextObject::getPool().getObject(_sayLineText);
if (textObject) {
if (x1 == 1000 || x2 == -1000 || y2 == -1000) {

View file

@ -148,13 +148,16 @@ public:
void resetColormap();
void setMatrix(Math::Matrix4 matrix) { _matrix = matrix; };
void restoreState(SaveGame *state);
void translateObject(bool reset);
static void translateObject(ModelNode *node, bool reset);
AnimManager *getAnimManager() const;
~ModelComponent();
ModelNode *getHierarchy() { return _hier; }
int getNumNodes() { return _obj->getNumNodes(); }
Model *getModel() { return _obj; }
void draw(int *x1, int *y1, int *x2, int *y2);
void draw();
void getBoundingBox(int *x1, int *y1, int *x2, int *y2);
protected:
Common::String _filename;
@ -440,22 +443,25 @@ ModelComponent::~ModelComponent() {
delete[] _hier;
}
void translateObject(ModelNode *node, bool reset) {
void ModelComponent::translateObject(ModelNode *node, bool reset) {
if (node->_parent)
translateObject(node->_parent, reset);
if (reset) {
g_driver->translateViewpointFinish();
node->translateViewpointBack();
} else {
Math::Vector3d animPos = node->_pos + node->_animPos;
Math::Angle animPitch = node->_pitch + node->_animPitch;
Math::Angle animYaw = node->_yaw + node->_animYaw;
Math::Angle animRoll = node->_roll + node->_animRoll;
g_driver->translateViewpointStart(animPos, animPitch, animYaw, animRoll);
node->translateViewpoint();
}
}
void ModelComponent::draw(int *x1, int *y1, int *x2, int *y2) {
void ModelComponent::translateObject(bool res) {
ModelNode *node = _hier->_parent;
if (node) {
translateObject(node, res);
}
}
void ModelComponent::draw() {
// If the object was drawn by being a component
// of it's parent then don't draw it
@ -463,14 +469,28 @@ void ModelComponent::draw(int *x1, int *y1, int *x2, int *y2) {
return;
// Need to translate object to be in accordance
// with the setup of the parent
if (_hier->_parent)
translateObject(_hier->_parent, false);
translateObject(false);
_hier->draw(x1, y1, x2, y2);
_hier->draw();
// Need to un-translate when done
if (_hier->_parent)
translateObject(_hier->_parent, true);
translateObject(true);
}
void ModelComponent::getBoundingBox(int *x1, int *y1, int *x2, int *y2) {
// If the object was drawn by being a component
// of it's parent then don't draw it
if (_parent && _parent->isVisible())
return;
// Need to translate object to be in accordance
// with the setup of the parent
translateObject(false);
_hier->getBoundingBox(x1, y1, x2, y2);
// Need to un-translate when done
translateObject(true);
}
MainModelComponent::MainModelComponent(Costume::Component *p, int parentID, const char *filename, Costume::Component *prevComponent, tag32 t) :
@ -1347,26 +1367,28 @@ Costume::Component *Costume::loadComponentEMI(Costume::Component *parent, int pa
return NULL;
}
ModelNode *Costume::getModelNodes() {
ModelComponent *Costume::getMainModelComponent() const {
for (int i = 0; i < _numComponents; i++) {
if (!_components[i])
continue;
// Needs to handle Main Models (pigeons) and normal Models
// (when Manny climbs the rope)
if (FROM_BE_32(_components[i]->getTag()) == MKTAG('M','M','D','L'))
return dynamic_cast<ModelComponent *>(_components[i])->getHierarchy();
return static_cast<ModelComponent *>(_components[i]);
}
return NULL;
}
ModelNode *Costume::getModelNodes() {
ModelComponent *comp = getMainModelComponent();
if (comp) {
return comp->getHierarchy();
}
return NULL;
}
Model *Costume::getModel() {
for (int i = 0; i < _numComponents; i++) {
if (!_components[i])
continue;
// Needs to handle Main Models (pigeons) and normal Models
// (when Manny climbs the rope)
if (FROM_BE_32(_components[i]->getTag()) == MKTAG('M','M','D','L'))
return dynamic_cast<ModelComponent *>(_components[i])->getModel();
ModelComponent *comp = getMainModelComponent();
if (comp) {
return comp->getModel();
}
return NULL;
}
@ -1482,13 +1504,16 @@ void Costume::setupTextures() {
void Costume::draw() {
for (int i = 0; i < _numComponents; i++)
if (_components[i])
_components[i]->draw(NULL, NULL, NULL, NULL);
_components[i]->draw();
}
void Costume::draw(int *x1, int *y1, int *x2, int *y2) {
for (int i = 0; i < _numComponents; i++)
if (_components[i])
_components[i]->draw(x1, y1, x2, y2);
void Costume::getBoundingBox(int *x1, int *y1, int *x2, int *y2) {
for (int i = 0; i < _numComponents; i++) {
ModelComponent *c = dynamic_cast<ModelComponent *>(_components[i]);
if (c) {
c->getBoundingBox(x1, y1, x2, y2);
}
}
}
int Costume::update(float time) {

View file

@ -41,6 +41,7 @@ class CMap;
class Model;
class ModelNode;
class TextSplitter;
class ModelComponent;
class Costume : public Object {
public:
@ -78,7 +79,7 @@ public:
void animate();
void setupTextures();
void draw();
void draw(int *x1, int *y1, int *x2, int *y2);
void getBoundingBox(int *x1, int *y1, int *x2, int *y2);
void setPosRotate(Math::Vector3d pos, const Math::Angle &pitch,
const Math::Angle &yaw, const Math::Angle &roll);
Math::Matrix4 getMatrix() const;
@ -104,7 +105,7 @@ public:
virtual int update(float time) { return 0; }
virtual void animate() { }
virtual void setupTexture() { }
virtual void draw(int *x1, int *y1, int *x2, int *y2) { }
virtual void draw() { }
virtual void reset() { }
virtual void resetColormap() { }
virtual void saveState(SaveGame *) { }
@ -130,6 +131,7 @@ public:
private:
Component *loadComponent(tag32 tag, Component *parent, int parentID, const char *name, Component *prevComponent);
Component *loadComponentEMI(Costume::Component *parent, int parentID, const char *name, Costume::Component *prevComponent);
ModelComponent *getMainModelComponent() const;
Common::String _fname;
Costume *_prevCostume;

View file

@ -28,10 +28,23 @@ namespace Grim {
GfxBase::GfxBase() :
_renderBitmaps(true),
_renderZBitmaps(true) {
_renderZBitmaps(true),
_shadowModeActive(false) {
}
void GfxBase::setShadowMode() {
_shadowModeActive = true;
}
void GfxBase::clearShadowMode() {
_shadowModeActive = false;
}
bool GfxBase::isShadowModeActive() {
return _shadowModeActive;
}
void GfxBase::saveState(SaveGame *state) {
state->beginSection('DRVR');

View file

@ -93,18 +93,19 @@ public:
virtual void finishActorDraw() = 0;
virtual void setShadow(Shadow *shadow) = 0;
virtual void drawShadowPlanes() = 0;
virtual void setShadowMode() = 0;
virtual void clearShadowMode() = 0;
virtual void setShadowMode();
virtual void clearShadowMode();
bool isShadowModeActive();
virtual void setShadowColor(byte r, byte g, byte b) = 0;
virtual void getShadowColor(byte *r, byte *g, byte *b) = 0;
virtual void set3DMode() = 0;
virtual void translateViewpointStart(Math::Vector3d pos, const Math::Angle &pitch,
const Math::Angle &yaw, const Math::Angle &roll) = 0;
virtual void translateViewpointStart() = 0;
virtual void translateViewpoint(const Math::Vector3d &vec) = 0;
virtual void rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis) = 0;
virtual void translateViewpointFinish() = 0;
virtual void drawHierachyNode(const ModelNode *node, int *x1, int *y1, int *x2, int *y2) = 0;
virtual void drawModelFace(const MeshFace *face, float *vertices, float *vertNormals, float *textureVerts) = 0;
virtual void drawSprite(const Sprite *sprite) = 0;
@ -227,6 +228,7 @@ protected:
unsigned char _shadowColorB;
bool _renderBitmaps;
bool _renderZBitmaps;
bool _shadowModeActive;
};
// Factory-like functions:

View file

@ -398,10 +398,12 @@ void GfxOpenGL::drawShadowPlanes() {
}
void GfxOpenGL::setShadowMode() {
GfxBase::setShadowMode();
}
void GfxOpenGL::clearShadowMode() {
GfxBase::clearShadowMode();
glDisable(GL_STENCIL_TEST);
glDepthMask(GL_TRUE);
}
@ -487,57 +489,24 @@ void GfxOpenGL::drawSprite(const Sprite *sprite) {
glPopMatrix();
}
void GfxOpenGL::translateViewpointStart(Math::Vector3d pos, const Math::Angle &pitch,
const Math::Angle &yaw, const Math::Angle &roll) {
void GfxOpenGL::translateViewpointStart() {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
}
glTranslatef(pos.x(), pos.y(), pos.z());
glRotatef(yaw.getDegrees(), 0, 0, 1);
glRotatef(pitch.getDegrees(), 1, 0, 0);
glRotatef(roll.getDegrees(), 0, 1, 0);
void GfxOpenGL::translateViewpoint(const Math::Vector3d &vec) {
glTranslatef(vec.x(), vec.y(), vec.z());
}
void GfxOpenGL::rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis) {
glRotatef(angle.getDegrees(), axis.x(), axis.y(), axis.z());
}
void GfxOpenGL::translateViewpointFinish() {
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
void GfxOpenGL::drawHierachyNode(const ModelNode *node, int *x1, int *y1, int *x2, int *y2) {
Math::Vector3d animPos = node->_pos + node->_animPos;
Math::Angle animPitch = node->_pitch + node->_animPitch;
Math::Angle animYaw = node->_yaw + node->_animYaw;
Math::Angle animRoll = node->_roll + node->_animRoll;
translateViewpointStart(animPos, animPitch, animYaw, animRoll);
if (node->_hierVisible) {
glPushMatrix();
glTranslatef(node->_pivot.x(), node->_pivot.y(), node->_pivot.z());
if (!_currentShadowArray) {
Sprite* sprite = node->_sprite;
while (sprite) {
sprite->draw();
sprite = sprite->_next;
}
}
if (node->_mesh && node->_meshVisible) {
node->_mesh->draw(x1, y1, x2, y2);
}
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
if (node->_child) {
node->_child->draw(x1, y1, x2, y2);
glMatrixMode(GL_MODELVIEW);
}
}
translateViewpointFinish();
if (node->_sibling)
node->_sibling->draw(x1, y1, x2, y2);
}
void GfxOpenGL::enableLights() {
glEnable(GL_LIGHTING);
}

View file

@ -73,11 +73,11 @@ public:
void set3DMode();
void translateViewpointStart(Math::Vector3d pos, const Math::Angle &pitch,
const Math::Angle &yaw, const Math::Angle &roll);
void translateViewpointStart();
void translateViewpoint(const Math::Vector3d &vec);
void rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis);
void translateViewpointFinish();
void drawHierachyNode(const ModelNode *node, int *x1, int *y1, int *x2, int *y2);
void drawModelFace(const MeshFace *face, float *vertices, float *vertNormals, float *textureVerts);
void drawSprite(const Sprite *sprite);

View file

@ -433,10 +433,12 @@ void GfxTinyGL::drawShadowPlanes() {
}
void GfxTinyGL::setShadowMode() {
GfxBase::setShadowMode();
tglEnable(TGL_SHADOW_MODE);
}
void GfxTinyGL::clearShadowMode() {
GfxBase::clearShadowMode();
tglDisable(TGL_SHADOW_MODE);
}
@ -519,56 +521,23 @@ void GfxTinyGL::drawSprite(const Sprite *sprite) {
tglPopMatrix();
}
void GfxTinyGL::translateViewpointStart(Math::Vector3d pos, const Math::Angle &pitch,
const Math::Angle &yaw, const Math::Angle &roll) {
void GfxTinyGL::translateViewpointStart() {
tglMatrixMode(TGL_MODELVIEW);
tglPushMatrix();
}
tglTranslatef(pos.x(), pos.y(), pos.z());
tglRotatef(yaw.getDegrees(), 0, 0, 1);
tglRotatef(pitch.getDegrees(), 1, 0, 0);
tglRotatef(roll.getDegrees(), 0, 1, 0);
void GfxTinyGL::translateViewpoint(const Math::Vector3d &vec) {
tglTranslatef(vec.x(), vec.y(), vec.z());
}
void GfxTinyGL::rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis) {
tglRotatef(angle.getDegrees(), axis.x(), axis.y(), axis.z());
}
void GfxTinyGL::translateViewpointFinish() {
tglPopMatrix();
}
void GfxTinyGL::drawHierachyNode(const ModelNode *node, int *x1, int *y1, int *x2, int *y2) {
Math::Vector3d animPos = node->_pos + node->_animPos;
Math::Angle animPitch = node->_pitch + node->_animPitch;
Math::Angle animYaw = node->_yaw + node->_animYaw;
Math::Angle animRoll = node->_roll + node->_animRoll;
translateViewpointStart(animPos, animPitch, animYaw, animRoll);
if (node->_hierVisible) {
tglPushMatrix();
tglTranslatef(node->_pivot.x(), node->_pivot.y(), node->_pivot.z());
if (!_currentShadowArray) {
Sprite* sprite = node->_sprite;
while (sprite) {
sprite->draw();
sprite = sprite->_next;
}
}
if (node->_mesh && node->_meshVisible) {
node->_mesh->draw(x1, y1, x2, y2);
}
tglMatrixMode(TGL_MODELVIEW);
tglPopMatrix();
if (node->_child) {
node->_child->draw(x1, y1, x2, y2);
tglMatrixMode(TGL_MODELVIEW);
}
}
translateViewpointFinish();
if (node->_sibling)
node->_sibling->draw(x1, y1, x2, y2);
}
void GfxTinyGL::enableLights() {
tglEnable(TGL_LIGHTING);
}

View file

@ -64,11 +64,11 @@ public:
void set3DMode();
void translateViewpointStart(Math::Vector3d pos, const Math::Angle &pitch,
const Math::Angle &yaw, const Math::Angle &roll);
void translateViewpointStart();
void translateViewpoint(const Math::Vector3d &vec);
void rotateViewpoint(const Math::Angle &angle, const Math::Vector3d &axis);
void translateViewpointFinish();
void drawHierachyNode(const ModelNode *node, int *x1, int *y1, int *x2, int *y2);
void drawModelFace(const MeshFace *face, float *vertices, float *vertNormals, float *textureVerts);
void drawSprite(const Sprite *sprite);

View file

@ -247,7 +247,7 @@ void Model::loadText(TextSplitter *ts, CMap *cmap) {
}
void Model::draw() const {
_rootHierNode->draw(NULL, NULL, NULL, NULL);
_rootHierNode->draw();
}
ModelNode *Model::copyHierarchy() {
@ -549,18 +549,7 @@ void Mesh::changeMaterials(Material *materials[]) {
_faces[i].changeMaterial(materials[_materialid[i]]);
}
void Mesh::draw(int *x1, int *y1, int *x2, int *y2) const {
if (x1) {
int winX1, winY1, winX2, winY2;
g_driver->getBoundingBoxPos(this, &winX1, &winY1, &winX2, &winY2);
if (winX1 != -1 && winY1 != -1 && winX2 != -1 && winY2 != -1) {
*x1 = MIN(*x1, winX1);
*y1 = MIN(*y1, winY1);
*x2 = MAX(*x2, winX2);
*y2 = MAX(*y2, winY2);
}
}
void Mesh::draw() const {
if (_lightingMode == 0)
g_driver->disableLights();
@ -571,6 +560,17 @@ void Mesh::draw(int *x1, int *y1, int *x2, int *y2) const {
g_driver->enableLights();
}
void Mesh::getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
int winX1, winY1, winX2, winY2;
g_driver->getBoundingBoxPos(this, &winX1, &winY1, &winX2, &winY2);
if (winX1 != -1 && winY1 != -1 && winX2 != -1 && winY2 != -1) {
*x1 = MIN(*x1, winX1);
*y1 = MIN(*y1, winY1);
*x2 = MAX(*x2, winX2);
*y2 = MAX(*y2, winY2);
}
}
/**
* @class ModelNode
*/
@ -630,8 +630,58 @@ void ModelNode::loadBinary(const char *&data, ModelNode *hierNodes, const Model:
_initialized = true;
}
void ModelNode::draw(int *x1, int *y1, int *x2, int *y2) const {
g_driver->drawHierachyNode(this, x1, y1, x2, y2);
void ModelNode::draw() const {
translateViewpoint();
if (_hierVisible) {
g_driver->translateViewpointStart();
g_driver->translateViewpoint(_pivot);
if (!g_driver->isShadowModeActive()) {
Sprite *sprite = _sprite;
while (sprite) {
sprite->draw();
sprite = sprite->_next;
}
}
if (_mesh && _meshVisible) {
_mesh->draw();
}
g_driver->translateViewpointFinish();
if (_child) {
_child->draw();
}
}
translateViewpointBack();
if (_sibling) {
_sibling->draw();
}
}
void ModelNode::getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
translateViewpoint();
if (_hierVisible) {
g_driver->translateViewpointStart();
g_driver->translateViewpoint(_pivot);
if (_mesh && _meshVisible) {
_mesh->getBoundingBox(x1, y1, x2, y2);
}
g_driver->translateViewpointFinish();
if (_child) {
_child->getBoundingBox(x1, y1, x2, y2);
}
}
translateViewpointBack();
if (_sibling) {
_sibling->getBoundingBox(x1, y1, x2, y2);
}
}
void ModelNode::addChild(ModelNode *child) {
@ -711,4 +761,21 @@ void ModelNode::removeSprite(Sprite *sprite) {
}
}
void ModelNode::translateViewpoint() const {
Math::Vector3d animPos = _pos + _animPos;
Math::Angle animPitch = _pitch + _animPitch;
Math::Angle animYaw = _yaw + _animYaw;
Math::Angle animRoll = _roll + _animRoll;
g_driver->translateViewpointStart();
g_driver->translateViewpoint(animPos);
g_driver->rotateViewpoint(animYaw, Math::Vector3d(0, 0, 1));
g_driver->rotateViewpoint(animPitch, Math::Vector3d(1, 0, 0));
g_driver->rotateViewpoint(animRoll, Math::Vector3d(0, 1, 0));
}
void ModelNode::translateViewpointBack() const {
g_driver->translateViewpointFinish();
}
} // end of namespace Grim

View file

@ -114,7 +114,8 @@ public:
void loadBinary(const char *&data, Material *materials[]);
void loadText(TextSplitter *ts, Material *materials[]);
void changeMaterials(Material *materials[]);
void draw(int *x1, int *y1, int *x2, int *y2) const;
void draw() const;
void getBoundingBox(int *x1, int *y1, int *x2, int *y2) const;
void update();
Mesh() : _numFaces(0) { }
~Mesh();
@ -142,13 +143,16 @@ public:
ModelNode() : _initialized(false) { }
~ModelNode();
void loadBinary(const char *&data, ModelNode *hierNodes, const Model::Geoset *g);
void draw(int *x1, int *y1, int *x2, int *y2) const;
void draw() const;
void getBoundingBox(int *x1, int *y1, int *x2, int *y2) const;
void addChild(ModelNode *child);
void removeChild(ModelNode *child);
void setMatrix(Math::Matrix4 matrix);
void update();
void addSprite(Sprite *sprite);
void removeSprite(Sprite *sprite);
void translateViewpoint() const;
void translateViewpointBack() const;
char _name[64];
Mesh *_mesh;