1395 lines
36 KiB
C++
1395 lines
36 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 "common/util.h"
|
|
#include "math/utils.h"
|
|
|
|
#include "engines/wintermute/ad/ad_block.h"
|
|
#include "engines/wintermute/ad/ad_game.h"
|
|
#include "engines/wintermute/ad/ad_generic.h"
|
|
#include "engines/wintermute/ad/ad_geom_ext.h"
|
|
#include "engines/wintermute/ad/ad_geom_ext_node.h"
|
|
#include "engines/wintermute/ad/ad_path3d.h"
|
|
#include "engines/wintermute/ad/ad_path_point3d.h"
|
|
#include "engines/wintermute/ad/ad_scene.h"
|
|
#include "engines/wintermute/ad/ad_scene_geometry.h"
|
|
#include "engines/wintermute/ad/ad_walkplane.h"
|
|
#include "engines/wintermute/ad/ad_waypoint_group3d.h"
|
|
#include "engines/wintermute/base/base_file_manager.h"
|
|
#include "engines/wintermute/base/base_game.h"
|
|
#include "engines/wintermute/base/base_sprite.h"
|
|
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
|
|
#include "engines/wintermute/base/gfx/3dcamera.h"
|
|
#include "engines/wintermute/base/gfx/3dlight.h"
|
|
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
|
|
#include "engines/wintermute/base/gfx/3dmesh.h"
|
|
#include "engines/wintermute/base/gfx/xmath.h"
|
|
#include "engines/wintermute/base/gfx/3dutils.h"
|
|
#include "engines/wintermute/utils/path_util.h"
|
|
#include "engines/wintermute/utils/utils.h"
|
|
#include "engines/wintermute/system/sys_class_registry.h"
|
|
#include "engines/wintermute/wintermute.h"
|
|
#include "engines/wintermute/dcgf.h"
|
|
|
|
namespace Wintermute {
|
|
|
|
IMPLEMENT_PERSISTENT(AdSceneGeometry, false)
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
AdSceneGeometry::AdSceneGeometry(BaseGame *gameRef) : BaseObject(gameRef) {
|
|
_activeCamera = _activeLight = -1;
|
|
DXMatrixIdentity(&_viewMatrix);
|
|
_waypointHeight = 10.0f;
|
|
_wptMarker = nullptr;
|
|
|
|
_PFReady = true;
|
|
_PFTargetPath = nullptr;
|
|
_PFMaxTime = 15;
|
|
_PFRerun = false;
|
|
|
|
_PFSource = _PFTarget = _PFAlternateTarget = DXVector3(0, 0, 0);
|
|
_PFAlternateDist = FLT_MAX;
|
|
|
|
memset(&_drawingViewport, 0, sizeof(DXViewport));
|
|
|
|
DXMatrixIdentity(&_lastWorldMat);
|
|
DXMatrixIdentity(&_lastViewMat);
|
|
DXMatrixIdentity(&_lastProjMat);
|
|
|
|
_lastOffsetX = _lastOffsetY = 0;
|
|
_lastScrollX = _lastScrollY = 0;
|
|
|
|
_lastValuesInitialized = false;
|
|
_maxLightsWarning = false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
AdSceneGeometry::~AdSceneGeometry() {
|
|
cleanup();
|
|
SAFE_DELETE(_wptMarker);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void AdSceneGeometry::cleanup() {
|
|
int32 i;
|
|
|
|
for (i = 0; i < _planes.getSize(); i++) {
|
|
delete _planes[i];
|
|
}
|
|
_planes.removeAll();
|
|
|
|
for (i = 0; i < _blocks.getSize(); i++) {
|
|
delete _blocks[i];
|
|
}
|
|
_blocks.removeAll();
|
|
|
|
for (i = 0; i < _generics.getSize(); i++) {
|
|
delete _generics[i];
|
|
}
|
|
_generics.removeAll();
|
|
|
|
for (i = 0; i < _waypointGroups.getSize(); i++) {
|
|
delete _waypointGroups[i];
|
|
}
|
|
_waypointGroups.removeAll();
|
|
|
|
for (i = 0; i < _cameras.getSize(); i++) {
|
|
BaseRenderer3D *renderer = _game->_renderer3D;
|
|
if (renderer->_camera == _cameras[i])
|
|
renderer->_camera = nullptr;
|
|
delete _cameras[i];
|
|
}
|
|
_cameras.removeAll();
|
|
|
|
for (i = 0; i < _lights.getSize(); i++) {
|
|
delete _lights[i];
|
|
}
|
|
_lights.removeAll();
|
|
|
|
_activeCamera = _activeLight = -1;
|
|
DXMatrixIdentity(&_viewMatrix);
|
|
|
|
for (i = 0; i < _PFPath.getSize(); i++) {
|
|
delete _PFPath[i];
|
|
}
|
|
_PFPath.removeAll();
|
|
|
|
_PFTargetPath = nullptr;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
AdGeomExt *AdSceneGeometry::getGeometryExtension(char *filename) {
|
|
AdGeomExt *ret = new AdGeomExt(_game);
|
|
|
|
AnsiString path = PathUtil::getDirectoryName(filename);
|
|
AnsiString name = PathUtil::getFileNameWithoutExtension(filename);
|
|
AnsiString geomExtFile = PathUtil::combine(path, name + ".geometry");
|
|
|
|
bool loadOK = false;
|
|
if (BaseFileManager::getEngineInstance()->hasFile(geomExtFile)) {
|
|
loadOK = ret->loadFile(geomExtFile.begin());
|
|
}
|
|
|
|
// no ext file found, just use the defaults
|
|
if (!loadOK) {
|
|
ret->addStandardNodes();
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::loadFile(const char *filename) {
|
|
cleanup();
|
|
|
|
// load waypoint graphics from resources
|
|
if (!_wptMarker) {
|
|
_wptMarker = new BaseSprite(_game);
|
|
if (_wptMarker) {
|
|
if (!_wptMarker->loadFile("wpt.sprite")) {
|
|
delete _wptMarker;
|
|
_wptMarker = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
Common::String extenstionCheck(filename);
|
|
extenstionCheck.toLowercase();
|
|
if (!extenstionCheck.hasSuffix(".3ds")) {
|
|
_game->LOG(0, "Error: no suitable loader found for file '%s'", filename);
|
|
return false;
|
|
}
|
|
|
|
AdGeomExt *geomExt = getGeometryExtension(const_cast<char *>(filename));
|
|
|
|
Loader3DS *loader = new Loader3DS(_game);
|
|
if (!loader->parseFile(filename)) {
|
|
delete loader;
|
|
delete geomExt;
|
|
return false;
|
|
}
|
|
|
|
int32 i;
|
|
|
|
SystemClassRegistry::getInstance()->_disabled = true;
|
|
|
|
// load meshes
|
|
for (i = 0; i < loader->getNumMeshes(); i++) {
|
|
AdGeomExtNode *extNode = geomExt->matchName(loader->getMeshName(i));
|
|
if (!extNode) {
|
|
continue;
|
|
}
|
|
|
|
switch (extNode->_type) {
|
|
case GEOM_WALKPLANE: {
|
|
AdWalkplane *plane = new AdWalkplane(_game);
|
|
plane->setName(loader->getMeshName(i));
|
|
plane->_mesh = _game->_renderer3D->createMesh3DS();
|
|
if (!loader->loadMesh(i, plane->_mesh)) {
|
|
delete plane->_mesh;
|
|
delete plane;
|
|
delete loader;
|
|
delete geomExt;
|
|
return false;
|
|
} else {
|
|
plane->_mesh->computeNormals();
|
|
plane->_mesh->fillVertexBuffer(0x700000FF);
|
|
plane->_receiveShadows = extNode->_receiveShadows;
|
|
_planes.add(plane);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case GEOM_BLOCKED: {
|
|
AdBlock *block = new AdBlock(_game);
|
|
block->setName(loader->getMeshName(i));
|
|
block->_mesh = _game->_renderer3D->createMesh3DS();
|
|
if (!loader->loadMesh(i, block->_mesh)) {
|
|
delete block->_mesh;
|
|
delete block;
|
|
delete loader;
|
|
delete geomExt;
|
|
return false;
|
|
} else {
|
|
block->_mesh->computeNormals();
|
|
block->_mesh->fillVertexBuffer(0x70FF0000);
|
|
block->_receiveShadows = extNode->_receiveShadows;
|
|
_blocks.add(block);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case GEOM_WAYPOINT: {
|
|
Mesh3DS *mesh = _game->_renderer3D->createMesh3DS();
|
|
if (!loader->loadMesh(i, mesh)) {
|
|
delete mesh;
|
|
delete loader;
|
|
delete geomExt;
|
|
return false;
|
|
} else {
|
|
if (_waypointGroups.getSize() == 0) {
|
|
_waypointGroups.add(new AdWaypointGroup3D(_game));
|
|
}
|
|
_waypointGroups[0]->addFromMesh(mesh);
|
|
delete mesh;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case GEOM_GENERIC: {
|
|
AdGeneric *generic = new AdGeneric(_game);
|
|
generic->setName(loader->getMeshName(i));
|
|
generic->_mesh = _game->_renderer3D->createMesh3DS();
|
|
if (!loader->loadMesh(i, generic->_mesh)) {
|
|
delete generic->_mesh;
|
|
delete generic;
|
|
delete loader;
|
|
delete geomExt;
|
|
return false;
|
|
} else {
|
|
generic->_mesh->computeNormals();
|
|
generic->_mesh->fillVertexBuffer(0x7000FF00);
|
|
generic->_receiveShadows = extNode->_receiveShadows;
|
|
_generics.add(generic);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// load cameras
|
|
for (i = 0; i < loader->getNumCameras(); i++) {
|
|
Camera3D *camera = new Camera3D(_game);
|
|
if (!loader->loadCamera(i, camera)) {
|
|
delete camera;
|
|
delete loader;
|
|
delete geomExt;
|
|
return false;
|
|
} else
|
|
_cameras.add(camera);
|
|
}
|
|
|
|
// load lights
|
|
for (i = 0; i < loader->getNumLights(); i++) {
|
|
Light3D *light = new Light3D(_game);
|
|
if (!loader->loadLight(i, light)) {
|
|
delete light;
|
|
delete loader;
|
|
delete geomExt;
|
|
return false;
|
|
} else
|
|
_lights.add(light);
|
|
}
|
|
|
|
SystemClassRegistry::getInstance()->_disabled = false;
|
|
|
|
if (_cameras.getSize() > 0) {
|
|
setActiveCamera(0, -1.0f, -1.0f, -1.0f);
|
|
}
|
|
createLights();
|
|
|
|
if (_lights.getSize() > 0) {
|
|
setActiveLight((int32)0);
|
|
}
|
|
|
|
delete loader;
|
|
delete geomExt;
|
|
|
|
// drop waypoints to the ground
|
|
dropWaypoints();
|
|
|
|
if (_filename != filename) {
|
|
setFilename(filename);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::dropWaypoints() {
|
|
for (int32 i = 0; i < _waypointGroups.getSize(); i++) {
|
|
for (int32 j = 0; j < _waypointGroups[i]->_points.getSize(); j++) {
|
|
DXVector3 *point = _waypointGroups[i]->_points[j];
|
|
point->_y = getHeightAt(*point) + _waypointHeight;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::setActiveCamera(int camera, float fov, float nearClipPlane, float farClipPlane) {
|
|
if (camera < 0 || camera >= _cameras.getSize()) {
|
|
_game->LOG(0, "Warning: Camera %d is out of bounds.", camera);
|
|
return false;
|
|
} else {
|
|
_activeCamera = camera;
|
|
|
|
if (fov >= 0.0f) {
|
|
_cameras[camera]->_fov = fov;
|
|
} else {
|
|
_cameras[camera]->_fov = _cameras[camera]->_origFov;
|
|
}
|
|
|
|
_cameras[camera]->_nearClipPlane = nearClipPlane;
|
|
_cameras[camera]->_farClipPlane = farClipPlane;
|
|
|
|
_cameras[camera]->getViewMatrix(&_viewMatrix);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::setActiveCamera(const char *camera, float fov, float nearClipPlane, float farClipPlane) {
|
|
for (int32 i = 0; i < _cameras.getSize(); i++) {
|
|
if (scumm_stricmp(_cameras[i]->_name, camera) == 0)
|
|
return setActiveCamera(i, fov, nearClipPlane, farClipPlane);
|
|
}
|
|
|
|
_game->LOG(0, "Warning: Camera '%s' not found.", camera);
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
Camera3D *AdSceneGeometry::getActiveCamera() {
|
|
if (_activeCamera >= 0 && _activeCamera < _cameras.getSize()) {
|
|
return _cameras[_activeCamera];
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::setActiveLight(int32 light) {
|
|
if (light < 0 || light >= _lights.getSize()) {
|
|
_game->LOG(0, "Warning: Light %d is out of bounds.", light);
|
|
return false;
|
|
} else {
|
|
_activeLight = light;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::setActiveLight(char *light) {
|
|
for (int32 i = 0; i < _lights.getSize(); i++) {
|
|
if (scumm_stricmp(_lights[i]->_name, light) == 0) {
|
|
return setActiveLight(i);
|
|
}
|
|
}
|
|
|
|
_game->LOG(0, "Warning: Light '%s' not found.", light);
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
DXMatrix *AdSceneGeometry::getViewMatrix() {
|
|
return &_viewMatrix;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::storeDrawingParams() {
|
|
BaseRenderer3D *renderer = _game->_renderer3D;
|
|
|
|
// store values
|
|
_drawingViewport = renderer->getViewPort();
|
|
|
|
renderer->getWorldTransform(&_lastWorldMat);
|
|
renderer->getViewTransform(&_lastViewMat);
|
|
renderer->getProjectionTransform(&_lastProjMat);
|
|
|
|
AdScene *scene = ((AdGame *)_game)->_scene;
|
|
if (scene) {
|
|
_lastScrollX = scene->getOffsetLeft();
|
|
_lastScrollY = scene->getOffsetTop();
|
|
} else {
|
|
_lastScrollX = 0;
|
|
_lastScrollY = 0;
|
|
}
|
|
|
|
Common::Rect32 rc;
|
|
_game->getCurrentViewportRect(&rc);
|
|
float width = (float)rc.right - (float)rc.left;
|
|
float height = (float)rc.bottom - (float)rc.top;
|
|
|
|
// margins
|
|
int mleft = rc.left;
|
|
int mright = _game->_renderer3D->getWidth() - width - rc.left;
|
|
int mtop = rc.top;
|
|
int mbottom = _game->_renderer3D->getHeight() - height - rc.top;
|
|
|
|
_lastOffsetX = _game->_offsetX + (mleft - mright) / 2;
|
|
_lastOffsetY = _game->_offsetY + (mtop - mbottom) / 2;
|
|
|
|
_lastValuesInitialized = true;
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::render(bool render) {
|
|
// store values
|
|
storeDrawingParams();
|
|
if (render) {
|
|
_game->_renderer3D->renderSceneGeometry(_planes, _blocks, _generics, _lights, getActiveCamera());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::renderShadowGeometry() {
|
|
storeDrawingParams();
|
|
|
|
_game->_renderer3D->renderShadowGeometry(_planes, _blocks, _generics, getActiveCamera());
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
float AdSceneGeometry::getHeightAt(DXVector3 pos, float tolerance, bool *intFound) {
|
|
float ret = pos._y;
|
|
DXVector3 intersection;
|
|
DXVector3 dir = DXVector3(0, -1, 0);
|
|
|
|
pos._y += tolerance;
|
|
|
|
bool intFoundTmp = false;
|
|
|
|
for (int32 i = 0; i < _planes.getSize(); i++) {
|
|
for (uint32 j = 0; j < _planes[i]->_mesh->_numFaces; j++) {
|
|
if (C3DUtils::intersectTriangle(
|
|
pos, dir,
|
|
_planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[0]]._pos,
|
|
_planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[1]]._pos,
|
|
_planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[2]]._pos,
|
|
&intersection._x, &intersection._y, &intersection._z)) {
|
|
if (intersection._y > pos._y + tolerance) {
|
|
continue; // only fall down
|
|
}
|
|
|
|
if (!intFoundTmp || fabs(ret - pos._y) > fabs(intersection._y - pos._y)) {
|
|
ret = intersection._y;
|
|
}
|
|
|
|
intFoundTmp = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (intFound) {
|
|
*intFound = intFoundTmp;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::directPathExists(DXVector3 *p1, DXVector3 *p2) {
|
|
DXVector3 v0, v1, v2;
|
|
|
|
// test walkplanes
|
|
for (int32 i = 0; i < _planes.getSize(); i++) {
|
|
for (int32 j = 0; j < _planes[i]->_mesh->_numFaces; j++) {
|
|
v0 = _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[0]]._pos;
|
|
v1 = _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[1]]._pos;
|
|
v2 = _planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[2]]._pos;
|
|
|
|
DXVector3 intersection;
|
|
float dist;
|
|
|
|
if (C3DUtils::pickGetIntersect(*p1, *p2, v0, v1, v2, &intersection, &dist)) {
|
|
if (C3DUtils::intersectTriangle(*p1, *p1 - *p2, v0, v1, v2, &intersection._x, &intersection._y, &intersection._z)) {
|
|
return false;
|
|
}
|
|
|
|
if (C3DUtils::intersectTriangle(*p2, *p2 - *p1, v0, v1, v2, &intersection._x, &intersection._y, &intersection._z)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// test blocks
|
|
for (int32 i = 0; i < _blocks.getSize(); i++) {
|
|
if (!_blocks[i]->_active) {
|
|
continue;
|
|
}
|
|
|
|
for (uint32 j = 0; j < _blocks[i]->_mesh->_numFaces; j++) {
|
|
v0 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[0]]._pos;
|
|
v1 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[1]]._pos;
|
|
v2 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[2]]._pos;
|
|
|
|
DXVector3 intersection;
|
|
float dist;
|
|
|
|
if (C3DUtils::pickGetIntersect(*p1, *p2, v0, v1, v2, &intersection, &dist)) {
|
|
if (C3DUtils::intersectTriangle(*p1, *p1 - *p2, v0, v1, v2, &intersection._x, &intersection._y, &intersection._z)) {
|
|
return false;
|
|
}
|
|
|
|
if (C3DUtils::intersectTriangle(*p2, *p2 - *p1, v0, v1, v2, &intersection._x, &intersection._y, &intersection._z)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
DXVector3 AdSceneGeometry::getBlockIntersection(DXVector3 *p1, DXVector3 *p2) {
|
|
DXVector3 v0, v1, v2;
|
|
|
|
// test blocks
|
|
for (int32 i = 0; i < _blocks.getSize(); i++) {
|
|
if (!_blocks[i]->_active) {
|
|
continue;
|
|
}
|
|
|
|
for (uint32 j = 0; j < _blocks[i]->_mesh->_numFaces; j++) {
|
|
v0 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[0]]._pos;
|
|
v1 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[1]]._pos;
|
|
v2 = _blocks[i]->_mesh->_vertices[_blocks[i]->_mesh->_faces[j]._vertices[2]]._pos;
|
|
|
|
DXVector3 intersection;
|
|
float dist;
|
|
|
|
if (C3DUtils::pickGetIntersect(*p1, *p2, v0, v1, v2, &intersection, &dist)) {
|
|
if (C3DUtils::intersectTriangle(*p1, *p1 - *p2, v0, v1, v2, &intersection._x, &intersection._y, &intersection._z)) {
|
|
return intersection;
|
|
}
|
|
|
|
if (C3DUtils::intersectTriangle(*p2, *p2 - *p1, v0, v1, v2, &intersection._x, &intersection._y, &intersection._z)) {
|
|
return intersection;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return DXVector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::convert2Dto3DTolerant(int x, int y, DXVector3 *pos) {
|
|
bool ret = convert2Dto3D(x, y, pos);
|
|
if (ret) {
|
|
return ret;
|
|
}
|
|
|
|
int32 lenLeft = 0;
|
|
int32 lenRight = 0;
|
|
int32 lenDown = 0;
|
|
int32 lenUp = 0;
|
|
|
|
int32 i;
|
|
|
|
// left
|
|
for (i = 0; i < 1000; i += 10) {
|
|
if (convert2Dto3D(x - i, y, pos)) {
|
|
lenLeft = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// right
|
|
for (i = 0; i < 1000; i += 10) {
|
|
if (convert2Dto3D(x + i, y, pos)) {
|
|
lenRight = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// up
|
|
for (i = 0; i < 1000; i += 10) {
|
|
if (convert2Dto3D(x, y - i, pos)) {
|
|
lenUp = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// down
|
|
for (i = 0; i < 1000; i += 10) {
|
|
if (convert2Dto3D(x, y + i, pos)) {
|
|
lenDown = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!lenLeft && !lenRight && !lenUp && !lenDown) {
|
|
return false;
|
|
}
|
|
|
|
int32 offsetX = INT_MAX_VALUE;
|
|
int32 offsetY = INT_MAX_VALUE;
|
|
|
|
if (lenLeft || lenRight) {
|
|
if (lenRight) {
|
|
if (lenLeft && lenLeft < lenRight) {
|
|
offsetX = -lenLeft;
|
|
} else {
|
|
offsetX = lenRight;
|
|
}
|
|
} else {
|
|
offsetX = -lenLeft;
|
|
}
|
|
}
|
|
|
|
if (lenUp || lenDown) {
|
|
if (lenDown) {
|
|
if (lenUp && lenUp < lenDown)
|
|
offsetY = -lenUp;
|
|
else
|
|
offsetY = lenDown;
|
|
} else
|
|
offsetY = -lenUp;
|
|
}
|
|
|
|
if (abs(offsetX) < abs(offsetY)) {
|
|
x += offsetX;
|
|
} else {
|
|
y += offsetY;
|
|
}
|
|
|
|
return convert2Dto3D(x, y, pos);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::convert2Dto3D(int x, int y, DXVector3 *pos) {
|
|
BaseRenderer3D *renderer = _game->_renderer3D;
|
|
|
|
if (!_lastValuesInitialized) {
|
|
_drawingViewport = renderer->getViewPort();
|
|
renderer->getProjectionTransform(&_lastProjMat);
|
|
}
|
|
|
|
float resWidth, resHeight;
|
|
float layerWidth, layerHeight;
|
|
float modWidth, modHeight;
|
|
bool customViewport;
|
|
_game->_renderer3D->getProjectionParams(&resWidth, &resHeight, &layerWidth, &layerHeight, &modWidth, &modHeight, &customViewport);
|
|
|
|
// modify coordinates according to viewport settings
|
|
int mleft = _drawingViewport._x;
|
|
int mright = resWidth - _drawingViewport._width - _drawingViewport._x;
|
|
int mtop = _drawingViewport._y;
|
|
int mbottom = resHeight - _drawingViewport._height - _drawingViewport._y;
|
|
|
|
x -= (mleft + mright) / 2 + modWidth;
|
|
y -= (mtop + mbottom) / 2 + modHeight;
|
|
|
|
DXVector3 vPickRayDir;
|
|
DXVector3 vPickRayOrig;
|
|
|
|
// Compute the vector of the pick ray in screen space
|
|
DXVector3 vec;
|
|
vec._x = (((2.0f * x) / _drawingViewport._width) - 1) / _lastProjMat.matrix._11;
|
|
vec._y = -(((2.0f * y) / _drawingViewport._height) - 1) / _lastProjMat.matrix._22;
|
|
vec._z = 1.0f;
|
|
|
|
// Get the inverse view matrix
|
|
DXMatrix m;
|
|
DXMatrixInverse(&m, nullptr, &_viewMatrix);
|
|
|
|
// Transform the screen space pick ray into 3D space
|
|
vPickRayDir._x = vec._x * m.matrix._11 + vec._y * m.matrix._21 + vec._z * m.matrix._31;
|
|
vPickRayDir._y = vec._x * m.matrix._12 + vec._y * m.matrix._22 + vec._z * m.matrix._32;
|
|
vPickRayDir._z = vec._x * m.matrix._13 + vec._y * m.matrix._23 + vec._z * m.matrix._33;
|
|
vPickRayOrig._x = m.matrix._41;
|
|
vPickRayOrig._y = m.matrix._42;
|
|
vPickRayOrig._z = m.matrix._43;
|
|
|
|
|
|
bool intFound = false;
|
|
float minDist = FLT_MAX;
|
|
DXVector3 intersection, ray;
|
|
for (int32 i = 0; i < _planes.getSize(); i++) {
|
|
for (int32 j = 0; j < _planes[i]->_mesh->_numFaces; j++) {
|
|
if (C3DUtils::intersectTriangle(
|
|
vPickRayOrig, vPickRayDir,
|
|
_planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[0]]._pos,
|
|
_planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[1]]._pos,
|
|
_planes[i]->_mesh->_vertices[_planes[i]->_mesh->_faces[j]._vertices[2]]._pos,
|
|
&intersection._x, &intersection._y, &intersection._z)) {
|
|
ray = intersection - vPickRayOrig;
|
|
float dist = DXVec3Length(&ray);
|
|
if (dist < minDist) {
|
|
*pos = intersection;
|
|
minDist = dist;
|
|
}
|
|
intFound = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return intFound;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::getPath(DXVector3 source, DXVector3 target, AdPath3D *path, bool rerun) {
|
|
if (!_PFReady) {
|
|
return false;
|
|
} else {
|
|
source._y = getHeightAt(source, _waypointHeight) + _waypointHeight;
|
|
target._y = getHeightAt(target, _waypointHeight) + _waypointHeight;
|
|
|
|
_PFReady = false;
|
|
_PFSource = source;
|
|
_PFTarget = target;
|
|
_PFTargetPath = path;
|
|
_PFAlternateTarget = DXVector3(0, 0, 0);
|
|
_PFAlternateDist = FLT_MAX;
|
|
|
|
_PFTargetPath->reset();
|
|
_PFTargetPath->setReady(false);
|
|
_PFRerun = rerun;
|
|
|
|
// prepare working path
|
|
int32 i, j;
|
|
for (i = 0; i < _PFPath.getSize(); i++) {
|
|
delete _PFPath[i];
|
|
}
|
|
_PFPath.removeAll();
|
|
|
|
// first point
|
|
_PFPath.add(new AdPathPoint3D(source, 0));
|
|
|
|
// last point
|
|
_PFPath.add(new AdPathPoint3D(target, FLT_MAX));
|
|
|
|
// add all active waypoints
|
|
for (i = 0; i < _waypointGroups.getSize(); i++) {
|
|
if (_waypointGroups[i]->_active) {
|
|
for (j = 0; j < _waypointGroups[i]->_points.getSize(); j++) {
|
|
_PFPath.add(new AdPathPoint3D(*_waypointGroups[i]->_points[j], FLT_MAX));
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void AdSceneGeometry::pathFinderStep() {
|
|
int32 i;
|
|
|
|
// get lowest unmarked
|
|
float lowestDist = FLT_MAX;
|
|
AdPathPoint3D *lowestPt = NULL;
|
|
|
|
for (i = 0; i < _PFPath.getSize(); i++) {
|
|
if (!_PFPath[i]->_marked && _PFPath[i]->_distance < lowestDist) {
|
|
lowestDist = _PFPath[i]->_distance;
|
|
lowestPt = _PFPath[i];
|
|
}
|
|
}
|
|
|
|
if (lowestPt == nullptr) { // no path -> terminate PathFinder
|
|
_PFReady = true;
|
|
if (!_PFRerun) {
|
|
if (_PFAlternateTarget != DXVector3(0, 0, 0)) {
|
|
getPath(_PFSource, _PFAlternateTarget, _PFTargetPath, true);
|
|
} else {
|
|
_PFTargetPath->setReady(true);
|
|
}
|
|
} else {
|
|
_PFTargetPath->setReady(true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
lowestPt->_marked = true;
|
|
|
|
// target point marked, generate path and terminate
|
|
if (lowestPt->_pos == _PFTarget) {
|
|
while (lowestPt != nullptr) {
|
|
_PFTargetPath->_points.insertAt(0, new DXVector3(lowestPt->_pos));
|
|
lowestPt = lowestPt->_origin;
|
|
}
|
|
// remove current position
|
|
if (_PFTargetPath->_points.getSize() > 0) {
|
|
delete _PFTargetPath->_points[0];
|
|
_PFTargetPath->_points.removeAt(0);
|
|
}
|
|
|
|
_PFReady = true;
|
|
_PFTargetPath->setReady(true);
|
|
return;
|
|
}
|
|
|
|
// otherwise keep on searching
|
|
for (i = 0; i < _PFPath.getSize(); i++) {
|
|
if (!_PFPath[i]->_marked) {
|
|
float dist = getPointsDist(lowestPt->_pos, _PFPath[i]->_pos);
|
|
if (dist >= 0 && lowestPt->_distance + dist < _PFPath[i]->_distance) {
|
|
_PFPath[i]->_distance = lowestPt->_distance + dist;
|
|
_PFPath[i]->_origin = lowestPt;
|
|
} else {
|
|
if (!_PFRerun && _PFPath[i]->_pos == _PFTarget) {
|
|
DXVector3 line = _PFPath[i]->_pos - lowestPt->_pos;
|
|
float len = DXVec3Length(&line);
|
|
|
|
if (len < _PFAlternateDist) {
|
|
_PFAlternateDist = len;
|
|
_PFAlternateTarget = getBlockIntersection(&lowestPt->_pos, &_PFPath[i]->_pos);
|
|
|
|
DXVector3 dir = _PFAlternateTarget - lowestPt->_pos;
|
|
DXVec3Normalize(&dir, &dir);
|
|
_PFAlternateTarget -= dir * 30;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
float AdSceneGeometry::getPointsDist(DXVector3 p1, DXVector3 p2) {
|
|
if (!directPathExists(&p1, &p2)) {
|
|
return -1;
|
|
}
|
|
|
|
DXVector3 vect = p2 - p1;
|
|
return DXVec3Length(&vect);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::initLoop() {
|
|
uint32 start = _game->_currentTime;
|
|
while (!_PFReady && _game->_currentTime - start <= _PFMaxTime) {
|
|
pathFinderStep();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::createLights() {
|
|
// disable all lights
|
|
BaseRenderer3D *renderer = _game->_renderer3D;
|
|
int32 maxLights = renderer->getMaxActiveLights();
|
|
for (int32 i = 0; i < maxLights; i++) {
|
|
renderer->lightEnable(i, false);
|
|
}
|
|
|
|
for (int32 i = 0; i < MIN(_lights.getSize(), maxLights); i++) {
|
|
_lights[i]->setLight(i);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::enableLights(DXVector3 point, BaseArray<char *> &ignoreLights) {
|
|
const int maxLightCount = 100;
|
|
BaseRenderer3D *renderer = _game->_renderer3D;
|
|
int maxLights = renderer->getMaxActiveLights();
|
|
|
|
int32 numActiveLights = 0;
|
|
for (int32 i = 0; i < _lights.getSize(); i++) {
|
|
_lights[i]->_isAvailable = false;
|
|
if (_lights[i]->_active) {
|
|
numActiveLights++;
|
|
}
|
|
}
|
|
|
|
if (numActiveLights <= maxLights) {
|
|
for (int32 i = 0; i < _lights.getSize(); i++) {
|
|
_lights[i]->_isAvailable = true;
|
|
}
|
|
} else {
|
|
if (!_maxLightsWarning) {
|
|
_game->LOG(0, "Warning: Using more lights than the hardware supports (%d)", maxLights);
|
|
_maxLightsWarning = true;
|
|
}
|
|
|
|
BaseArray<Light3D *> activeLights;
|
|
|
|
// compute distance to point
|
|
for (int32 i = 0; i < _lights.getSize(); i++) {
|
|
if (!_lights[i]->_active) {
|
|
continue;
|
|
}
|
|
|
|
DXVector3 dif;
|
|
|
|
if (_lights[i]->_isSpotlight) {
|
|
DXVector3 dir = _lights[i]->_target - _lights[i]->_pos;
|
|
dif = (_lights[i]->_pos + dir * 0.75f) - point;
|
|
} else {
|
|
dif = _lights[i]->_pos - point;
|
|
}
|
|
|
|
_lights[i]->_distance = fabs(DXVec3Length(&dif));
|
|
|
|
activeLights.add(_lights[i]);
|
|
}
|
|
|
|
// sort by distance
|
|
if (activeLights.getSize() > 0) {
|
|
qsort_msvc(activeLights.getData(), activeLights.getSize(), sizeof(Light3D *), AdSceneGeometry::compareLights);
|
|
|
|
for (int32 i = 0; i < activeLights.getSize(); i++) {
|
|
activeLights[i]->_isAvailable = i < maxLights;
|
|
}
|
|
}
|
|
}
|
|
|
|
// light all available lights
|
|
for (int32 i = 0; i < maxLightCount; i++) {
|
|
renderer->lightEnable(i, false);
|
|
}
|
|
|
|
numActiveLights = 0;
|
|
for (int32 i = 0; i < _lights.getSize(); i++) {
|
|
if (numActiveLights >= maxLights) {
|
|
break;
|
|
}
|
|
|
|
if (ignoreLights.getSize()) {
|
|
bool ignore = false;
|
|
for (int32 j = 0; j < ignoreLights.getSize(); j++) {
|
|
if (scumm_stricmp(_lights[i]->_name, ignoreLights[j]) == 0) {
|
|
ignore = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ignore) {
|
|
continue; // skip this light
|
|
}
|
|
}
|
|
|
|
if (_lights[i]->_isAvailable) {
|
|
renderer->lightEnable(i, _lights[i]->_active);
|
|
if (_lights[i]->_active) {
|
|
numActiveLights++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int32 AdSceneGeometry::compareLights(const void *obj1, const void *obj2) {
|
|
void *o1 = const_cast<void *>(obj1);
|
|
void *o2 = const_cast<void *>(obj2);
|
|
Light3D *light1 = *(Light3D **)o1;
|
|
Light3D *light2 = *(Light3D **)o2;
|
|
|
|
if (light1->_distance < light2->_distance)
|
|
return -1;
|
|
else if (light1->_distance > light2->_distance)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::correctTargetPoint(const DXVector3 &source, DXVector3 *target) {
|
|
int32 i;
|
|
int32 MaxLen = 1000;
|
|
int32 Step = 10;
|
|
DXVector3 newTarget;
|
|
|
|
int32 lenLeft = 0;
|
|
int32 lenRight = 0;
|
|
int32 lenUp = 0;
|
|
int32 lenDown = 0;
|
|
|
|
// left
|
|
newTarget = *target;
|
|
for (i = 1; i <= MaxLen; i += Step) {
|
|
newTarget._x -= i;
|
|
if (!directPathExists(target, &newTarget)) {
|
|
lenLeft = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// right
|
|
newTarget = *target;
|
|
for (i = 1; i <= MaxLen; i += Step) {
|
|
newTarget._x += i;
|
|
if (!directPathExists(target, &newTarget)) {
|
|
lenRight = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// up
|
|
newTarget = *target;
|
|
for (i = 1; i <= MaxLen; i += Step) {
|
|
newTarget._z -= i;
|
|
if (!directPathExists(target, &newTarget)) {
|
|
lenUp = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// down
|
|
newTarget = *target;
|
|
for (i = 1; i <= MaxLen; i += Step) {
|
|
newTarget._z += i;
|
|
if (!directPathExists(target, &newTarget)) {
|
|
lenDown = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!lenLeft && !lenRight && !lenUp && !lenDown) {
|
|
return true;
|
|
}
|
|
|
|
int offsetX = INT_MAX_VALUE;
|
|
int offsetZ = INT_MAX_VALUE;
|
|
|
|
if (lenLeft || lenRight) {
|
|
if (lenRight) {
|
|
if (lenLeft && lenLeft < lenRight) {
|
|
offsetX = -lenLeft;
|
|
} else {
|
|
offsetX = lenRight;
|
|
}
|
|
} else {
|
|
offsetX = -lenLeft;
|
|
}
|
|
}
|
|
|
|
if (lenUp || lenDown) {
|
|
if (lenDown) {
|
|
if (lenUp && lenUp < lenDown) {
|
|
offsetZ = -lenUp;
|
|
} else {
|
|
offsetZ = lenDown;
|
|
}
|
|
} else {
|
|
offsetZ = -lenUp;
|
|
}
|
|
}
|
|
|
|
if (abs(offsetX) < abs(offsetZ)) {
|
|
target->_x += offsetX;
|
|
} else {
|
|
target->_z += offsetZ;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::enableNode(const char *nodeName, bool enable) {
|
|
bool ret = false;
|
|
|
|
int32 i;
|
|
for (i = 0; i < _blocks.getSize(); i++) {
|
|
if (scumm_stricmp(nodeName, _blocks[i]->_name) == 0) {
|
|
_blocks[i]->_active = enable;
|
|
ret = true;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < _planes.getSize(); i++) {
|
|
if (scumm_stricmp(nodeName, _planes[i]->_name) == 0) {
|
|
_planes[i]->_active = enable;
|
|
ret = true;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < _generics.getSize(); i++) {
|
|
if (scumm_stricmp(nodeName, _generics[i]->_name) == 0) {
|
|
_generics[i]->_active = enable;
|
|
ret = true;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::isNodeEnabled(const char *nodeName) {
|
|
for (int32 i = 0; i < _blocks.getSize(); i++) {
|
|
if (scumm_stricmp(nodeName, _blocks[i]->_name) == 0) {
|
|
return _blocks[i]->_active;
|
|
}
|
|
}
|
|
for (int32 i = 0; i < _planes.getSize(); i++) {
|
|
if (scumm_stricmp(nodeName, _planes[i]->_name) == 0) {
|
|
return _planes[i]->_active;
|
|
}
|
|
}
|
|
|
|
for (int32 i = 0; i < _generics.getSize(); i++) {
|
|
if (scumm_stricmp(nodeName, _generics[i]->_name) == 0) {
|
|
return _generics[i]->_active;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::enableLight(const char *lightName, bool enable) {
|
|
bool ret = false;
|
|
|
|
int32 i;
|
|
for (i = 0; i < _lights.getSize(); i++) {
|
|
if (scumm_stricmp(lightName, _lights[i]->_name) == 0) {
|
|
_lights[i]->_active = enable;
|
|
ret = true;
|
|
}
|
|
}
|
|
createLights();
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::isLightEnabled(const char *lightName) {
|
|
for (int32 i = 0; i < _lights.getSize(); i++) {
|
|
if (scumm_stricmp(lightName, _lights[i]->_name) == 0) {
|
|
return _lights[i]->_active;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::setLightColor(const char *lightName, uint32 color) {
|
|
bool ret = false;
|
|
|
|
int32 i;
|
|
for (i = 0; i < _lights.getSize(); i++) {
|
|
if (scumm_stricmp(lightName, _lights[i]->_name) == 0) {
|
|
_lights[i]->_diffuseColor = color;
|
|
ret = true;
|
|
}
|
|
}
|
|
createLights();
|
|
|
|
return ret;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint32 AdSceneGeometry::getLightColor(const char *lightName) {
|
|
for (int32 i = 0; i < _lights.getSize(); i++) {
|
|
if (scumm_stricmp(lightName, _lights[i]->_name) == 0) {
|
|
return _lights[i]->_diffuseColor;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
DXVector3 AdSceneGeometry::getLightPos(const char *lightName) {
|
|
for (int32 i = 0; i < _lights.getSize(); i++) {
|
|
if (scumm_stricmp(lightName, _lights[i]->_name) == 0) {
|
|
return _lights[i]->_pos;
|
|
}
|
|
}
|
|
return DXVector3(0, 0, 0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::persist(BasePersistenceManager *persistMgr) {
|
|
BaseObject::persist(persistMgr);
|
|
|
|
persistMgr->transferFloat(TMEMBER(_waypointHeight));
|
|
persistMgr->transferPtr(TMEMBER(_wptMarker));
|
|
|
|
if (!persistMgr->getIsSaving()) {
|
|
//m_WptMarker = NULL;
|
|
loadFile(_filename);
|
|
_lastValuesInitialized = false;
|
|
}
|
|
|
|
persistMgr->transferSint32(TMEMBER(_activeCamera));
|
|
persistMgr->transferSint32(TMEMBER(_activeLight));
|
|
persistMgr->transferMatrix4(TMEMBER(_viewMatrix));
|
|
|
|
_PFPath.persist(persistMgr);
|
|
persistMgr->transferBool(TMEMBER(_PFReady));
|
|
persistMgr->transferVector3d(TMEMBER(_PFSource));
|
|
persistMgr->transferVector3d(TMEMBER(_PFTarget));
|
|
persistMgr->transferVector3d(TMEMBER(_PFAlternateTarget));
|
|
persistMgr->transferPtr(TMEMBER(_PFTargetPath));
|
|
persistMgr->transferUint32(TMEMBER(_PFMaxTime));
|
|
persistMgr->transferBool(TMEMBER(_PFRerun));
|
|
|
|
// now save/load light/blocks/walkplanes/generic node states by name
|
|
int i;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int32 numLights = _lights.getSize();
|
|
persistMgr->transferSint32(TMEMBER(numLights));
|
|
for (i = 0; i < numLights; i++) {
|
|
if (persistMgr->getIsSaving()) {
|
|
persistMgr->transferCharPtr(TMEMBER(_lights[i]->_name));
|
|
_lights[i]->persist(persistMgr);
|
|
} else {
|
|
char *name = nullptr;
|
|
persistMgr->transferCharPtr(TMEMBER(name));
|
|
bool found = false;
|
|
|
|
for (int32 j = 0; j < _lights.getSize(); j++) {
|
|
if (scumm_stricmp(name, _lights[j]->_name) == 0) {
|
|
_lights[j]->persist(persistMgr);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
Light3D *light = new Light3D(_game);
|
|
light->persist(persistMgr);
|
|
delete light;
|
|
}
|
|
SAFE_DELETE_ARRAY(name);
|
|
}
|
|
}
|
|
createLights();
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int32 numBlocks = _blocks.getSize();
|
|
persistMgr->transferSint32(TMEMBER(numBlocks));
|
|
for (i = 0; i < numBlocks; i++) {
|
|
if (persistMgr->getIsSaving()) {
|
|
persistMgr->transferCharPtr(TMEMBER(_blocks[i]->_name));
|
|
_blocks[i]->persist(persistMgr);
|
|
} else {
|
|
char *name = nullptr;
|
|
persistMgr->transferCharPtr(TMEMBER(name));
|
|
bool found = false;
|
|
for (int32 j = 0; j < _blocks.getSize(); j++) {
|
|
if (scumm_stricmp(name, _blocks[j]->_name) == 0) {
|
|
_blocks[j]->persist(persistMgr);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
AdBlock *block = new AdBlock(_game);
|
|
block->persist(persistMgr);
|
|
delete block;
|
|
}
|
|
SAFE_DELETE_ARRAY(name);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int32 numPlanes = _planes.getSize();
|
|
persistMgr->transferSint32(TMEMBER(numPlanes));
|
|
for (i = 0; i < numPlanes; i++) {
|
|
if (persistMgr->getIsSaving()) {
|
|
persistMgr->transferCharPtr(TMEMBER(_planes[i]->_name));
|
|
_planes[i]->persist(persistMgr);
|
|
} else {
|
|
char *name = nullptr;
|
|
persistMgr->transferCharPtr(TMEMBER(name));
|
|
bool found = false;
|
|
for (int32 j = 0; j < _planes.getSize(); j++) {
|
|
if (scumm_stricmp(name, _planes[j]->_name) == 0) {
|
|
_planes[j]->persist(persistMgr);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
AdWalkplane *plane = new AdWalkplane(_game);
|
|
plane->persist(persistMgr);
|
|
delete plane;
|
|
}
|
|
SAFE_DELETE_ARRAY(name);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int32 numGenerics = _generics.getSize();
|
|
persistMgr->transferSint32(TMEMBER(numGenerics));
|
|
for (i = 0; i < numGenerics; i++) {
|
|
if (persistMgr->getIsSaving()) {
|
|
persistMgr->transferCharPtr(TMEMBER(_generics[i]->_name));
|
|
_generics[i]->persist(persistMgr);
|
|
} else {
|
|
char *name = nullptr;
|
|
persistMgr->transferCharPtr(TMEMBER(name));
|
|
bool found = false;
|
|
for (int32 j = 0; j < _generics.getSize(); j++) {
|
|
if (scumm_stricmp(name, _generics[j]->_name) == 0) {
|
|
_generics[j]->persist(persistMgr);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
AdGeneric *generic = new AdGeneric(_game);
|
|
generic->persist(persistMgr);
|
|
delete generic;
|
|
}
|
|
SAFE_DELETE_ARRAY(name);
|
|
}
|
|
}
|
|
|
|
if (!persistMgr->getIsSaving()) {
|
|
_maxLightsWarning = false;
|
|
}
|
|
|
|
// initialise to defaults
|
|
if (!persistMgr->getIsSaving()) {
|
|
memset(&_drawingViewport, 0, sizeof(DXViewport));
|
|
|
|
DXMatrixIdentity(&_lastWorldMat);
|
|
DXMatrixIdentity(&_lastViewMat);
|
|
DXMatrixIdentity(&_lastProjMat);
|
|
|
|
_lastOffsetX = _lastOffsetY = 0;
|
|
_lastScrollX = _lastScrollY = 0;
|
|
|
|
_PFAlternateDist = FLT_MAX; // this is not stored in original, lets restore to default
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool AdSceneGeometry::convert3Dto2D(DXVector3 *pos, int32 *x, int32 *y) {
|
|
DXMatrix worldMat;
|
|
DXMatrixIdentity(&worldMat);
|
|
|
|
DXVector3 vect2D;
|
|
DXVec3Project(&vect2D, pos, &_drawingViewport, &_lastProjMat, &_lastViewMat, &worldMat);
|
|
*x = vect2D._x + _lastScrollX;
|
|
*y = vect2D._y + _lastScrollY;
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace Wintermute
|