Files
scummvm-cursorfix/engines/wintermute/ad/ad_attach_3dx.cpp
2026-02-02 04:50:13 +01:00

266 lines
7.9 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* This file is based on WME.
* http://dead-code.org/redir.php?target=wme
* Copyright (c) 2003-2013 Jan Nedoma and contributors
*/
#include "engines/wintermute/ad/ad_attach_3dx.h"
#include "engines/wintermute/base/base_active_rect.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/3dshadow_volume.h"
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
#include "engines/wintermute/base/gfx/xmodel.h"
#include "engines/wintermute/base/scriptables/script.h"
#include "engines/wintermute/base/scriptables/script_stack.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
IMPLEMENT_PERSISTENT(AdAttach3DX, false)
//////////////////////////////////////////////////////////////////////////
AdAttach3DX::AdAttach3DX(BaseGame *inGame, BaseObject *owner) : AdObject3D(inGame) {
_owner = owner;
_parentBone = nullptr;
_dropToFloor = false;
}
//////////////////////////////////////////////////////////////////////////
AdAttach3DX::~AdAttach3DX() {
SAFE_DELETE_ARRAY(_parentBone);
_owner = nullptr; // ref only
}
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::init(const char *modelFile, const char *name, const char *parentBone) {
SAFE_DELETE(_xmodel);
BaseUtils::setString(&_parentBone, parentBone);
setName(name);
_xmodel = new XModel(_game, _owner);
if (!_xmodel) {
return false;
}
bool res = _xmodel->loadFromFile(modelFile);
if (!res) {
SAFE_DELETE(_xmodel);
}
return res;
}
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::update() {
AdObject3D::update();
if (_xmodel) {
return _xmodel->update();
} else {
return true;
}
}
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::displayAttachable(DXMatrix *viewMat, bool registerObjects) {
BaseRenderer3D *renderer = _game->_renderer3D;
DXMatrix finalMat;
DXMatrixMultiply(&finalMat, &_worldMatrix, viewMat);
renderer->setWorldTransform(finalMat);
if (_xmodel) {
_xmodel->render();
if (registerObjects && _owner && _owner->_registrable) {
renderer->_rectList.add(new BaseActiveRect(_game, _owner, _xmodel, _xmodel->_boundingRect.left, _xmodel->_boundingRect.top, _xmodel->_boundingRect.right - _xmodel->_boundingRect.left, _xmodel->_boundingRect.bottom - _xmodel->_boundingRect.top, true));
}
}
_game->_renderer3D->invalidateLastTexture();
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::displayShadowVol(DXMatrix *modelMat, DXVector3 *light, float extrusionDepth, bool update) {
BaseRenderer3D *renderer = _game->_renderer3D;
DXMatrix finalMat;
DXMatrixMultiply(&finalMat, &_worldMatrix, modelMat);
if (_xmodel) {
if (update) {
getShadowVolume()->reset();
_xmodel->updateShadowVol(getShadowVolume(), &finalMat, light, extrusionDepth);
}
renderer->setWorldTransform(finalMat);
getShadowVolume()->renderToStencilBuffer();
}
return true;
}
//////////////////////////////////////////////////////////////////////////
char *AdAttach3DX::getParentBone() {
return _parentBone;
}
//////////////////////////////////////////////////////////////////////////
// high level scripting interface
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) {
//////////////////////////////////////////////////////////////////////////
// PlayAnim / PlayAnimAsync
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "PlayAnim") == 0 || strcmp(name, "PlayAnimAsync") == 0) {
stack->correctParams(1);
const char *animName = stack->pop()->getString();
if (!_xmodel || !_xmodel->playAnim(0, animName, 0, true)) {
stack->pushBool(false);
} else {
if (strcmp(name, "PlayAnimAsync") != 0)
script->waitFor(this);
stack->pushBool(true);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
// StopAnim
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "StopAnim") == 0) {
stack->correctParams(0);
bool ret = false;
if (_xmodel) {
ret = _xmodel->stopAnim(0);
}
stack->pushBool(ret);
return true;
}
//////////////////////////////////////////////////////////////////////////
// StopAnimChannel
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "StopAnimChannel") == 0) {
stack->correctParams(1);
int channel = stack->pop()->getInt();
bool ret = false;
if (_xmodel) {
ret = _xmodel->stopAnim(channel, 0);
}
stack->pushBool(ret);
return true;
}
//////////////////////////////////////////////////////////////////////////
// PlayAnimChannel / PlayAnimChannelAsync
//////////////////////////////////////////////////////////////////////////
else if (strcmp(name, "PlayAnimChannel") == 0 || strcmp(name, "PlayAnimChannelAsync") == 0) {
stack->correctParams(2);
int channel = stack->pop()->getInt();
const char *animName = stack->pop()->getString();
if (!_xmodel || !_xmodel->playAnim(channel, animName, 0, true)) {
stack->pushBool(false);
} else {
if (strcmp(name, "PlayAnimChannelAsync") != 0) {
script->waitFor(this);
}
stack->pushBool(true);
}
return true;
}
else {
return AdObject3D::scCallMethod(script, stack, thisStack, name);
}
}
//////////////////////////////////////////////////////////////////////////
ScValue *AdAttach3DX::scGetProperty(const char *name) {
_scValue->setNULL();
//////////////////////////////////////////////////////////////////////////
// Type
//////////////////////////////////////////////////////////////////////////
if (strcmp(name, "Type") == 0) {
_scValue->setString("attachment");
return _scValue;
} else {
return AdObject3D::scGetProperty(name);
}
}
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::scSetProperty(const char *name, ScValue *value) {
return AdObject3D::scSetProperty(name, value);
}
//////////////////////////////////////////////////////////////////////////
const char *AdAttach3DX::scToString() {
return "[attachment object]";
}
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::persist(BasePersistenceManager *persistMgr) {
AdObject3D::persist(persistMgr);
persistMgr->transferPtr(TMEMBER(_owner));
persistMgr->transferCharPtr(TMEMBER(_parentBone));
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::invalidateDeviceObjects() {
if (_xmodel) {
_xmodel->invalidateDeviceObjects();
}
if (_shadowModel) {
_shadowModel->invalidateDeviceObjects();
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AdAttach3DX::restoreDeviceObjects() {
if (_xmodel) {
_xmodel->restoreDeviceObjects();
}
if (_shadowModel) {
_shadowModel->restoreDeviceObjects();
}
return true;
}
} // namespace Wintermute