Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,111 @@
/* 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/base/gfx/3dcamera.h"
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
#include "engines/wintermute/base/gfx/3dutils.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Camera3D::Camera3D(BaseGame *inGame) : BaseNamedObject(inGame) {
_position = DXVector3(0.0f, 0.0f, 0.0f);
_target = DXVector3(0.0f, 0.0f, 0.0f);
_bank = 0.0f;
_fov = _origFov = degToRad(45.0f);
_nearClipPlane = _farClipPlane = -1.0f;
}
//////////////////////////////////////////////////////////////////////////
Camera3D::~Camera3D() {
}
//////////////////////////////////////////////////////////////////////////
bool Camera3D::getViewMatrix(DXMatrix *viewMatrix) {
DXVector3 up = DXVector3(0.0f, 1.0f, 0.0f);
if (_bank != 0) {
DXMatrix rot;
DXMatrixRotationZ(&rot, degToRad(_bank));
DXVec3TransformCoord(&up, &up, &rot);
}
DXMatrixLookAtLH(viewMatrix, &_position, &_target, &up);
return true;
}
//////////////////////////////////////////////////////////////////////////
void Camera3D::setupPos(DXVector3 pos, DXVector3 target, float bank) {
_position = pos;
_target = target;
_bank = bank;
}
//////////////////////////////////////////////////////////////////////////
void Camera3D::rotateView(float x, float y, float z) {
DXVector3 vVector; // Vector for the position/view.
// Get our view vector (The direciton we are facing)
vVector = _target - _position; // This gets the direction of the view
// Rotate the view along the desired axis
if (x) {
// Rotate the view vector up or down, then add it to our position
_target._z = (float)(_position._z + sin(x) * vVector._y + cos(x) * vVector._z);
_target._y = (float)(_position._y + cos(x) * vVector._y - sin(x) * vVector._z);
}
if (y) {
// Rotate the view vector right or left, then add it to our position
_target._z = (float)(_position._z + sin(y) * vVector._x + cos(y) * vVector._z);
_target._x = (float)(_position._x + cos(y) * vVector._x - sin(y) * vVector._z);
}
if (z) {
// Rotate the view vector diagnally right or diagnally down, then add it to our position
_target._x = (float)(_position._x + sin(z) * vVector._y + cos(z) * vVector._x);
_target._y = (float)(_position._y + cos(z) * vVector._y - sin(z) * vVector._x);
}
}
//////////////////////////////////////////////////////////////////////////
void Camera3D::move(float speed) {
DXVector3 vector; // Init a vector for our view
// Get our view vector (The direciton we are facing)
vector = _target - _position; // This gets the direction of the view
_position._x += vector._x * speed; // Add our acceleration to our position's X
_position._z += vector._z * speed; // Add our acceleration to our position's Z
_target._x += vector._x * speed; // Add our acceleration to our view's X
_target._z += vector._z * speed; // Add our acceleration to our view's Z
}
} // namespace Wintermute

View File

@@ -0,0 +1,58 @@
/* 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
*/
#ifndef WINTERMUTE_CAMERA3D_H
#define WINTERMUTE_CAMERA3D_H
#include "common/memstream.h"
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/gfx/xmath.h"
namespace Wintermute {
class Camera3D : public BaseNamedObject {
public:
void move(float speed);
void rotateView(float x, float y, float z);
void setupPos(DXVector3 pos, DXVector3 target, float bank = 0);
bool getViewMatrix(DXMatrix *viewMatrix);
Camera3D(BaseGame *inGame);
virtual ~Camera3D();
DXVector3 _position;
DXVector3 _target;
float _bank;
float _fov;
float _origFov;
float _nearClipPlane;
float _farClipPlane;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,78 @@
/* 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/crc.h"
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/gfx/3deffect.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
Effect3D::Effect3D(BaseGame *inGame) : BaseClass(inGame) {
_filename = nullptr;
_effectHash = 0xFFFFFFFF;
}
//////////////////////////////////////////////////////////////////////////
Effect3D::~Effect3D() {
SAFE_DELETE_ARRAY(_filename);
_effectHash = 0xFFFFFFFF;
}
//////////////////////////////////////////////////////////////////////////
bool Effect3D::invalidateDeviceObjects() {
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Effect3D::restoreDeviceObjects() {
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Effect3D::createFromFile(const char *filename) {
uint32 size;
byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &size);
if (!buffer) {
return false;
}
BaseUtils::setString(&_filename, filename);
Common::CRC32 crc;
_effectHash = crc.crcFast(buffer, size);
delete[] buffer;
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,54 @@
/* 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
*/
#ifndef WINTERMUTE_3D_EFFECT_H
#define WINTERMUTE_3D_EFFECT_H
#include "engines/wintermute/base/base_named_object.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
class Effect3D : public BaseClass {
public:
Effect3D(BaseGame *inGame);
~Effect3D();
bool createFromFile(const char *filename);
uint32 getEffectHash() { return _effectHash; }
bool invalidateDeviceObjects();
bool restoreDeviceObjects();
const char *getFileName() { return _filename; }
private:
char *_filename;
uint32 _effectHash;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,203 @@
/* 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/crc.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/scriptables/script_value.h"
#include "engines/wintermute/base/gfx/3deffect_params.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParam::Effect3DParam() {
setDefaultValues();
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParam::Effect3DParam(const char *paramName) {
setDefaultValues();
BaseUtils::setString(&_paramName, paramName);
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParam::~Effect3DParam() {
SAFE_DELETE_ARRAY(_paramName);
SAFE_DELETE_ARRAY(_valString);
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(char *val) {
_type = EP_STRING;
BaseUtils::setString(&_valString, val);
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(int val) {
_type = EP_INT;
_valInt = val;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(float val) {
_type = EP_FLOAT;
_valFloat = val;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(bool val) {
_type = EP_BOOL;
_valBool = val;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setValue(DXVector4 val) {
_type = EP_VECTOR;
_valVector = val;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::Effect3DParam::setDefaultValues() {
_paramName = nullptr;
_valString = nullptr;
_valInt = 0;
_valFloat = 0;
_valBool = 0;
_valVector = DXVector4(0, 0, 0, 0);
_type = EP_UNKNOWN;
_initialized = false;
}
//////////////////////////////////////////////////////////////////////////
bool Effect3DParams::Effect3DParam::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferCharPtr(TMEMBER(_paramName));
persistMgr->transferSint32(TMEMBER_INT(_type));
persistMgr->transferCharPtr(TMEMBER(_valString));
persistMgr->transferSint32(TMEMBER(_valInt));
persistMgr->transferFloat(TMEMBER(_valFloat));
persistMgr->transferVector4d(TMEMBER(_valVector));
persistMgr->transferBool(TMEMBER(_valBool));
if (!persistMgr->getIsSaving()) {
_initialized = false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParams() {
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::~Effect3DParams() {
clear();
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::clear() {
for (int32 i = 0; i < _params.getSize(); i++) {
SAFE_DELETE(_params[i]);
}
_params.removeAll();
}
//////////////////////////////////////////////////////////////////////////
bool Effect3DParams::persist(BasePersistenceManager *persistMgr) {
if (persistMgr->getIsSaving()) {
int32 numItems = _params.getSize();
persistMgr->transferSint32(TMEMBER(numItems));
for (int32 i = 0; i < numItems; i++) {
_params[i]->persist(persistMgr);
}
} else {
uint32 numItems = 0;
persistMgr->transferUint32(TMEMBER(numItems));
for (uint32 i = 0; i < numItems; i++) {
Effect3DParam *param = new Effect3DParam();
param->persist(persistMgr);
_params.add(param);
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::setParam(const char *paramName, ScValue *val) {
Effect3DParam *param = getParamByName(paramName);
switch (val->getType()) {
case VAL_INT:
param->setValue(val->getInt());
break;
case VAL_FLOAT:
param->setValue((float)val->getFloat());
break;
case VAL_BOOL:
param->setValue(val->getBool());
break;
default:
param->setValue(val->getString());
}
}
//////////////////////////////////////////////////////////////////////////
void Effect3DParams::setParam(const char *paramName, DXVector4 val) {
Effect3DParam *param = getParamByName(paramName);
param->setValue(val);
}
//////////////////////////////////////////////////////////////////////////
Effect3DParams::Effect3DParam *Effect3DParams::getParamByName(const char *paramName) {
Effect3DParam *param = nullptr;
for (int32 i = 0; i < _params.getSize(); i++) {
if (_params[i]->getParamName() && strcmp(paramName, _params[i]->getParamName()) == 0) {
param = _params[i];
break;
}
}
if (!param) {
param = new Effect3DParam(paramName);
_params.add(param);
}
return param;
}
} // namespace Wintermute

View File

@@ -0,0 +1,96 @@
/* 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
*/
#ifndef WINTERMUTE_3D_EFFECT_PARAMS_H
#define WINTERMUTE_3D_EFFECT_PARAMS_H
#include "engines/wintermute/base/base_game.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
class Effect3DParams {
public:
//////////////////////////////////////////////////////////////////////////
class Effect3DParam {
public:
enum ParamType {
EP_UNKNOWN,
EP_STRING,
EP_FLOAT,
EP_INT,
EP_BOOL,
EP_VECTOR
};
Effect3DParam();
Effect3DParam(const char *paramName);
~Effect3DParam();
void setValue(char *val);
void setValue(int val);
void setValue(float val);
void setValue(bool val);
void setValue(DXVector4 val);
const char *getParamName() const { return _paramName; }
bool persist(BasePersistenceManager *persistMgr);
private:
void setDefaultValues();
ParamType _type;
char * _paramName;
bool _initialized;
char *_valString;
int32 _valInt;
float _valFloat;
DXVector4 _valVector;
bool _valBool;
};
//////////////////////////////////////////////////////////////////////////
Effect3DParams();
~Effect3DParams();
bool persist(BasePersistenceManager *persistMgr);
void clear();
void setParam(const char *paramName, ScValue *val);
void setParam(const char *paramName, DXVector4 Val);
private:
Effect3DParam *getParamByName(const char *paramName);
BaseArray<Effect3DParam *> _params;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,49 @@
/* 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/base/gfx/3dface.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Face3D::Face3D() {
for (int i = 0; i < 3; i++) {
_normals[i] = DXVector3(0, 0, 0);
_vertices[i] = 0;
}
}
//////////////////////////////////////////////////////////////////////////
Face3D::~Face3D() {
}
} // namespace Wintermute

View File

@@ -0,0 +1,45 @@
/* 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
*/
#ifndef WINTERMUTE_3D_FACE_H
#define WINTERMUTE_3D_FACE_H
#include "engines/wintermute/base/gfx/xmath.h"
namespace Wintermute {
class Face3D {
public:
uint16 _vertices[3];
DXVector3 _normals[3];
Face3D();
virtual ~Face3D();
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,89 @@
/* 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/base/base_game.h"
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
#include "engines/wintermute/base/gfx/3dlight.h"
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
#include "engines/wintermute/math/math_util.h"
#include "engines/wintermute/wintypes.h"
#include "graphics/opengl/system_headers.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
Light3D::Light3D(BaseGame *inGame) : BaseScriptable(inGame, false, false) {
_diffuseColor = BYTETORGBA(255, 255, 255, 255);
_pos = DXVector3(0, 0, 0);
_target = DXVector3(0, 0, 0);
_isSpotlight = false;
_falloff = 0;
_active = true;
_distance = 0.0f;
_isAvailable = false;
}
//////////////////////////////////////////////////////////////////////////
Light3D::~Light3D() {
}
//////////////////////////////////////////////////////////////////////////
bool Light3D::setLight(int index) {
DXVector4 diffuse;
diffuse._x = RGBCOLGetR(_diffuseColor) / 256.0f;
diffuse._y = RGBCOLGetG(_diffuseColor) / 256.0f;
diffuse._z = RGBCOLGetB(_diffuseColor) / 256.0f;
diffuse._w = 1.0f;
DXVector3 dir = _target - _pos;
DXVec3Normalize(&dir, &dir);
_game->_renderer3D->setLightParameters(index, _pos, dir, diffuse, _isSpotlight);
if (_active) {
_game->_renderer3D->lightEnable(index, true);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Light3D::getViewMatrix(DXMatrix *viewMatrix) {
DXVector3 up = DXVector3(0.0f, 1.0f, 0.0f);
DXMatrixLookAtLH(viewMatrix, &_pos, &_target, &up);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Light3D::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferBool(TMEMBER(_active));
persistMgr->transferUint32(TMEMBER(_diffuseColor));
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,59 @@
/* 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
*/
#ifndef WINTERMUTE_3D_LIGHT_H
#define WINTERMUTE_3D_LIGHT_H
#include "common/memstream.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/base/base_scriptable.h"
namespace Wintermute {
class Light3D : public BaseScriptable {
public:
bool persist(BasePersistenceManager *persistMgr);
bool getViewMatrix(DXMatrix *viewMatrix);
Light3D(BaseGame *inGame);
virtual ~Light3D();
uint32 _diffuseColor;
DXVector3 _pos;
DXVector3 _target;
bool _isSpotlight;
bool _active;
float _falloff;
float _distance;
bool _isAvailable;
bool setLight(int index = 0);
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,525 @@
/* 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/>.
*
*/
#include "engines/wintermute/dcgf.h"
#include "engines/wintermute/math/math_util.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
#include "engines/wintermute/base/gfx/3dface.h"
#include "engines/wintermute/base/gfx/3dvertex.h"
#include "engines/wintermute/base/gfx/3dutils.h"
namespace Wintermute {
#define MAIN3DS 0x4D4D // level 1
#define EDIT3DS 0x3D3D // level 1
#define NAMED_OBJECT 0x4000 // level 2
#define TRIANGLE_MESH 0x4100 // level 3
#define TRIANGLE_VERTEXLIST 0x4110 // level 4
#define TRIANGLE_FACELIST 0x4120 // level 4
#define CHUNK_CAMERA 0x4700 // level 3
#define CHUNK_LIGHT 0x4600
#define LIGHT_SPOTLIGHT 0x4610
#define LIGHT_IS_OFF 0x4620
#define RGB_FLOAT 0x0010
#define RGB_BYTE 0x0011
#define KEYFRAMER 0xB000 // level 1
#define KEYFRAMER_AMBIENT_INFO 0xB001
#define KEYFRAMER_MESH_INFO 0xB002
#define KEYFRAMER_CAMERA_INFO 0xB003
#define KEYFRAMER_CAMERA_TARGET_INFO 0xB004
#define KEYFRAMER_OMNI_INFO 0xB005
#define KEYFRAMER_SPOT_TARGET_INFO 0xB006
#define KEYFRAMER_SPOT_INFO 0xB007
#define NODE_HDR 0xB010
#define ROLL_TRACK_TAG 0xB024
//////////////////////////////////////////////////////////////////////////
Loader3DS::Loader3DS(BaseGame *inGame) : BaseNamedObject(inGame) {
_filename = nullptr;
}
//////////////////////////////////////////////////////////////////////////
Loader3DS::~Loader3DS() {
for (int32 i = 0; i < _objects.getSize(); i++)
delete _objects[i];
_objects.removeAll();
SAFE_DELETE_ARRAY(_filename);
}
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
Loader3DS::FileObject3DS::FileObject3DS() {
_name = nullptr;
_type = OBJ_3DS_NONE;
_numVertices = 0;
_vertices = nullptr;
_numFaces = 0;
_faces = nullptr;
_lightOff = false;
_lightSpotlight = false;
_lightColor = 0;
_lightHotspot = false;
_lightFalloff = false;
_lightTarget._x = _lightTarget._y = _lightTarget._z = 0.0f;
_lightPos._x = _lightPos._y = _lightPos._z = 0.0f;
_cameraBank = 0;
_cameraLens = 0;
_cameraFOV = 0;
_cameraPos._x = _cameraPos._y = _cameraPos._z = 0.0f;
_hidden = false;
}
//////////////////////////////////////////////////////////////////////
Loader3DS::FileObject3DS::~FileObject3DS() {
if (_name != nullptr)
delete[] _name;
if (_vertices != nullptr)
delete[] _vertices;
if (_faces != nullptr)
delete[] _faces;
}
//////////////////////////////////////////////////////////////////////////
bool Loader3DS::parseFile(const char *filename) {
SAFE_DELETE_ARRAY(_filename);
size_t filenameSize = strlen(filename) + 1;
_filename = new char[filenameSize];
Common::strcpy_s(_filename, filenameSize, filename);
uint32 fileSize;
byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &fileSize);
if (!buffer)
return false;
uint16 keyframerSection = 0;
char *keyframerObject = nullptr;
FileObject3DS *obj = nullptr;
uint16 i;
Common::MemoryReadStream fileStream(buffer, fileSize);
while (fileStream.pos() < fileStream.size()) {
uint16 chunkId = fileStream.readUint16LE();
uint32 chunkLength = fileStream.readUint32LE();
bool handled = true;
switch (chunkId) {
case MAIN3DS:
break;
case EDIT3DS:
break;
//////////////////////////////////////////////////////////////////////
// object ////////////////////////////////////////////////////////////
case NAMED_OBJECT: {
obj = new FileObject3DS;
auto name = fileStream.readString();
size_t nameSize = name.size() + 1;
obj->_name = new char[nameSize];
Common::strcpy_s(obj->_name, nameSize, name.c_str());
_objects.add(obj);
}
break;
// mesh //////////////////////////////////////////////////////////////
case TRIANGLE_MESH:
if (obj == nullptr)
break;
obj->_type = OBJ_3DS_MESH;
break;
case TRIANGLE_VERTEXLIST:
if (obj == nullptr || obj->_type != OBJ_3DS_MESH)
break;
obj->_numVertices = fileStream.readUint16LE();
obj->_vertices = new DXVector3[obj->_numVertices];
for (i = 0; i < obj->_numVertices; i++) {
obj->_vertices[i]._x = fileStream.readFloatLE();
obj->_vertices[i]._z = fileStream.readFloatLE();
obj->_vertices[i]._y = fileStream.readFloatLE();
}
break;
case TRIANGLE_FACELIST:
if (obj == nullptr || obj->_type != OBJ_3DS_MESH)
break;
obj->_numFaces = fileStream.readUint16LE();
obj->_faces = new SFace[obj->_numFaces];
for (i = 0; i < obj->_numFaces; i++) {
obj->_faces[i]._a = fileStream.readUint16LE();
obj->_faces[i]._c = fileStream.readUint16LE();
obj->_faces[i]._b = fileStream.readUint16LE();
fileStream.readUint16LE(); // skip
}
break;
// camera //////////////////////////////////////////////////////////////
case CHUNK_CAMERA:
if (obj == nullptr)
break;
obj->_type = OBJ_3DS_CAMERA;
obj->_cameraPos._x = fileStream.readFloatLE();
obj->_cameraPos._z = fileStream.readFloatLE();
obj->_cameraPos._y = fileStream.readFloatLE();
obj->_cameraTarget._x = fileStream.readFloatLE();
obj->_cameraTarget._z = fileStream.readFloatLE();
obj->_cameraTarget._y = fileStream.readFloatLE();
obj->_cameraBank = fileStream.readFloatLE();
obj->_cameraLens = fileStream.readFloatLE();
if (obj->_cameraLens > 0)
obj->_cameraFOV = 1900.0f / obj->_cameraLens;
else
obj->_cameraFOV = 45.0f;
break;
// light //////////////////////////////////////////////////////////////
case CHUNK_LIGHT:
if (obj == nullptr)
break;
obj->_type = OBJ_3DS_LIGHT;
obj->_lightPos._x = fileStream.readFloatLE();
obj->_lightPos._z = fileStream.readFloatLE();
obj->_lightPos._y = fileStream.readFloatLE();
break;
case LIGHT_SPOTLIGHT:
if (obj == nullptr || obj->_type != OBJ_3DS_LIGHT)
break;
obj->_lightTarget._x = fileStream.readFloatLE();
obj->_lightTarget._z = fileStream.readFloatLE();
obj->_lightTarget._y = fileStream.readFloatLE();
obj->_lightHotspot = fileStream.readFloatLE();
obj->_lightFalloff = fileStream.readFloatLE();
obj->_lightSpotlight = true;
break;
case LIGHT_IS_OFF:
if (obj == nullptr || obj->_type != OBJ_3DS_LIGHT)
break;
obj->_lightOff = true;
break;
// colors ////////////////////////////////////////////////////////////////////////
case RGB_FLOAT:
if (obj && obj->_type == OBJ_3DS_LIGHT) {
float r, g, b;
r = fileStream.readFloatLE();
g = fileStream.readFloatLE();
b = fileStream.readFloatLE();
obj->_lightColor = BYTETORGBA((int)(r * 255), (int)(g * 255), (int)(b * 255), 255);
} else
handled = false;
break;
case RGB_BYTE:
if (obj && obj->_type == OBJ_3DS_LIGHT) {
byte r, g, b;
r = fileStream.readByte();
g = fileStream.readByte();
b = fileStream.readByte();
obj->_lightColor = BYTETORGBA(r, g, b, 255);
} else
handled = false;
break;
// keyframer stuff
case KEYFRAMER:
break;
case KEYFRAMER_AMBIENT_INFO:
case KEYFRAMER_MESH_INFO:
case KEYFRAMER_CAMERA_INFO:
case KEYFRAMER_CAMERA_TARGET_INFO:
case KEYFRAMER_OMNI_INFO:
case KEYFRAMER_SPOT_TARGET_INFO:
case KEYFRAMER_SPOT_INFO:
keyframerSection = chunkId;
break;
case NODE_HDR: {
// object name
SAFE_DELETE_ARRAY(keyframerObject);
auto keyname = fileStream.readString();
size_t keynameSize = keyname.size() + 1;
keyframerObject = new char[keynameSize];
Common::strcpy_s(keyframerObject, keynameSize, keyname.c_str());
// flags1
fileStream.readUint16LE();
// flags2
fileStream.readUint16LE();
// hierarchy
fileStream.readUint16LE();
}
break;
case ROLL_TRACK_TAG:
if (keyframerSection == KEYFRAMER_CAMERA_INFO && keyframerObject != nullptr) {
// flags
fileStream.readUint16LE();
// unknown
fileStream.readUint16LE();
fileStream.readUint16LE();
fileStream.readUint16LE();
fileStream.readUint16LE();
// keys
uint16 keys = fileStream.readUint16LE();
// unknown
fileStream.readUint16LE();
for (uint16 key = 0; key < keys; key++) {
// frame number
fileStream.readUint16LE();
// unknown
fileStream.readUint32LE();
// camera roll
float cameraRoll = fileStream.readFloatLE();
// inject this roll value to the camera
if (key == 0) {
for (int32 index = 0; index < _objects.getSize(); index++) {
if (_objects[index]->_type == OBJ_3DS_CAMERA && scumm_stricmp(_objects[index]->_name, keyframerObject) == 0) {
_objects[index]->_cameraBank = cameraRoll;
break;
}
}
}
}
} else
handled = false;
break;
default:
handled = false;
}
if (!handled)
fileStream.seek(chunkLength - 6, SEEK_CUR);
}
SAFE_DELETE_ARRAY(keyframerObject);
delete[] buffer;
return true;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int32 Loader3DS::getNumMeshes() {
int32 ret = 0;
for (int32 i = 0; i < _objects.getSize(); i++)
if (_objects[i]->_type == OBJ_3DS_MESH)
ret++;
return ret;
}
//////////////////////////////////////////////////////////////////////////
char *Loader3DS::getMeshName(int index) {
int32 pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_MESH)
pos++;
if (pos == index)
return _objects[i]->_name;
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool Loader3DS::loadMesh(int index, Mesh3DS *mesh) {
if (!mesh)
return false;
int pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_MESH)
pos++;
if (pos == index){
FileObject3DS *obj = _objects[i];
mesh->cleanup();
mesh->_numVertices = obj->_numVertices;
mesh->_numFaces = obj->_numFaces;
int j;
mesh->_vertices = new Vertex3D[mesh->_numVertices];
for (j = 0; j < mesh->_numVertices; j++) {
mesh->_vertices[j]._pos._x = obj->_vertices[j]._x;
mesh->_vertices[j]._pos._y = obj->_vertices[j]._y;
mesh->_vertices[j]._pos._z = obj->_vertices[j]._z;
}
mesh->_faces = new Face3D[mesh->_numFaces];
for (j = 0; j < mesh->_numFaces; j++) {
mesh->_faces[j]._vertices[0] = obj->_faces[j]._a;
mesh->_faces[j]._vertices[1] = obj->_faces[j]._b;
mesh->_faces[j]._vertices[2] = obj->_faces[j]._c;
}
mesh->setName(obj->_name);
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int32 Loader3DS::getNumLights() {
int ret = 0;
for (int32 i = 0; i < _objects.getSize(); i++)
if (_objects[i]->_type == OBJ_3DS_LIGHT)
ret++;
return ret;
}
//////////////////////////////////////////////////////////////////////////
char *Loader3DS::getLightName(int index) {
int pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_LIGHT)
pos++;
if (pos == index)
return _objects[i]->_name;
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool Loader3DS::loadLight(int index, Light3D *light) {
if (!light)
return false;
int pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_LIGHT) {
pos++;
if (pos == index) {
light->setName(_objects[i]->_name);
light->_pos = _objects[i]->_lightPos;
light->_target = _objects[i]->_lightTarget;
light->_isSpotlight = _objects[i]->_lightSpotlight;
light->_active = !_objects[i]->_lightOff;
light->_diffuseColor = _objects[i]->_lightColor;
light->_falloff = _objects[i]->_lightFalloff;
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int32 Loader3DS::getNumCameras() {
int32 ret = 0;
for (int32 i = 0; i < _objects.getSize(); i++)
if (_objects[i]->_type == OBJ_3DS_CAMERA)
ret++;
return ret;
}
//////////////////////////////////////////////////////////////////////////
char *Loader3DS::getCameraName(int index) {
int32 pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_CAMERA)
pos++;
if (pos == index)
return _objects[i]->_name;
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool Loader3DS::loadCamera(int index, Camera3D *camera) {
if (!camera)
return false;
int pos = -1;
for (int32 i = 0; i < _objects.getSize(); i++) {
if (_objects[i]->_type == OBJ_3DS_CAMERA)
pos++;
if (pos == index) {
camera->setupPos(_objects[i]->_cameraPos, _objects[i]->_cameraTarget, _objects[i]->_cameraBank);
camera->setName(_objects[i]->_name);
camera->_fov = camera->_origFov = degToRad(_objects[i]->_cameraFOV);
return true;
}
}
return false;
}
} // namespace Wintermute

View File

@@ -0,0 +1,94 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_3D_LOADER_3DS_H
#define WINTERMUTE_3D_LOADER_3DS_H
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/gfx/3dcamera.h"
#include "engines/wintermute/base/gfx/3dlight.h"
#include "engines/wintermute/base/gfx/3dmesh.h"
#include "common/str.h"
namespace Wintermute {
class Loader3DS : public BaseNamedObject {
public:
enum E3DSFileObjectType{
OBJ_3DS_NONE,
OBJ_3DS_MESH,
OBJ_3DS_CAMERA,
OBJ_3DS_LIGHT
};
struct SFace{
uint16 _a;
uint16 _b;
uint16 _c;
};
class FileObject3DS {
public:
DXVector3 _cameraTarget;
float _cameraBank;
float _cameraLens;
float _cameraFOV;
DXVector3 _cameraPos;
DXVector3 _lightTarget;
DXVector3 _lightPos;
uint32 _lightColor;
float _lightHotspot;
float _lightFalloff;
bool _lightOff;
bool _lightSpotlight;
bool _hidden;
uint16 _numFaces;
SFace *_faces;
DXVector3 *_vertices;
uint16 _numVertices;
char *_name;
E3DSFileObjectType _type;
virtual ~FileObject3DS();
FileObject3DS();
};
public:
char * getCameraName(int index);
char * getLightName(int index);
char * getMeshName(int index);
bool loadCamera(int index, Camera3D *camera);
int32 getNumCameras();
bool loadLight(int index, Light3D *light);
int32 getNumLights();
bool loadMesh(int index, Mesh3DS *mesh);
int32 getNumMeshes();
bool parseFile(const char *filename);
char *_filename;
Loader3DS(BaseGame *inGame);
virtual ~Loader3DS();
BaseArray<FileObject3DS *> _objects;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,172 @@
/* 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/file.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/3dloader_3ds.h"
#include "engines/wintermute/base/gfx/3dmesh.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Mesh3DS::Mesh3DS(BaseGame *inGame) : BaseNamedObject(inGame) {
_vertices = nullptr;
_faces = nullptr;
_numFaces = _numVertices = 0;
_visible = true;
}
//////////////////////////////////////////////////////////////////////////
Mesh3DS::~Mesh3DS() {
cleanup();
}
//////////////////////////////////////////////////////////////////////////
void Mesh3DS::cleanup() {
SAFE_DELETE_ARRAY(_vertices);
_numVertices = 0;
SAFE_DELETE_ARRAY(_faces);
_numFaces = 0;
_vb.free();
}
//////////////////////////////////////////////////////////////////////////
bool Mesh3DS::createVertexBuffer() {
_vb.free();
if (_numFaces == 0)
return true;
int vbSize = _numFaces * sizeof(Mesh3DSVertex) * 3;
_vb = DXBuffer(vbSize);
if (_vb.ptr() == nullptr) {
_game->LOG(0, "Error creating vertex buffer.");
return false;
} else
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Mesh3DS::fillVertexBuffer(uint32 color) {
_vb.free();
if (_numFaces == 0)
return true;
int vbSize = _numFaces * sizeof(Mesh3DSVertex) * 3;
_vb = DXBuffer(vbSize);
if (_vb.ptr() == nullptr) {
_game->LOG(0, "Error creating vertex buffer.");
return false;
}
Mesh3DSVertex *verts = (Mesh3DSVertex *)_vb.ptr();
for (int i = 0; i < _numFaces; i++) {
for (int j = 0; j < 3; j++) {
int outVert = i * 3 + j;
int vertex = _faces[i]._vertices[j];
verts[outVert]._x = _vertices[vertex]._pos._x;
verts[outVert]._y = _vertices[vertex]._pos._y;
verts[outVert]._z = _vertices[vertex]._pos._z;
verts[outVert]._nx = _faces[i]._normals[j]._x;
verts[outVert]._ny = _faces[i]._normals[j]._y;
verts[outVert]._nz = _faces[i]._normals[j]._z;
verts[outVert]._r = RGBCOLGetR(color) / 255.0f;
verts[outVert]._g = RGBCOLGetG(color) / 255.0f;
verts[outVert]._b = RGBCOLGetB(color) / 255.0f;
verts[outVert]._a = RGBCOLGetA(color) / 255.0f;
}
}
fillVertexBuffer();
return true;
}
//////////////////////////////////////////////////////////////////////////
void Mesh3DS::computeNormals() {
DXVector3 *normals = new DXVector3[_numVertices];
for (uint32 i = 0; i < _numVertices; i++) {
normals[i]._x = 0.0f;
normals[i]._y = 0.0f;
normals[i]._z = 0.0f;
}
for (uint32 i = 0; i < _numFaces; i++) {
uint16 a = _faces[i]._vertices[0];
uint16 b = _faces[i]._vertices[1];
uint16 c = _faces[i]._vertices[2];
DXVector3 *v1 = &_vertices[a]._pos;
DXVector3 *v2 = &_vertices[b]._pos;
DXVector3 *v3 = &_vertices[c]._pos;
DXVector3 edge1 = *v2 - *v1;
DXVector3 edge2 = *v3 - *v2;
DXVector3 normal;
DXVec3Cross(&normal, &edge1, &edge2);
DXVec3Normalize(&normal, &normal);
normals[a] += normal;
normals[b] += normal;
normals[c] += normal;
}
// Assign the newly computed normals back to the vertices
for (uint32 i = 0; i < _numFaces; i++) {
for (uint32 j = 0; j < 3; j++) {
DXVec3Normalize(&_faces[i]._normals[j], &normals[_faces[i]._vertices[j]]);
//_faces[i]._normals[j] = normals[_faces[i]._vertices[j]];
}
}
delete[] normals;
}
//////////////////////////////////////////////////////////////////////////
bool Mesh3DS::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferBool(TMEMBER(_visible));
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,77 @@
/* 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
*/
#ifndef WINTERMUTE_3D_MESH_H
#define WINTERMUTE_3D_MESH_H
#include "common/memstream.h"
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/gfx/xmath.h"
#include "engines/wintermute/base/gfx/xbuffer.h"
#include "engines/wintermute/base/gfx/3dface.h"
#include "engines/wintermute/base/gfx/3dvertex.h"
namespace Wintermute {
#if defined(SCUMMVM_USE_PRAGMA_PACK)
#pragma pack(4)
#endif
struct Mesh3DSVertex {
float _x, _y, _z;
float _nx, _ny, _nz;
float _r, _g, _b, _a;
};
#if defined(SCUMMVM_USE_PRAGMA_PACK)
#pragma pack()
#endif
class Mesh3DS : public BaseNamedObject {
public:
bool persist(BasePersistenceManager *persistMgr);
bool createVertexBuffer();
void computeNormals();
void cleanup();
Mesh3DS(BaseGame *inGame);
virtual ~Mesh3DS();
virtual void fillVertexBuffer() = 0;
bool fillVertexBuffer(uint32 color);
virtual void render(bool color = false) = 0;
Face3D *_faces;
uint16 _numFaces;
uint16 _numVertices;
Vertex3D *_vertices;
DXBuffer _vb;
bool _visible;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,176 @@
/* 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/base/base_game.h"
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
#include "engines/wintermute/base/gfx/3dshadow_volume.h"
#include "engines/wintermute/base/gfx/xskinmesh.h"
#include "engines/wintermute/dcgf.h"
#include "graphics/opengl/system_headers.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
ShadowVolume::ShadowVolume(BaseGame *inGame) : BaseClass(inGame), _color(0x7f000000) {
}
//////////////////////////////////////////////////////////////////////////
ShadowVolume::~ShadowVolume() {
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolume::reset() {
_vertices.removeAll();
return true;
}
//////////////////////////////////////////////////////////////////////////^M
bool ShadowVolume::addMesh(DXMesh *mesh, uint32 *adjacency, DXMatrix *modelMat, DXVector3 *light, float extrusionDepth) {
if (!mesh || !adjacency)
return false;
DXVector3 invLight;
DXMatrix matInverseModel;
DXMatrixInverse(&matInverseModel, nullptr, modelMat);
DXVec3TransformNormal(&invLight, light, &matInverseModel);
float *points = (float *)mesh->getVertexBuffer().ptr();
if (points == nullptr) {
return false;
}
uint32 *indices = (uint32 *)mesh->getIndexBuffer().ptr();
if (indices == nullptr) {
return false;
}
uint32 numFaces = mesh->getNumFaces();
// Allocate a temporary edge list
uint32 *edges = new uint32[numFaces * 6];
if (edges == nullptr) {
return false;
}
uint32 numEdges = 0;
uint32 fvfSize = DXGetFVFVertexSize(mesh->getFVF()) / sizeof(float);
bool *isFront = new bool[numFaces];
// First pass : for each face, record if it is front or back facing the light
for (uint32 i = 0; i < numFaces; i++) {
uint32 index0 = indices[3 * i + 0];
uint32 index1 = indices[3 * i + 1];
uint32 index2 = indices[3 * i + 2];
DXVector3 v0(points + index0 * fvfSize);
DXVector3 v1(points + index1 * fvfSize);
DXVector3 v2(points + index2 * fvfSize);
// Transform vertices or transform light?
DXVector3 vNormal, vec1, vec2;
vec1 = v2 - v1;
vec2 = v1 - v0;
DXVec3Cross(&vNormal, &vec1, &vec2);
if (DXVec3Dot(&vNormal, &invLight) >= 0.0f) {
isFront[i] = false; // back face
} else {
isFront[i] = true; // front face
}
}
// First pass : for each face, record if it is front or back facing the light
for (uint32 i = 0; i < numFaces; i++) {
if (isFront[i]) {
uint32 wFace0 = indices[3 * i + 0];
uint32 wFace1 = indices[3 * i + 1];
uint32 wFace2 = indices[3 * i + 2];
uint32 adjacent0 = adjacency[3 * i + 0];
uint32 adjacent1 = adjacency[3 * i + 1];
uint32 adjacent2 = adjacency[3 * i + 2];
if (adjacent0 == 0xFFFFFFFF || isFront[adjacent0] == false) {
// add edge v0-v1
edges[2 * numEdges + 0] = wFace0;
edges[2 * numEdges + 1] = wFace1;
numEdges++;
}
if (adjacent1 == 0xFFFFFFFF || isFront[adjacent1] == false) {
// add edge v1-v2
edges[2 * numEdges + 0] = wFace1;
edges[2 * numEdges + 1] = wFace2;
numEdges++;
}
if (adjacent2 == 0xFFFFFFFF || isFront[adjacent2] == false) {
// add edge v2-v0
edges[2 * numEdges + 0] = wFace2;
edges[2 * numEdges + 1] = wFace0;
numEdges++;
}
}
}
for (uint32 i = 0; i < numEdges; i++) {
DXVector3 v1(points + edges[2 * i + 0] * fvfSize);
DXVector3 v2(points + edges[2 * i + 1] * fvfSize);
DXVector3 v3 = v1 - invLight * extrusionDepth;
DXVector3 v4 = v2 - invLight * extrusionDepth;
// Add a quad (two triangles) to the vertex list
addVertex(v1);
addVertex(v2);
addVertex(v3);
addVertex(v2);
addVertex(v4);
addVertex(v3);
}
// Delete the temporary edge list
delete[] edges;
delete[] isFront;
return true;
}
//////////////////////////////////////////////////////////////////////////
void ShadowVolume::addVertex(DXVector3 &vertex) {
_vertices.add(vertex);
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolume::setColor(uint32 color) {
if (color != _color) {
_color = color;
return initMask();
} else {
return true;
}
}
} // namespace Wintermute

View File

@@ -0,0 +1,73 @@
/* 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
*/
#ifndef WINTERMUTE_3D_SHADOW_VOLUME_H
#define WINTERMUTE_3D_SHADOW_VOLUME_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/gfx/xbuffer.h"
#include "engines/wintermute/base/gfx/xmesh.h"
#include "engines/wintermute/base/gfx/xmath.h"
#include "engines/wintermute/coll_templ.h"
namespace Wintermute {
struct ShadowVertex {
float x;
float y;
float z;
uint8 r;
uint8 g;
uint8 b;
uint8 a;
};
class ShadowVolume : public BaseClass {
public:
ShadowVolume(BaseGame *inGame);
virtual ~ShadowVolume();
bool addMesh(DXMesh *mesh, uint32 *adjacency, DXMatrix *modelMat, DXVector3 *light, float extrusionDepth);
void addVertex(DXVector3 &vertex);
bool reset();
virtual bool renderToStencilBuffer() = 0;
virtual bool renderToScene() = 0;
bool setColor(uint32 color);
protected:
BaseArray<DXVector3> _vertices; // Vertex data for rendering shadow volume
uint32 _color;
private:
virtual bool initMask() = 0;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,188 @@
/* 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/base/gfx/3dutils.h"
#include "common/scummsys.h"
#ifdef ENABLE_WME3D
#include "common/util.h"
#endif
namespace Wintermute {
#ifdef ENABLE_WME3D
bool C3DUtils::intersectTriangle(const DXVector3 &orig, const DXVector3 &dir,
DXVector3 &v0, DXVector3 &v1, DXVector3 &v2,
float *t, float *u, float *v) {
// Find vectors for two edges sharing vert0
DXVector3 edge1 = v1 - v0;
DXVector3 edge2 = v2 - v0;
// Begin calculating determinant - also used to calculate U parameter
DXVector3 pvec;
DXVec3Cross(&pvec, &dir, &edge2);
// If determinant is near zero, ray lies in plane of triangle
float det = DXVec3Dot(&edge1, &pvec);
if (det < 0.0001f)
return false;
// Calculate distance from vert0 to ray origin
DXVector3 tvec = orig - v0;
// Calculate U parameter and test bounds
*u = DXVec3Dot(&tvec, &pvec);
if (*u < 0.0f || *u > det)
return false;
// Prepare to test V parameter
DXVector3 qvec;
DXVec3Cross(&qvec, &tvec, &edge1);
// Calculate V parameter and test bounds
*v = DXVec3Dot(&dir, &qvec);
if (*v < 0.0f || *u + *v > det)
return false;
// Calculate t, scale parameters, ray intersects triangle
*t = DXVec3Dot(&edge2, &qvec);
float fInvDet = 1.0f / det;
*t *= fInvDet;
*u *= fInvDet;
*v *= fInvDet;
DXVector3 intersection;
DXVector3 dest = orig + dir;
DXPlane plane;
DXPlaneFromPoints(&plane, &v0, &v1, &v2);
DXPlaneIntersectLine(&intersection, &plane, &orig, &dest);
*t = intersection._x;
*u = intersection._y;
*v = intersection._z;
return true;
}
DXMatrix *C3DUtils::matrixSetTranslation(DXMatrix *mat, DXVector3 *vec) {
mat->matrix._41 = vec->_x;
mat->matrix._42 = vec->_y;
mat->matrix._43 = vec->_z;
return mat;
}
DXMatrix *C3DUtils::matrixSetRotation(DXMatrix *mat, DXVector3 *vec) {
double cr = cos(vec->_x);
double sr = sin(vec->_x);
double cp = cos(vec->_y);
double sp = sin(vec->_y);
double cy = cos(vec->_z);
double sy = sin(vec->_z);
mat->matrix._11 = (float)(cp * cy);
mat->matrix._12 = (float)(cp * sy);
mat->matrix._13 = (float)(-sp);
double srsp = sr * sp;
double crsp = cr * sp;
mat->matrix._21 = (float)(srsp * cy - cr * sy);
mat->matrix._22 = (float)(srsp * sy + cr * cy);
mat->matrix._23 = (float)(sr * cp);
mat->matrix._31 = (float)(crsp * cy + sr * sy);
mat->matrix._32 = (float)(crsp * sy - sr * cy);
mat->matrix._33 = (float)(cr * cp);
return mat;
}
bool C3DUtils::pickGetIntersect(DXVector3 lineStart, DXVector3 lineEnd,
DXVector3 v0, DXVector3 v1, DXVector3 v2,
DXVector3 *intersection, float *distance) {
// compute plane's normal
DXVector3 vertex;
DXVector3 normal;
DXVector3 edge1 = v1 - v0;
DXVector3 edge2 = v2 - v1;
DXVec3Cross(&normal, &edge1, &edge2);
DXVec3Normalize(&normal, &normal);
vertex = v0;
DXVector3 direction, l1;
float lineLength, distFromPlane, percentage;
direction._x = lineEnd._x - lineStart._x; // calculate the lines direction vector
direction._y = lineEnd._y - lineStart._y;
direction._z = lineEnd._z - lineStart._z;
lineLength = DXVec3Dot(&direction, &normal); // This gives us the line length (the blue dot L3 + L4 in figure d)
if (fabsf(lineLength) < 0.00001f)
return false;
l1._x = vertex._x - lineStart._x; // calculate vector L1 (the PINK line in figure d)
l1._y = vertex._y - lineStart._y;
l1._z = vertex._z - lineStart._z;
distFromPlane = DXVec3Dot(&l1, &normal); // gives the distance from the plane (ORANGE Line L3 in figure d)
percentage = distFromPlane / lineLength; // How far from Linestart , intersection is as a percentage of 0 to 1
if (percentage < 0.0)
return false;
else if (percentage > 1.0)
return false;
*distance = percentage; //record the distance from beginning of ray (0.0 -1.0)
intersection->_x = lineStart._x + direction._x * percentage; // add the percentage of the line to line start
intersection->_y = lineStart._y + direction._y * percentage;
intersection->_z = lineStart._z + direction._z * percentage;
return true;
}
void C3DUtils::decomposeMatrixSimple(const DXMatrix *mat, DXVector3 *transVec, DXVector3 *scaleVec, DXQuaternion *rotQ) {
*transVec = DXVector3(mat->matrix._41, mat->matrix._42, mat->matrix._43);
*scaleVec = DXVector3(sqrtf(mat->matrix._11 * mat->matrix._11 + mat->matrix._21 * mat->matrix._21 + mat->matrix._31 * mat->matrix._31),
sqrtf(mat->matrix._12 * mat->matrix._12 + mat->matrix._22 * mat->matrix._22 + mat->matrix._32 * mat->matrix._32),
sqrtf(mat->matrix._13 * mat->matrix._13 + mat->matrix._23 * mat->matrix._23 + mat->matrix._33 * mat->matrix._33));
DXQuaternion q;
DXQuaternionRotationMatrix(&q, mat);
*rotQ = q;
}
#endif
} // End of namespace Wintermute

View File

@@ -0,0 +1,57 @@
/* 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
*/
#ifndef WINTERMUTE_3DUTILS_H
#define WINTERMUTE_3DUTILS_H
#ifdef ENABLE_WME3D
#include "engines/wintermute/base/gfx/xmath.h"
#endif
namespace Wintermute {
#define DX_PI ((float)3.141592654f)
#define degToRad(_val) (_val * DX_PI * (1.0f / 180.0f))
#define radToDeg(_val) (_val * (180.0f / DX_PI))
class C3DUtils {
public:
static bool intersectTriangle(const DXVector3 &orig, const DXVector3 &dir,
DXVector3 &v0, DXVector3 &v1, DXVector3 &v2,
float *t, float *u, float *v);
static bool pickGetIntersect(DXVector3 linestart, DXVector3 lineend,
DXVector3 v0, DXVector3 v1, DXVector3 v2,
DXVector3 *intersection, float *distance);
static DXMatrix *matrixSetTranslation(DXMatrix *mat, DXVector3 *vec);
static DXMatrix *matrixSetRotation(DXMatrix *mat, DXVector3 *vec);
static void decomposeMatrixSimple(const DXMatrix *mat, DXVector3 *transVec,
DXVector3 *scaleVec, DXQuaternion *rotQ);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,46 @@
/* 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/base/gfx/3dvertex.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Vertex3D::Vertex3D() {
_pos = DXVector3(0, 0, 0);
}
//////////////////////////////////////////////////////////////////////////
Vertex3D::~Vertex3D() {
}
} // namespace Wintermute

View File

@@ -0,0 +1,44 @@
/* 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
*/
#ifndef WINTERMUTE_3D_VERTEX_H
#define WINTERMUTE_3D_VERTEX_H
#include "engines/wintermute/base/gfx/xmath.h"
namespace Wintermute {
class Vertex3D {
public:
DXVector3 _pos;
Vertex3D();
virtual ~Vertex3D();
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,296 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/file/base_savefile_manager_file.h"
#include "graphics/surface.h"
#include "image/png.h"
#include "image/jpeg.h"
#include "image/bmp.h"
#include "image/tga.h"
#include "common/textconsole.h"
#include "common/stream.h"
#include "common/system.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
BaseImage::BaseImage() {
_fileManager = BaseFileManager::getEngineInstance();
_palette = nullptr;
_paletteCount = 0;
_surface = nullptr;
_decoder = nullptr;
_deletableSurface = nullptr;
}
//////////////////////////////////////////////////////////////////////
BaseImage::~BaseImage() {
delete _decoder;
if (_deletableSurface) {
_deletableSurface->free();
}
delete _deletableSurface;
}
bool BaseImage::getImageInfo(const Common::String &filename, int32 &width, int32 &height) {
bool ret = false;
Common::String file = filename;
file.toLowercase();
if (file.hasPrefix("savegame:") || file.hasSuffix(".bmp")) {
ret = getImageInfoBMP(filename, width, height);
} else if (file.hasSuffix(".tga")) {
ret = getImageInfoTGA(filename, width, height);
} else if (file.hasSuffix(".png")) {
ret = getImageInfoPNG(filename, width, height);
} else if (file.hasSuffix(".jpg")) {
ret = getImageInfoJPG(filename, width, height);
} else {
warning("BaseImage::loadFile : Unsupported fileformat %s", filename.c_str());
}
return ret;
}
bool BaseImage::getImageInfoBMP(const Common::String &filename, int32 &width, int32 &height) {
Common::SeekableReadStream *stream = _fileManager->openFile(filename);
if (!stream) {
return false;
}
uint16 fileType = stream->readUint16BE();
if (fileType != MKTAG16('B', 'M')) {
_fileManager->closeFile(stream);
return false;
}
stream->skip(16);
width = stream->readSint32LE();
height = stream->readSint32LE();
_fileManager->closeFile(stream);
return true;
}
bool BaseImage::getImageInfoTGA(const Common::String &filename, int32 &width, int32 &height) {
Common::SeekableReadStream *stream = _fileManager->openFile(filename);
if (!stream) {
return false;
}
stream->skip(12);
width = stream->readSint16LE();
height = stream->readSint16LE();
_fileManager->closeFile(stream);
return true;
}
bool BaseImage::getImageInfoPNG(const Common::String &filename, int32 &width, int32 &height) {
Common::SeekableReadStream *stream = _fileManager->openFile(filename);
if (!stream) {
return false;
}
if (stream->readUint32BE() != MKTAG(0x89, 'P', 'N', 'G')) {
_fileManager->closeFile(stream);
return false;
}
stream->skip(4);
uint32 headerLen = stream->readUint32BE();
uint32 headerType = stream->readUint32BE();
if (headerType != MKTAG('I', 'H', 'D', 'R') || headerLen != 13) {
_fileManager->closeFile(stream);
return false;
}
width = stream->readSint32BE();
height = stream->readSint32BE();
_fileManager->closeFile(stream);
return true;
}
bool BaseImage::getImageInfoJPG(const Common::String &filename, int32 &width, int32 &height) {
Common::SeekableReadStream *stream = _fileManager->openFile(filename);
if (!stream) {
return false;
}
uint16 fileType = stream->readSint16BE();
if (fileType != 0xFFD8) {
_fileManager->closeFile(stream);
return false;
}
while (1) {
byte markerPrefix = stream->readByte();
if (stream->eos() || stream->err()) {
break;
}
if (markerPrefix != 0xff) {
continue;
}
byte marker = stream->readByte();
while (marker == 0xff) {
marker = stream->readByte();
if (stream->eos() || stream->err()) {
_fileManager->closeFile(stream);
return false;
}
}
if (marker == 0xd9 || marker == 0xda) {
break;
}
uint16 segLength = stream->readUint16BE();
if (segLength < 2) {
break;
}
if ((marker >= 0xc0 && marker <= 0xc3) ||
(marker >= 0xc9 && marker <= 0xcb)) {
stream->skip(1);
height = stream->readUint16BE();
width = stream->readUint16BE();
_fileManager->closeFile(stream);
return true;
} else {
stream->skip(segLength - 2);
if (stream->eos() || stream->err()) {
break;
}
}
}
_fileManager->closeFile(stream);
return false;
}
bool BaseImage::loadFile(const Common::String &filename) {
_filename = filename;
_filename.toLowercase();
if (filename.hasPrefix("savegame:") || _filename.hasSuffix(".bmp")) {
_decoder = new Image::BitmapDecoder();
} else if (_filename.hasSuffix(".png")) {
if (BaseEngine::instance().getGameId() == "satanandsons" &&
_filename.hasSuffix("\\plein\\kaars.1.png")) {
debug(2, "BaseImage::loadFile : Buggy PNG bitmap %s, skipping...", filename.c_str());
return false;
}
_decoder = new Image::PNGDecoder();
} else if (_filename.hasSuffix(".tga")) {
_decoder = new Image::TGADecoder();
} else if (_filename.hasSuffix(".jpg")) {
Image::JPEGDecoder *jpeg = new Image::JPEGDecoder();
jpeg->setOutputPixelFormat(BaseEngine::getRenderer()->getPixelFormat());
_decoder = jpeg;
} else {
warning("BaseImage::loadFile : Unsupported fileformat %s", filename.c_str());
}
_filename = filename;
Common::SeekableReadStream *file = _fileManager->openFile(filename);
if (!file) {
return false;
}
_decoder->loadStream(*file);
_surface = _decoder->getSurface();
_palette = _decoder->getPalette().data();
_paletteCount = _decoder->getPalette().size();
_fileManager->closeFile(file);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseImage::saveBMPFile(const char *filename) const {
Common::WriteStream *stream = openSfmFileForWrite(filename);
if (stream) {
bool ret = writeBMPToStream(stream);
delete stream;
return ret;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool BaseImage::writeBMPToStream(Common::WriteStream *stream) const {
if (!stream || !_surface) {
return false;
}
return Image::writeBMP(*stream, *_surface, _palette);
}
//////////////////////////////////////////////////////////////////////////
void BaseImage::copyFrom(const Graphics::Surface *surface, int newWidth, int newHeight, byte flip) {
if (newWidth == 0)
newWidth = surface->w;
if (newHeight == 0)
newHeight = surface->h;
Graphics::Surface *temp;
if (newWidth == surface->w && newHeight == surface->h && flip == 0) {
temp = new Graphics::Surface();
temp->copyFrom(*surface);
} else {
temp = surface->scale((uint16)newWidth, (uint16)newHeight, true, flip);
}
if (_deletableSurface) {
_deletableSurface->free();
delete _deletableSurface;
_deletableSurface = nullptr;
}
_surface = _deletableSurface = temp;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,82 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_IMAGE_H
#define WINTERMUTE_BASE_IMAGE_H
#include "graphics/surface.h"
#include "graphics/pixelformat.h"
#include "common/endian.h"
#include "common/str.h"
#include "common/stream.h"
namespace Image {
class ImageDecoder;
}
namespace Wintermute {
class BaseSurface;
class BaseFileManager;
class BaseImage {
public:
BaseImage();
~BaseImage();
bool getImageInfo(const Common::String &filename, int32 &width, int32 &height);
bool loadFile(const Common::String &filename);
const Graphics::Surface *getSurface() const {
return _surface;
};
const byte *getPalette() const {
return _palette;
}
uint16 getPaletteCount() const {
return _paletteCount;
}
bool writeBMPToStream(Common::WriteStream *stream) const;
bool saveBMPFile(const char *filename) const;
void copyFrom(const Graphics::Surface *surface, int newWidth = 0, int newHeight = 0, byte flip = 0);
private:
Common::String _filename;
Image::ImageDecoder *_decoder;
const Graphics::Surface *_surface;
Graphics::Surface *_deletableSurface;
const byte *_palette;
uint16 _paletteCount;
BaseFileManager *_fileManager;
bool getImageInfoBMP(const Common::String &filename, int32 &width, int32 &height);
bool getImageInfoTGA(const Common::String &filename, int32 &width, int32 &height);
bool getImageInfoPNG(const Common::String &filename, int32 &width, int32 &height);
bool getImageInfoJPG(const Common::String &filename, int32 &width, int32 &height);
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,243 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_active_rect.h"
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/base/base_sub_frame.h"
#include "engines/wintermute/base/base_region.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/platform_osystem.h"
#include "engines/wintermute/base/base_persistence_manager.h"
#include "engines/wintermute/dcgf.h"
#ifdef ENABLE_WME3D
#include "engines/wintermute/base/gfx/xmodel.h"
#endif
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
BaseRenderer::BaseRenderer(BaseGame *inGame) : BaseClass(inGame) {
_window = 0;
_clipperWindow = 0;
_active = false;
_ready = false;
_windowed = true;
_forceAlphaColor = 0x00;
_width = _height = _bPP = 0;
BasePlatform::setRectEmpty(&_monitorRect);
_realWidth = _realHeight = 0;
_drawOffsetX = _drawOffsetY = 0;
}
//////////////////////////////////////////////////////////////////////
BaseRenderer::~BaseRenderer() {
deleteRectList();
unclipCursor();
}
//////////////////////////////////////////////////////////////////////
void BaseRenderer::initLoop() {
deleteRectList();
}
//////////////////////////////////////////////////////////////////////
BaseObject *BaseRenderer::getObjectAt(int x, int y) {
Common::Point32 point;
point.x = x;
point.y = y;
for (int32 i = _rectList.getSize() - 1; i >= 0; i--) {
if (BasePlatform::ptInRect(&_rectList[i]->_rect, point)) {
if (_rectList[i]->_precise) {
// frame
if (_rectList[i]->_frame) {
int xx = (int)((_rectList[i]->_frame->_rect.left + x - _rectList[i]->_rect.left + _rectList[i]->_offsetX) / (float)((float)_rectList[i]->_zoomX / (float)100));
int yy = (int)((_rectList[i]->_frame->_rect.top + y - _rectList[i]->_rect.top + _rectList[i]->_offsetY) / (float)((float)_rectList[i]->_zoomY / (float)100));
if (_rectList[i]->_frame->_mirrorX) {
int width = _rectList[i]->_frame->_rect.right - _rectList[i]->_frame->_rect.left;
xx = width - xx;
}
if (_rectList[i]->_frame->_mirrorY) {
int height = _rectList[i]->_frame->_rect.bottom - _rectList[i]->_frame->_rect.top;
yy = height - yy;
}
if (!_rectList[i]->_frame->_surface->isTransparentAt(xx, yy)) {
return _rectList[i]->_owner;
}
}
#ifdef ENABLE_WME3D
else if (_rectList[i]->_xmodel) {
if (!_rectList[i]->_xmodel->isTransparentAt(x, y)) {
return _rectList[i]->_owner;
}
}
#endif
// region
else if (_rectList[i]->_region) {
if (_rectList[i]->_region->pointInRegion(x + _rectList[i]->_offsetX, y + _rectList[i]->_offsetY)) {
return _rectList[i]->_owner;
}
}
} else {
return _rectList[i]->_owner;
}
}
}
return (BaseObject *)nullptr;
}
//////////////////////////////////////////////////////////////////////////
void BaseRenderer::deleteRectList() {
for (int32 i = 0; i < _rectList.getSize(); i++) {
delete _rectList[i];
}
_rectList.removeAll();
}
//////////////////////////////////////////////////////////////////////
bool BaseRenderer::initRenderer(int width, int height, bool windowed) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////
void BaseRenderer::onWindowChange() {
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::windowedBlt() {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setup2D(bool force) {
return STATUS_FAILED;
}
#ifdef ENABLE_WME3D
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setup3D(Camera3D *camera, bool force) {
return STATUS_FAILED;
}
#endif
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::drawLine(int x1, int y1, int x2, int y2, uint32 color) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::drawRect(int x1, int y1, int x2, int y2, uint32 color, int width) {
for (int i = 0; i < width; i++) {
drawLine(x1 + i, y1 + i, x2 - i, y1 + i, color); // up
drawLine(x1 + i, y2 - i, x2 - i + 1, y2 - i, color); // down
drawLine(x1 + i, y1 + i, x1 + i, y2 - i, color); // left
drawLine(x2 - i, y1 + i, x2 - i, y2 - i + 1, color); // right
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::fillRect(int x, int y, int w, int h, uint32 color) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setViewport(int left, int top, int right, int bottom) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setScreenViewport() {
return setViewport(_drawOffsetX, _drawOffsetY, _width + _drawOffsetX, _height + _drawOffsetY);
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::setViewport(Common::Rect32 *rect) {
return setViewport(rect->left + _drawOffsetX,
rect->top + _drawOffsetY,
rect->right + _drawOffsetX,
rect->bottom + _drawOffsetY);
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::clipCursor() {
// TODO: Reimplement this. (Currently aspect-indpendence isn't quite finished)
/*
if (!_windowed) {
Common::Rect32 rc;
GetWindowRect(_window, &rc);
// if "maintain aspect ratio" is in effect, lock mouse to visible area
rc.left = _drawOffsetX;
rc.top = _drawOffsetY;
rc.right = rc.left + _width;
rc.bottom = rc.top + _height;
::ClipCursor(&rc);
}
*/
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::unclipCursor() {
/*
if (!_windowed) ::ClipCursor(nullptr);
*/
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderer::pointInViewport(Common::Point32 *p) {
if (p->x < _drawOffsetX) {
return false;
}
if (p->y < _drawOffsetY) {
return false;
}
if (p->x > _drawOffsetX + _width) {
return false;
}
if (p->y > _drawOffsetY + _height) {
return false;
}
return true;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,206 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_RENDERER_H
#define WINTERMUTE_BASE_RENDERER_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/coll_templ.h"
#include "common/rect.h"
#include "common/array.h"
namespace Wintermute {
class BaseImage;
class BaseActiveRect;
class BaseObject;
class BaseSurface;
class BasePersistenceManager;
#ifdef ENABLE_WME3D
class Camera3D;
#endif
/**
* @class BaseRenderer a common interface for the rendering portion of WME
* this interface is mainly intended to wrap away any differencies between
* software-rendering/hardware-rendering.
*/
class BaseRenderer : public BaseClass {
public:
int _realWidth;
int _realHeight;
int _drawOffsetX;
int _drawOffsetY;
void dumpData(const char *filename) {};
/**
* Take a screenshot of the current screenstate
*
* @return a BaseImage containing the current screen-buffer.
*/
virtual BaseImage *takeScreenshot(int newWidth = 0, int newHeight = 0) = 0;
virtual bool setViewport(int left, int top, int right, int bottom);
virtual bool setViewport(Common::Rect32 *rect);
virtual bool setScreenViewport();
virtual void setWindowed(bool windowed) = 0;
virtual Graphics::PixelFormat getPixelFormat() const = 0;
/**
* Fade the screen to black
*
* @param alpha amount to fade by (alpha value of black)
*/
virtual bool fade(uint16 alpha) = 0;
/**
* Fade a portion of the screen to a specific color
*
* @param r the red component to fade too.
* @param g the green component to fade too.
* @param b the blue component to fade too.
* @param a the alpha component to fade too.
* @param rect the portion of the screen to fade (if nullptr, the entire screen will be faded).
*/
virtual bool fadeToColor(byte r, byte g, byte b, byte a) = 0;
virtual bool drawLine(int x1, int y1, int x2, int y2, uint32 color);
virtual bool drawRect(int x1, int y1, int x2, int y2, uint32 color, int width = 1);
virtual bool fillRect(int x, int y, int w, int h, uint32 color); // Unused outside indicator-display
BaseRenderer(BaseGame *inGame = nullptr);
~BaseRenderer() override;
virtual bool setProjection() {
return STATUS_OK;
};
virtual bool windowedBlt();
/**
* Clear the screen
*/
virtual bool clear() = 0;
virtual void onWindowChange();
virtual bool initRenderer(int width, int height, bool windowed);
/**
* Flip the backbuffer onto the screen-buffer
* The screen will NOT be updated before calling this function.
*
* @return true if successful, false on error.
*/
virtual bool flip() = 0;
/**
* Special flip for the indicator drawn during save/load
* essentially, just copies the region defined by the indicator rectangle.
*/
virtual bool indicatorFlip(int32 x, int32 y, int32 width, int32 height) = 0;
virtual bool forcedFlip() = 0;
virtual void initLoop();
virtual bool setup2D(bool force = false);
#ifdef ENABLE_WME3D
virtual bool setup3D(Camera3D *camera = nullptr, bool force = false);
#endif
/**
* Get the name of the current renderer
*
* @return the name of the renderer.
*/
virtual Common::String getName() const = 0;
virtual bool displayDebugInfo() {
return STATUS_FAILED;
};
virtual bool drawShaderQuad() {
return STATUS_FAILED;
}
virtual float getScaleRatioX() const {
return 1.0f;
}
virtual float getScaleRatioY() const {
return 1.0f;
}
/**
* Create a Surface fit for use with the renderer.
* As diverse implementations of BaseRenderer might have different solutions for storing surfaces
* this allows for a common interface for creating surface-handles. (Mostly useful to ease future
* implementation of hw-accelerated rendering, or readding 3D-support at some point).
*
* @return a surface that can be used with this renderer
*/
virtual BaseSurface *createSurface() = 0;
bool clipCursor();
bool unclipCursor();
BaseObject *getObjectAt(int x, int y);
void deleteRectList();
virtual bool startSpriteBatch() {
return STATUS_OK;
};
virtual bool endSpriteBatch() {
return STATUS_OK;
};
bool pointInViewport(Common::Point32 *P);
uint32 _forceAlphaColor;
uint32 _window;
uint32 _clipperWindow;
bool _active;
bool _ready;
bool isReady() const { return _ready; }
bool isWindowed() const { return _windowed; }
int32 getBPP() const { return _bPP; }
int32 getWidth() const { return _width; }
int32 getHeight() const { return _height; }
virtual void endSaveLoad() {};
bool _windowed;
Common::Rect32 _windowRect;
Common::Rect32 _viewportRect;
Common::Rect32 _screenRect;
Common::Rect32 _monitorRect;
int32 _bPP;
int32 _height;
int32 _width;
BaseArray<BaseActiveRect *> _rectList;
};
BaseRenderer *makeOSystemRenderer(BaseGame *inGame);
#ifdef ENABLE_WME3D
class BaseRenderer3D;
BaseRenderer3D *makeOpenGL3DRenderer(BaseGame *inGame);
BaseRenderer3D *makeOpenGL3DShaderRenderer(BaseGame *inGame);
BaseRenderer3D *makeTinyGL3DRenderer(BaseGame *inGame);
#endif
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,175 @@
/* 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/>.
*
*/
#include "engines/wintermute/base/gfx/base_renderer3d.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/3dutils.h"
#include "common/config-manager.h"
namespace Wintermute {
BaseRenderer3D::BaseRenderer3D(Wintermute::BaseGame *inGame) : BaseRenderer(inGame) {
_camera = nullptr;
_state = RSTATE_NONE;
_fov = (float)DX_PI / 4;
_nearClipPlane = DEFAULT_NEAR_PLANE;
_farClipPlane = DEFAULT_FAR_PLANE;
_lastTexture = nullptr;
_ambientLightColor = 0x00000000;
_ambientLightOverride = false;
DXMatrixIdentity(&_worldMatrix);
DXMatrixIdentity(&_viewMatrix);
DXMatrixIdentity(&_projectionMatrix);
}
BaseRenderer3D::~BaseRenderer3D() {
_camera = nullptr; // ref only
}
void BaseRenderer3D::initLoop() {
BaseRenderer::initLoop();
setup2D();
}
bool BaseRenderer3D::drawSprite(BaseSurface *texture, const Common::Rect32 &rect,
float zoomX, float zoomY, const DXVector2 &pos,
uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode,
bool mirrorX, bool mirrorY) {
DXVector2 scale(zoomX / 100.0f, zoomY / 100.0f);
return drawSpriteEx(texture, rect, pos, DXVector2(0.0f, 0.0f), scale, 0.0f, color, alphaDisable, blendMode, mirrorX, mirrorY);
}
bool BaseRenderer3D::getProjectionParams(float *resWidth, float *resHeight, float *layerWidth, float *layerHeight,
float *modWidth, float *modHeight, bool *customViewport) {
*resWidth = _width;
*resHeight = _height;
if (_game->_editorResolutionWidth > 0)
*resWidth = _game->_editorResolutionWidth;
if (_game->_editorResolutionHeight > 0)
*resHeight = _game->_editorResolutionHeight;
int lWidth, lHeight;
Common::Rect32 sceneViewport;
_game->getLayerSize(&lWidth, &lHeight, &sceneViewport, customViewport);
*layerWidth = (float)lWidth;
*layerHeight = (float)lHeight;
*modWidth = 0.0f;
*modHeight = 0.0f;
if (*layerWidth > *resWidth)
*modWidth = (*layerWidth - *resWidth) / 2.0f;
if (*layerHeight > *resHeight)
*modHeight = (*layerHeight - *resHeight) / 2.0f;
// new in 1.7.2.1
// if layer height is smaller than resolution, we assume that we don't want to scroll
// and that the camera overviews the entire resolution
if (*layerHeight < *resHeight) {
*modHeight -= (*resHeight - *layerHeight) / 2;
*layerHeight = *resHeight;
}
return true;
}
bool BaseRenderer3D::fade(uint16 alpha) {
return fadeToColor(0, 0, 0, (byte)(255 - alpha));
}
bool BaseRenderer3D::setAmbientLightColor(uint32 color) {
_ambientLightColor = color;
_ambientLightOverride = true;
setAmbientLightRenderState();
return true;
}
bool BaseRenderer3D::setDefaultAmbientLightColor() {
_ambientLightColor = 0x00000000;
_ambientLightOverride = false;
setAmbientLightRenderState();
return true;
}
bool BaseRenderer3D::setup3DCustom(DXMatrix &viewMat, DXMatrix &projMat) {
setup3D();
_state = RSTATE_3D;
if (viewMat)
setViewTransform(viewMat);
if (projMat)
setProjectionTransform(projMat);
return true;
}
DXViewport BaseRenderer3D::getViewPort() {
return _viewport;
}
Graphics::PixelFormat BaseRenderer3D::getPixelFormat() const {
return Graphics::PixelFormat::createFormatRGBA32();
}
bool BaseRenderer3D::flip() {
_lastTexture = nullptr;
g_system->updateScreen();
return true;
}
bool BaseRenderer3D::indicatorFlip(int32 x, int32 y, int32 width, int32 height) {
flip();
return true;
}
bool BaseRenderer3D::forcedFlip() {
flip();
return true;
}
bool BaseRenderer3D::windowedBlt() {
flip();
return true;
}
void BaseRenderer3D::onWindowChange() {
_windowed = !g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
}
void BaseRenderer3D::setWindowed(bool windowed) {
ConfMan.setBool("fullscreen", !windowed);
g_system->beginGFXTransaction();
g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !windowed);
g_system->endGFXTransaction();
}
void BaseRenderer3D::endSaveLoad() {
BaseRenderer::endSaveLoad();
}
} // namespace Wintermute

View File

@@ -0,0 +1,177 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_BASE_RENDERER_3D_H
#define WINTERMUTE_BASE_RENDERER_3D_H
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/dctypes.h"
#include "graphics/transform_struct.h"
#include "graphics/surface.h"
#if defined(USE_OPENGL_SHADERS)
#include "graphics/opengl/system_headers.h"
#include "engines/wintermute/base/gfx/xmath.h"
#endif
namespace Wintermute {
class AdBlock;
class AdGeneric;
class AdWalkplane;
class BaseSurfaceOpenGL3D;
class Light3D;
class Mesh3DS;
class XMesh;
class ShadowVolume;
#define DEFAULT_NEAR_PLANE 90.0f
#define DEFAULT_FAR_PLANE 10000.0f
enum PostFilter {
kPostFilterOff,
kPostFilterBlackAndWhite,
kPostFilterSepia
};
class BaseRenderer3D : public BaseRenderer {
public:
BaseRenderer3D(BaseGame *inGame = nullptr);
~BaseRenderer3D() override;
bool getProjectionParams(float *resWidth, float *resHeight, float *layerWidth, float *layerHeight,
float *modWidth, float *modHeight, bool *customViewport);
virtual int getMaxActiveLights() = 0;
bool setAmbientLightColor(uint32 color);
bool setDefaultAmbientLightColor();
uint32 _ambientLightColor;
bool _ambientLightOverride;
void dumpData(const char *filename) {};
bool setup3DCustom(DXMatrix &viewMat, DXMatrix &projMat);
virtual bool enableShadows() = 0;
virtual bool disableShadows() = 0;
virtual bool shadowVolumeSupported() = 0;
virtual bool invalidateTexture(BaseSurface *texture) = 0;
virtual void setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode, bool forceChange = false) = 0;
virtual bool invalidateDeviceObjects() = 0;
virtual bool restoreDeviceObjects() = 0;
BaseSurface *_lastTexture;
bool fade(uint16 alpha) override;
bool drawSprite(BaseSurface *texture, const Common::Rect32 &rect, float zoomX, float zoomY, const DXVector2 &pos,
uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY);
virtual bool drawSpriteEx(BaseSurface *texture, const Common::Rect32 &rect, const DXVector2 &pos, const DXVector2 &rot, const DXVector2 &scale,
float angle, uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) = 0;
Camera3D *_camera;
virtual bool resetDevice() = 0;
void initLoop() override;
bool windowedBlt() override;
virtual bool startSpriteBatch() override = 0;
virtual bool endSpriteBatch() override = 0;
virtual bool commitSpriteBatch() = 0;
// ScummVM specific methods -->
virtual void lightEnable(int index, bool enable) = 0;
virtual void setLightParameters(int index, const DXVector3 &position, const DXVector3 &direction,
const DXVector4 &diffuse, bool spotlight) = 0;
virtual void enableCulling() = 0;
virtual void disableCulling() = 0;
DXViewport getViewPort();
void setWindowed(bool windowed) override;
void onWindowChange() override;
Graphics::PixelFormat getPixelFormat() const override;
virtual bool setWorldTransform(const DXMatrix &transform) = 0;
virtual bool setViewTransform(const DXMatrix &transform) = 0;
virtual bool setProjectionTransform(const DXMatrix &transform) = 0;
void getWorldTransform(DXMatrix *transform) {
*transform = _worldMatrix;
}
void getViewTransform(DXMatrix *transform) {
*transform = _viewMatrix;
}
void getProjectionTransform(DXMatrix *transform) {
*transform = _projectionMatrix;
}
virtual Mesh3DS *createMesh3DS() = 0;
virtual XMesh *createXMesh() = 0;
virtual ShadowVolume *createShadowVolume() = 0;
virtual void renderSceneGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks,
const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) = 0;
virtual void renderShadowGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks, const BaseArray<AdGeneric *> &generics, Camera3D *camera) = 0;
virtual void displaySimpleShadow(BaseObject *object) = 0;
virtual void postfilter() = 0;
virtual void setPostfilter(PostFilter postFilter) = 0;
bool flip() override;
bool indicatorFlip(int32 x, int32 y, int32 width, int32 height) override;
bool forcedFlip() override;
virtual bool setViewport3D(DXViewport *viewport) = 0;
void invalidateLastTexture() {
_lastTexture = nullptr;
}
void endSaveLoad() override;
// ScummVM specific methods <--
protected:
DXMatrix _worldMatrix;
DXMatrix _viewMatrix;
DXMatrix _projectionMatrix;
DXViewport _viewport{};
float _fov;
float _nearClipPlane;
float _farClipPlane;
TRendererState _state;
PostFilter _postFilterMode;
bool _flipInProgress;
virtual void setAmbientLightRenderState() = 0;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,122 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/wintypes.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/dcgf.h"
#include "common/str.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
BaseSurface::BaseSurface(BaseGame *inGame) : BaseClass(inGame) {
_referenceCount = 0;
_width = _height = 0;
_filename = nullptr;
_ckDefault = true;
_ckRed = _ckGreen = _ckBlue = 0;
_lifeTime = 0;
_keepLoaded = false;
_lastUsedTime = 0;
_valid = false;
}
//////////////////////////////////////////////////////////////////////
BaseSurface::~BaseSurface() {
if (_filename) {
SAFE_DELETE_ARRAY(_filename);
}
}
//////////////////////////////////////////////////////////////////////
bool BaseSurface::restore() {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////
bool BaseSurface::isTransparentAt(int x, int y) {
if (startPixelOp()) {
bool retval = isTransparentAtLite(x, y);
endPixelOp();
return retval;
} else {
return false;
}
}
//////////////////////////////////////////////////////////////////////
bool BaseSurface::displayHalfTrans(int x, int y, Common::Rect32 rect) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurface::create(int width, int height) {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurface::invalidate() {
return STATUS_FAILED;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurface::prepareToDraw() {
_lastUsedTime = _game->_liveTimer;
if (!_valid) {
//_game->LOG(0, "Reviving: %s", _filename);
return create(_filename, _ckDefault, _ckRed, _ckGreen, _ckBlue, _lifeTime, _keepLoaded);
} else {
return STATUS_OK;
}
}
//////////////////////////////////////////////////////////////////////////
void BaseSurface::setFilename(const char *filename) {
SAFE_DELETE_ARRAY(_filename);
if (!filename) {
return;
}
size_t nameSize = strlen(filename) + 1;
_filename = new char[nameSize];
Common::strcpy_s(_filename, nameSize, filename);
}
//////////////////////////////////////////////////////////////////////////
void BaseSurface::setSize(int width, int height) {
_width = width;
_height = height;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,98 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SURFACE_H
#define WINTERMUTE_BASE_SURFACE_H
#include "engines/wintermute/base/base.h"
#include "graphics/surface.h"
#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseSurface : public BaseClass {
public:
virtual bool invalidate();
virtual bool prepareToDraw();
bool _ckDefault;
byte _ckRed;
byte _ckGreen;
byte _ckBlue;
uint32 _lastUsedTime;
bool _valid;
int32 _lifeTime;
bool _keepLoaded;
BaseSurface(BaseGame *inGame);
~BaseSurface() override;
virtual bool displayHalfTrans(int x, int y, Common::Rect32 rect);
virtual bool isTransparentAt(int x, int y);
virtual bool displayTransRotate(int x, int y, float rotate, int32 hotspotX, int32 hotspotY, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTransZoom(int x, int y, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTrans(int x, int y, Common::Rect32 rect, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) = 0;
virtual bool display(int x, int y, Common::Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) = 0;
virtual bool displayTiled(int x, int y, Common::Rect32 rect, int numTimesX, int numTimesY) = 0;
virtual bool restore();
virtual bool create(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) = 0;
virtual bool create(int width, int height);
virtual bool setAlphaImage(const char *filename) {
return STATUS_FAILED;
}
virtual bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) {
return STATUS_FAILED;
}
virtual bool startPixelOp() = 0;
virtual bool endPixelOp() = 0;
virtual bool putPixel(int x, int y, byte r, byte g, byte b, byte a) = 0;
virtual bool getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a = nullptr) const = 0;
virtual bool isTransparentAtLite(int x, int y) const = 0;
void setFilename(const char *filename);
void setSize(int width, int height);
int _referenceCount;
char *_filename;
virtual int getWidth() {
return _width;
}
virtual int getHeight() {
return _height;
}
//void SetWidth(int Width) { _width = Width; }
//void SetHeight(int Height){ _height = Height; }
protected:
int32 _height;
int32 _width;
};
} // End of namespace Wintermute
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,176 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_BASE_RENDER_OPENGL3D_H
#define WINTERMUTE_BASE_RENDER_OPENGL3D_H
#include "engines/wintermute/base/gfx/base_renderer3d.h"
#include "engines/wintermute/dctypes.h"
#include "graphics/transform_struct.h"
#if defined(USE_OPENGL_GAME)
#include "graphics/opengl/system_headers.h"
namespace Wintermute {
class BaseSurfaceOpenGL3D;
class BaseRenderOpenGL3D : public BaseRenderer3D {
friend class BaseSurfaceOpenGL3D;
friend class Mesh3DSOpenGL;
friend class XMeshOpenGL;
friend class ShadowVolumeOpenGL;
struct SpriteVertex {
float x;
float y;
float z;
float u;
float v;
float r;
float g;
float b;
float a;
};
struct RectangleVertex {
float x;
float y;
float z;
};
struct SimpleShadowVertex {
float nx;
float ny;
float nz;
float x;
float y;
float z;
float u;
float v;
};
public:
BaseRenderOpenGL3D(BaseGame *inGame = nullptr);
~BaseRenderOpenGL3D() override;
bool invalidateTexture(BaseSurface *texture) override;
bool invalidateDeviceObjects() override;
bool restoreDeviceObjects() override;
bool resetDevice() override;
void setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode, bool forceChange = false) override;
void setAmbientLightRenderState() override;
int getMaxActiveLights() override;
void lightEnable(int index, bool enable) override;
void setLightParameters(int index, const DXVector3 &position, const DXVector3 &direction, const DXVector4 &diffuse, bool spotlight) override;
void enableCulling() override;
void disableCulling() override;
bool enableShadows() override;
bool disableShadows() override;
bool shadowVolumeSupported() override;
BaseImage *takeScreenshot(int newWidth = 0, int newHeight = 0) override;
bool fadeToColor(byte r, byte g, byte b, byte a) override;
bool flip() override;
bool clear() override;
bool setViewport(int left, int top, int right, int bottom) override;
bool drawLine(int x1, int y1, int x2, int y2, uint32 color) override;
bool fillRect(int x, int y, int w, int h, uint32 color) override;
DXMatrix *buildMatrix(DXMatrix* out, const DXVector2 *centre, const DXVector2 *scaling, float angle);
void transformVertices(struct SpriteVertex *vertices, const DXVector2 *centre, const DXVector2 *scaling, float angle);
bool setProjection() override;
bool setProjection2D();
bool setWorldTransform(const DXMatrix &transform) override;
bool setViewTransform(const DXMatrix &transform) override;
bool setProjectionTransform(const DXMatrix &transform) override;
bool initRenderer(int width, int height, bool windowed) override;
bool setup2D(bool force = false) override;
bool setup3D(Camera3D *camera, bool force = false) override;
Common::String getName() const override {
return "OpenGL 3D renderer";
};
bool displayDebugInfo() override {
return STATUS_FAILED;
};
bool drawShaderQuad() override {
return STATUS_FAILED;
}
float getScaleRatioX() const override {
return 1.0f;
}
float getScaleRatioY() const override {
return 1.0f;
}
BaseSurface *createSurface() override;
bool startSpriteBatch() override;
bool endSpriteBatch() override;
bool commitSpriteBatch() override;
bool drawSpriteEx(BaseSurface *texture, const Common::Rect32 &rect, const DXVector2 &pos, const DXVector2 &rot, const DXVector2 &scale,
float angle, uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) override;
void renderSceneGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks,
const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) override;
void renderShadowGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks, const BaseArray<AdGeneric *> &generics, Camera3D *camera) override;
Mesh3DS *createMesh3DS() override;
XMesh *createXMesh() override;
ShadowVolume *createShadowVolume() override;
bool setViewport3D(DXViewport *viewport) override;
void postfilter() override;
void setPostfilter(PostFilter postFilter) override { _postFilterMode = postFilter; };
private:
bool setupLines();
void displaySimpleShadow(BaseObject *object) override;
Graphics::TSpriteBlendMode _blendMode;
SimpleShadowVertex _simpleShadow[4];
Common::Array<DXVector4> _lightPositions;
Common::Array<DXVector3> _lightDirections;
GLuint _postfilterTexture;
};
} // wintermute namespace
#endif // defined(USE_OPENGL_GAME)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,200 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_BASE_RENDER_OPENGL3D_H
#define WINTERMUTE_BASE_RENDER_OPENGL3D_H
#include "engines/wintermute/base/gfx/base_renderer3d.h"
#include "engines/wintermute/dctypes.h"
#include "graphics/opengl/system_headers.h"
#include "graphics/transform_struct.h"
#if defined(USE_OPENGL_SHADERS)
#include "graphics/opengl/shader.h"
namespace Wintermute {
class BaseSurfaceOpenGL3D;
class BaseRenderOpenGL3DShader : public BaseRenderer3D {
friend class BaseSurfaceOpenGL3DShader;
friend class Mesh3DSOpenGLShader;
friend class XMeshOpenGLShader;
friend class ShadowVolumeOpenGLShader;
struct SpriteVertex {
float x;
float y;
float z;
float u;
float v;
float r;
float g;
float b;
float a;
};
struct RectangleVertex {
float x;
float y;
float z;
};
struct SimpleShadowVertex {
float x;
float y;
float z;
float nx;
float ny;
float nz;
float u;
float v;
};
public:
BaseRenderOpenGL3DShader(BaseGame *inGame = nullptr);
~BaseRenderOpenGL3DShader() override;
bool invalidateTexture(BaseSurface *texture) override;
bool invalidateDeviceObjects() override;
bool restoreDeviceObjects() override;
bool resetDevice() override;
void setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode, bool forceChange = false) override;
void setAmbientLightRenderState() override;
int getMaxActiveLights() override;
void lightEnable(int index, bool enable) override;
void setLightParameters(int index, const DXVector3 &position, const DXVector3 &direction, const DXVector4 &diffuse, bool spotlight) override;
void enableCulling() override;
void disableCulling() override;
bool enableShadows() override;
bool disableShadows() override;
bool shadowVolumeSupported() override;
BaseImage *takeScreenshot(int newWidth = 0, int newHeight = 0) override;
bool fadeToColor(byte r, byte g, byte b, byte a) override;
bool flip() override;
bool clear() override;
bool setViewport(int left, int top, int right, int bottom) override;
bool drawLine(int x1, int y1, int x2, int y2, uint32 color) override;
bool fillRect(int x, int y, int w, int h, uint32 color) override;
DXMatrix *buildMatrix(DXMatrix* out, const DXVector2 *centre, const DXVector2 *scaling, float angle);
void transformVertices(struct SpriteVertex *vertices, const DXVector2 *centre, const DXVector2 *scaling, float angle);
bool setProjection() override;
bool setProjection2D(OpenGL::Shader *);
bool setWorldTransform(const DXMatrix &transform) override;
bool setViewTransform(const DXMatrix &transform) override;
bool setProjectionTransform(const DXMatrix &transform) override;
bool initRenderer(int width, int height, bool windowed) override;
bool setup2D(bool force = false) override;
bool setup3D(Camera3D *camera, bool force = false) override;
Common::String getName() const override {
return "OpenGL 3D renderer";
};
bool displayDebugInfo() override {
return STATUS_FAILED;
};
bool drawShaderQuad() override {
return STATUS_FAILED;
}
float getScaleRatioX() const override {
return 1.0f;
}
float getScaleRatioY() const override {
return 1.0f;
}
BaseSurface *createSurface() override;
bool startSpriteBatch() override;
bool endSpriteBatch() override;
bool commitSpriteBatch() override;
bool drawSpriteEx(BaseSurface *texture, const Common::Rect32 &rect, const DXVector2 &pos, const DXVector2 &rot, const DXVector2 &scale,
float angle, uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) override;
void renderSceneGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks,
const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) override;
void renderShadowGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks, const BaseArray<AdGeneric *> &generics, Camera3D *camera) override;
Mesh3DS *createMesh3DS() override;
XMesh *createXMesh() override;
ShadowVolume *createShadowVolume() override;
bool setViewport3D(DXViewport *viewport) override;
void postfilter() override;
void setPostfilter(PostFilter postFilter) override { _postFilterMode = postFilter; };
OpenGL::Shader *_shadowMaskShader;
private:
bool setupLines();
void displaySimpleShadow(BaseObject *object) override;
SimpleShadowVertex _simpleShadow[4];
Graphics::TSpriteBlendMode _blendMode;
DXMatrix _glProjectionMatrix;
float _alphaRef;
Common::Array<DXMatrix> _transformStack;
Math::Vector4d _flatShadowColor;
GLuint _spriteVBO{};
GLuint _fadeVBO{};
GLuint _rectangleVBO{};
GLuint _simpleShadowVBO{};
GLuint _postfilterVBO{};
OpenGL::Shader *_spriteShader{};
OpenGL::Shader *_fadeShader{};
OpenGL::Shader *_xmodelShader{};
OpenGL::Shader *_geometryShader{};
OpenGL::Shader *_simpleShadowShader{};
OpenGL::Shader *_flatShadowShader{};
OpenGL::Shader *_shadowVolumeShader{};
OpenGL::Shader *_lineShader{};
OpenGL::Shader *_postfilterShader{};
GLuint _postfilterTexture;
};
} // namespace Wintermute
#endif // defined(USE_OPENGL_SHADERS)
#endif

View File

@@ -0,0 +1,469 @@
/* 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/>.
*
*/
#include "common/algorithm.h"
#include "graphics/transform_tools.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/gfx/base_image.h"
#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
#include "engines/wintermute/base/gfx/3dutils.h"
#include "engines/wintermute/base/gfx/opengl/base_surface_opengl3d.h"
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
namespace Wintermute {
BaseSurfaceOpenGL3D::BaseSurfaceOpenGL3D(BaseGame *game, BaseRenderer3D *renderer)
: BaseSurface(game), _tex(0), _renderer(renderer), _imageData(nullptr), _maskData(nullptr), _texWidth(0), _texHeight(0), _pixelOpReady(false) {
}
BaseSurfaceOpenGL3D::~BaseSurfaceOpenGL3D() {
_renderer->invalidateTexture(this);
if (_tex) {
glDeleteTextures(1, &_tex);
_tex = 0;
}
freeImageData();
if (_maskData) {
_maskData->free();
delete _maskData;
_maskData = nullptr;
}
}
bool BaseSurfaceOpenGL3D::invalidate() {
_renderer->invalidateTexture(this);
if (_tex) {
glDeleteTextures(1, &_tex);
_tex = 0;
}
freeImageData();
_valid = false;
return true;
}
bool BaseSurfaceOpenGL3D::prepareToDraw() {
_lastUsedTime = _game->_liveTimer;
if (!_valid) {
if (!loadImage()) {
return false;
}
uploadTexture();
freeImageData();
}
return true;
}
bool BaseSurfaceOpenGL3D::displayTransZoom(int x, int y, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
prepareToDraw();
_renderer->drawSprite(dynamic_cast<BaseSurface *>(this), rect, zoomX, zoomY, DXVector2(x, y), alpha, false, blendMode, mirrorX, mirrorY);
return true;
}
bool BaseSurfaceOpenGL3D::displayTrans(int x, int y, Common::Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
prepareToDraw();
_renderer->drawSprite(dynamic_cast<BaseSurface *>(this), rect, 100, 100, DXVector2(x + offsetX, y + offsetY), alpha, false, blendMode, mirrorX, mirrorY);
return true;
}
bool BaseSurfaceOpenGL3D::display(int x, int y, Common::Rect32 rect, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
prepareToDraw();
_renderer->drawSprite(dynamic_cast<BaseSurface *>(this), rect, 100, 100, DXVector2(x, y), 0xFFFFFFFF, true, blendMode, mirrorX, mirrorY);
return true;
}
bool BaseSurfaceOpenGL3D::displayTransRotate(int x, int y, float rotate, int32 hotspotX, int32 hotspotY, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
prepareToDraw();
x -= hotspotX;
y -= hotspotY;
DXVector2 position(x, y);
DXVector2 rotation;
rotation._x = x + hotspotX * (zoomX / 100.0f);
rotation._y = y + hotspotY * (zoomY / 100.0f);
DXVector2 scale(zoomX / 100.0f, zoomY / 100.0f);
float angle = degToRad(rotate);
_renderer->drawSpriteEx(dynamic_cast<BaseSurface *>(this), rect, position, rotation, scale, angle, alpha, false, blendMode, mirrorX, mirrorY);
return true;
}
bool BaseSurfaceOpenGL3D::displayTiled(int x, int y, Common::Rect32 rect, int numTimesX, int numTimesY) {
prepareToDraw();
DXVector2 scale(numTimesX, numTimesY);
_renderer->drawSpriteEx(dynamic_cast<BaseSurface *>(this), rect, DXVector2(x, y), DXVector2(0, 0), scale, 0, 0xFFFFFFFF, false, Graphics::BLEND_NORMAL, false, false);
return true;
}
bool BaseSurfaceOpenGL3D::create(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime, bool keepLoaded) {
if (defaultCK) {
ckRed = 255;
ckGreen = 0;
ckBlue = 255;
}
Common::String surfacefilename = filename;
BaseImage img = BaseImage();
if (!img.getImageInfo(surfacefilename, _width, _height)) {
return false;
}
if (lifeTime != -1 && _lifeTime == 0) {
_valid = false;
}
_ckDefault = defaultCK;
_ckRed = ckRed;
_ckGreen = ckGreen;
_ckBlue = ckBlue;
if (!_filename || scumm_stricmp(_filename, filename) != 0) {
setFilename(filename);
}
if (_lifeTime == 0 || lifeTime == -1 || lifeTime > _lifeTime) {
_lifeTime = lifeTime;
}
_keepLoaded = keepLoaded;
if (_keepLoaded) {
_lifeTime = -1;
}
return true;
}
bool BaseSurfaceOpenGL3D::loadImage() {
if (!_filename || !_filename[0]) {
return false;
}
Common::String filename = _filename;
BaseImage img = BaseImage();
if (!img.loadFile(filename)) {
return false;
}
if (img.getSurface()->format.bytesPerPixel == 1 && img.getPalette() == nullptr) {
return false;
}
_width = img.getSurface()->w;
_height = img.getSurface()->h;
bool needsColorKey = false;
bool replaceAlpha = true;
freeImageData();
_imageData = img.getSurface()->convertTo(Graphics::PixelFormat::createFormatRGBA32(), img.getPalette(), img.getPaletteCount());
if (filename.matchString("savegame:*g", true)) {
uint8 r, g, b, a;
for (int x = 0; x < _imageData->w; x++) {
for (int y = 0; y < _imageData->h; y++) {
_imageData->format.colorToARGB(_imageData->getPixel(x, y), a, r, g, b);
uint8 grey = (uint8)((0.2126f * r + 0.7152f * g + 0.0722f * b) + 0.5f);
_imageData->setPixel(x, y, _imageData->format.ARGBToColor(a, grey, grey, grey));
}
}
}
if (filename.hasSuffix(".bmp")) {
// Ignores alpha channel for BMPs
needsColorKey = true;
} else if (filename.hasSuffix(".jpg")) {
// Ignores alpha channel for JPEGs
needsColorKey = true;
} else if (BaseEngine::instance().getTargetExecutable() < WME_LITE) {
// WME 1.x always use colorkey, even for images with transparency
needsColorKey = true;
replaceAlpha = false;
} else if (BaseEngine::instance().isFoxTail()) {
// FoxTail does not use colorkey
needsColorKey = false;
} else if (img.getSurface()->format.aBits() == 0) {
// generic WME Lite does not use colorkey for non-BMPs with transparency
needsColorKey = true;
}
if (needsColorKey) {
// We set the pixel color to transparent black,
// like D3DX, if it matches the color key.
_imageData->applyColorKey(_ckRed, _ckGreen, _ckBlue, replaceAlpha, 0, 0, 0);
}
// Bug #6572 WME: Rosemary - Sprite flaw on going upwards
// Some Rosemary sprites have non-fully transparent pixels
// In original WME it wasn't seen because sprites were downscaled
// Let's set alpha to 0 if it is smaller then some treshold
if (BaseEngine::instance().getGameId() == "rosemary" && filename.hasPrefix("actors") && _imageData->format.bytesPerPixel == 4) {
uint32 mask = _imageData->format.ARGBToColor(255, 0, 0, 0);
uint32 treshold = _imageData->format.ARGBToColor(16, 0, 0, 0);
uint32 blank = _imageData->format.ARGBToColor(0, 0, 0, 0);
for (int x = 0; x < _imageData->w; x++) {
for (int y = 0; y < _imageData->h; y++) {
uint32 pixel = _imageData->getPixel(x, y);
if ((pixel & mask) > blank && (pixel & mask) < treshold) {
_imageData->setPixel(x, y, blank);
}
}
}
}
_valid = true;
return true;
}
bool BaseSurfaceOpenGL3D::create(int width, int height) {
_width = width;
_height = height;
_texWidth = Common::nextHigher2(width);
_texHeight = Common::nextHigher2(height);
if (!_tex) {
glGenTextures(1, &_tex);
}
glBindTexture(GL_TEXTURE_2D, _tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _texWidth, _texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
_valid = true;
return true;
}
bool BaseSurfaceOpenGL3D::putSurface(const Graphics::Surface &surface, bool hasAlpha) {
if (!_imageData) {
_imageData = new Graphics::Surface();
}
if (_imageData != &surface) {
_imageData->copyFrom(surface);
writeAlpha(_imageData, _maskData);
}
_width = surface.w;
_height = surface.h;
uploadTexture();
freeImageData();
_valid = true;
return true;
}
void BaseSurfaceOpenGL3D::freeImageData() {
if (_imageData) {
_imageData->free();
delete _imageData;
_imageData = nullptr;
}
}
bool BaseSurfaceOpenGL3D::uploadTexture() {
if (!_imageData) {
return false;
}
_texWidth = Common::nextHigher2(_width);
_texHeight = Common::nextHigher2(_height);
if (!_tex) {
glGenTextures(1, &_tex);
}
glBindTexture(GL_TEXTURE_2D, _tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _texWidth, _texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_RGBA, GL_UNSIGNED_BYTE, _imageData->getPixels());
glBindTexture(GL_TEXTURE_2D, 0);
return true;
}
bool BaseSurfaceOpenGL3D::putPixel(int x, int y, byte r, byte g, byte b, byte a) {
if (!_pixelOpReady) {
return false;
}
if (x < 0 || y < 0 || x >= _width || y >= _height) {
return false;
}
if (_imageData == nullptr) {
return false;
}
_imageData->setPixel(x, y, _imageData->format.ARGBToColor(a, r, g, b));
return true;
}
bool BaseSurfaceOpenGL3D::getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a) const {
if (!_pixelOpReady) {
return false;
}
if (x < 0 || y < 0 || x >= _width || y >= _height) {
return false;
}
if (_imageData == nullptr) {
return false;
}
uint8 alpha, red, green, blue;
_imageData->format.colorToARGB(_imageData->getPixel(x, y), alpha, red, green, blue);
*r = red;
*g = green;
*b = blue;
*a = alpha;
return true;
}
bool BaseSurfaceOpenGL3D::startPixelOp() {
if (_pixelOpReady) {
return true;
}
if (!_valid || (_valid && !_imageData)) {
if (!loadImage()) {
return false;
}
}
_lastUsedTime = _game->_liveTimer;
_pixelOpReady = true;
return true;
}
bool BaseSurfaceOpenGL3D::endPixelOp() {
_pixelOpReady = false;
uploadTexture();
return true;
}
bool BaseSurfaceOpenGL3D::isTransparentAtLite(int x, int y) const {
if (!_pixelOpReady) {
return false;
}
if (x < 0 || y < 0 || x >= _width || y >= _height) {
return false;
}
if (_imageData == nullptr) {
return false;
}
uint8 a, r, g, b;
_imageData->format.colorToARGB(_imageData->getPixel(x, y), a, r, g, b);
// Keep behavior in sync with the 2D renderer, which implements the WME Lite logic
// by comparing alpha against 128.
// This differs from the original WME1 sources, where alpha is compared against 0.
// The likely reason for this discrepancy is a difference in how bitmaps are
// converted after loading.
if (a <= 128) {
return true;
} else {
return false;
}
}
void BaseSurfaceOpenGL3D::setTexture() {
prepareToDraw();
glBindTexture(GL_TEXTURE_2D, _tex);
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOpenGL3D::setAlphaImage(const char *filename) {
BaseImage *alphaImage = new BaseImage();
if (!alphaImage->loadFile(filename)) {
delete alphaImage;
return false;
}
if (_maskData) {
_maskData->free();
delete _maskData;
_maskData = nullptr;
}
Graphics::AlphaType type = alphaImage->getSurface()->detectAlpha();
if (type != Graphics::ALPHA_OPAQUE) {
_maskData = alphaImage->getSurface()->convertTo(Graphics::PixelFormat::createFormatRGBA32());
}
delete alphaImage;
return true;
}
void BaseSurfaceOpenGL3D::writeAlpha(Graphics::Surface *surface, const Graphics::Surface *mask) {
if (mask && surface->w == mask->w && surface->h == mask->h) {
assert(mask->pitch == mask->w * 4);
assert(mask->format.bytesPerPixel == 4);
assert(surface->pitch == surface->w * 4);
assert(surface->format.bytesPerPixel == 4);
const byte *alphaData = (const byte *)mask->getPixels();
#ifdef SCUMM_LITTLE_ENDIAN
int alphaPlace = (mask->format.aShift / 8);
#else
int alphaPlace = 3 - (mask->format.aShift / 8);
#endif
alphaData += alphaPlace;
byte *imgData = (byte *)surface->getPixels();
#ifdef SCUMM_LITTLE_ENDIAN
imgData += (surface->format.aShift / 8);
#else
imgData += 3 - (surface->format.aShift / 8);
#endif
for (int i = 0; i < surface->w * surface->h; i++) {
*imgData = *alphaData;
alphaData += 4;
imgData += 4;
}
}
}
} // End of namespace Wintermute
#endif // defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)

View File

@@ -0,0 +1,100 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_BASE_SURFACE_OPENGL3D_H
#define WINTERMUTE_BASE_SURFACE_OPENGL3D_H
#include "engines/wintermute/base/gfx/base_surface.h"
#if defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
#include "graphics/opengl/system_headers.h"
namespace Wintermute {
class BaseGame;
class BaseRenderer3D;
class BaseSurfaceOpenGL3D : public BaseSurface {
public:
BaseSurfaceOpenGL3D(BaseGame *game, BaseRenderer3D *renderer);
~BaseSurfaceOpenGL3D();
bool invalidate() override;
bool prepareToDraw() override;
bool displayTransRotate(int x, int y, float rotate, int32 hotspotX, int32 hotspotY, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTransZoom(int x, int y, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTrans(int x, int y, Common::Rect32 rect, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override;
bool display(int x, int y, Common::Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTiled(int x, int y, Common::Rect32 rect, int numTimesX, int numTimesY) override;
bool create(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) override;
bool create(int width, int height) override;
bool setAlphaImage(const char *filename) override;
bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override;
bool putPixel(int x, int y, byte r, byte g, byte b, byte a) override;
bool getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a = nullptr) const override;
bool startPixelOp() override;
bool endPixelOp() override;
bool isTransparentAtLite(int x, int y) const override;
void setTexture();
int getWidth() override {
return _width;
}
int getHeight() override {
return _height;
}
GLuint getTextureName() {
return _tex;
}
uint getGLTextureWidth() const {
return _texWidth;
}
uint getGLTextureHeight() const {
return _texHeight;
}
private:
GLuint _tex;
BaseRenderer3D *_renderer;
Graphics::Surface *_imageData;
Graphics::Surface *_maskData;
uint _texWidth;
uint _texHeight;
bool _pixelOpReady;
bool loadImage();
void writeAlpha(Graphics::Surface *surface, const Graphics::Surface *mask);
bool uploadTexture();
void freeImageData();
};
} // End of namespace Wintermute
#endif // defined(USE_OPENGL_GAME) || defined(USE_OPENGL_SHADERS)
#endif

View File

@@ -0,0 +1,60 @@
/* 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/>.
*
*/
#include "engines/wintermute/wintypes.h"
#include "graphics/opengl/system_headers.h"
#if defined(USE_OPENGL_GAME)
#include "engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h"
namespace Wintermute {
Mesh3DSOpenGL::Mesh3DSOpenGL(BaseGame *inGame) : Mesh3DS(inGame) {
_vertexCount = 0;
_vertexData = nullptr;
}
Mesh3DSOpenGL::~Mesh3DSOpenGL() {
}
void Mesh3DSOpenGL::fillVertexBuffer() {
_vertexCount = _numFaces * 3;
_vertexData = (Mesh3DSVertex *)_vb.ptr();
}
void Mesh3DSOpenGL::render(bool color) {
if (_vertexCount == 0)
return;
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(Mesh3DSVertex), &_vertexData[0]._x);
glColorPointer(4, GL_FLOAT, sizeof(Mesh3DSVertex), &_vertexData[0]._r);
glDrawArrays(GL_TRIANGLES, 0, _vertexCount);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
} // namespace Wintermute
#endif // defined(USE_OPENGL_GAME)

View File

@@ -0,0 +1,47 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_MESH_OPENGL_H
#define WINTERMUTE_MESH_OPENGL_H
#include "engines/wintermute/base/gfx/3dmesh.h"
#if defined(USE_OPENGL_GAME)
namespace Wintermute {
class Mesh3DSOpenGL : public Mesh3DS {
public:
Mesh3DSOpenGL(BaseGame *inGame);
~Mesh3DSOpenGL();
void fillVertexBuffer() override;
void render(bool color) override;
private:
Mesh3DSVertex *_vertexData;
uint16 _vertexCount;
};
} // namespace Wintermute
#endif // defined(USE_OPENGL_GAME)
#endif

View File

@@ -0,0 +1,66 @@
/* 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/>.
*
*/
#include "engines/wintermute/wintypes.h"
#include "graphics/opengl/system_headers.h"
#if defined(USE_OPENGL_SHADERS)
#include "engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h"
namespace Wintermute {
Mesh3DSOpenGLShader::Mesh3DSOpenGLShader(BaseGame *inGame, OpenGL::Shader *shader) : Mesh3DS(inGame), _shader(shader) {
_vertexCount = 0;
_vertexData = nullptr;
glGenBuffers(1, &_vertexBuffer);
}
Mesh3DSOpenGLShader::~Mesh3DSOpenGLShader() {
glDeleteBuffers(1, &_vertexBuffer);
}
void Mesh3DSOpenGLShader::fillVertexBuffer() {
_vertexCount = _numFaces * 3;
_vertexData = (Mesh3DSVertex *)_vb.ptr();
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Mesh3DSVertex) * _vertexCount, _vertexData, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
void Mesh3DSOpenGLShader::render(bool color) {
if (_vertexCount == 0)
return;
_shader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, sizeof(Mesh3DSVertex), 0);
if (color)
_shader->enableVertexAttribute("color", _vertexBuffer, 4, GL_FLOAT, false, sizeof(Mesh3DSVertex), 24);
_shader->use(true);
glDrawArrays(GL_TRIANGLES, 0, _vertexCount);
}
} // namespace Wintermute
#endif // defined(USE_OPENGL_SHADERS)

View File

@@ -0,0 +1,51 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_MESH_OPENGL_H
#define WINTERMUTE_MESH_OPENGL_H
#include "engines/wintermute/base/gfx/3dmesh.h"
#if defined(USE_OPENGL_SHADERS)
#include "graphics/opengl/shader.h"
namespace Wintermute {
class Mesh3DSOpenGLShader : public Mesh3DS {
public:
Mesh3DSOpenGLShader(BaseGame *inGame, OpenGL::Shader *shader);
~Mesh3DSOpenGLShader();
void fillVertexBuffer() override;
void render(bool color) override;
private:
Mesh3DSVertex *_vertexData;
uint16 _vertexCount;
GLuint _vertexBuffer;
OpenGL::Shader *_shader;
};
} // namespace Wintermute
#endif // defined(USE_OPENGL_SHADERS)
#endif

View File

@@ -0,0 +1,264 @@
/* 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/base/gfx/xmaterial.h"
#include "engines/wintermute/base/gfx/3deffect.h"
#include "engines/wintermute/base/gfx/3deffect_params.h"
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "graphics/opengl/system_headers.h"
#if defined(USE_OPENGL_GAME)
#include "engines/wintermute/base/gfx/opengl/base_surface_opengl3d.h"
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
#include "engines/wintermute/base/gfx/opengl/meshx_opengl.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
XMeshOpenGL::XMeshOpenGL(BaseGame *inGame) : XMesh(inGame) {
}
//////////////////////////////////////////////////////////////////////////
XMeshOpenGL::~XMeshOpenGL() {
}
//////////////////////////////////////////////////////////////////////////
bool XMeshOpenGL::render(XModel *model) {
if (!_blendedMesh)
return false;
// For WME DX, mesh model is not visible, possible it's clipped.
// For OpenGL, mesh is visible, skip draw it here instead in core.
if (!_game->_renderer3D->_camera)
return false;
auto fvf = _blendedMesh->getFVF();
uint32 vertexSize = DXGetFVFVertexSize(fvf) / sizeof(float);
float *vertexData = (float *)_blendedMesh->getVertexBuffer().ptr();
if (vertexData == nullptr) {
return false;
}
uint32 offset = 0, normalOffset = 0, textureOffset = 0;
if (fvf & DXFVF_XYZ) {
offset += sizeof(DXVector3) / sizeof(float);
}
if (fvf & DXFVF_NORMAL) {
normalOffset = offset;
offset += sizeof(DXVector3) / sizeof(float);
}
if (fvf & DXFVF_DIFFUSE) {
offset += sizeof(DXColorValue) / sizeof(float);
}
if (fvf & DXFVF_TEX1) {
textureOffset = offset;
}
uint32 *indexData = (uint32 *)_blendedMesh->getIndexBuffer().ptr();
bool noAttrs = false;
auto attrsTable = _blendedMesh->getAttributeTable();
uint32 numAttrs = attrsTable->_size;
DXAttributeRange *attrs;
if (numAttrs == 0) {
noAttrs = true;
numAttrs = 1;
attrs = new DXAttributeRange[numAttrs];
} else {
attrs = attrsTable->_ptr;
}
if (noAttrs) {
attrs[0]._attribId = 0;
attrs[0]._vertexStart = attrs[0]._faceStart = 0;
attrs[0]._vertexCount = _blendedMesh->getNumVertices();
attrs[0]._faceCount = _blendedMesh->getNumFaces();
}
for (uint32 i = 0; i < numAttrs; i++) {
Material *mat = _materials[attrs[i]._attribId];
bool textureEnable = false;
if (mat->getSurface()) {
textureEnable = true;
glEnable(GL_TEXTURE_2D);
static_cast<BaseSurfaceOpenGL3D *>(mat->getSurface())->setTexture();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
} else {
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}
if (mat->getEffect()) {
renderEffect(mat);
} else {
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat->_material._diffuse._data);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat->_material._diffuse._data);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat->_material._specular._data);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat->_material._emissive._data);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, mat->_material._power);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
if (textureEnable)
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, vertexSize * sizeof(float), vertexData);
glNormalPointer(GL_FLOAT, vertexSize * sizeof(float), vertexData + normalOffset);
if (textureEnable)
glTexCoordPointer(2, GL_FLOAT, vertexSize * sizeof(float), vertexData + textureOffset);
glDrawElements(GL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, GL_UNSIGNED_INT, indexData + attrsTable->_ptr[i]._faceStart * 3);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
if (noAttrs) {
delete[] attrs;
}
return true;
}
bool XMeshOpenGL::renderFlatShadowModel(uint32 shadowColor) {
if (!_blendedMesh)
return false;
// For WME DX, mesh model is not visible, possible it's clipped.
// For OpenGL, mesh is visible, skip draw it here instead in core.
if (!_game->_renderer3D->_camera)
return false;
// W/A for the scene with the table in the laboratory where the engine switches to flat shadows.
// Presumably, it's supposed to disable shadows.
// Instead, OpenGL draws graphical glitches.
// Original DX version does not have this issue due to rendering shadows differently.
if (BaseEngine::instance().getGameId() == "alphapolaris")
return false;
uint32 vertexSize = DXGetFVFVertexSize(_blendedMesh->getFVF()) / sizeof(float);
float *vertexData = (float *)_blendedMesh->getVertexBuffer().ptr();
if (vertexData == nullptr) {
return false;
}
uint32 *indexData = (uint32 *)_blendedMesh->getIndexBuffer().ptr();
bool noAttrs = false;
auto attrsTable = _blendedMesh->getAttributeTable();
uint32 numAttrs = attrsTable->_size;
DXAttributeRange *attrs;
if (numAttrs == 0) {
noAttrs = true;
numAttrs = 1;
attrs = new DXAttributeRange[numAttrs];
} else {
attrs = attrsTable->_ptr;
}
if (noAttrs) {
attrs[0]._attribId = 0;
attrs[0]._vertexStart = attrs[0]._faceStart = 0;
attrs[0]._vertexCount = _blendedMesh->getNumVertices();
attrs[0]._faceCount = _blendedMesh->getNumFaces();
}
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glShadeModel(GL_FLAT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, (GLuint)~0);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
for (uint32 i = 0; i < numAttrs; i++) {
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, vertexSize * sizeof(float), vertexData);
glDrawElements(GL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, GL_UNSIGNED_INT, indexData + attrsTable->_ptr[i]._faceStart * 3);
glDisableClientState(GL_VERTEX_ARRAY);
}
glStencilFunc(GL_EQUAL, 1, (GLuint)~0);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
glColor4ub(RGBCOLGetR(shadowColor), RGBCOLGetG(shadowColor), RGBCOLGetB(shadowColor), RGBCOLGetA(shadowColor));
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_TRUE);
for (uint32 i = 0; i < numAttrs; i++) {
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, vertexSize * sizeof(float), vertexData);
glDrawElements(GL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, GL_UNSIGNED_INT, indexData + attrsTable->_ptr[i]._faceStart * 3);
glDisableClientState(GL_VERTEX_ARRAY);
}
if (noAttrs) {
delete[] attrs;
}
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
return true;
}
void XMeshOpenGL::renderEffect(Material *material) {
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material->_material._diffuse._data);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material->_material._diffuse._data);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material->_material._specular._data);
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, material->_material._emissive._data);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material->_material._power);
}
} // namespace Wintermute
#endif // defined(USE_OPENGL_GAME)

View File

@@ -0,0 +1,56 @@
/* 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
*/
#ifndef WINTERMUTE_XMESH_OPENGL_H
#define WINTERMUTE_XMESH_OPENGL_H
#include "engines/wintermute/base/gfx/xmesh.h"
class Effect3D;
class Effect3DParams;
#if defined(USE_OPENGL_GAME)
namespace Wintermute {
class XMeshOpenGL : public XMesh {
public:
XMeshOpenGL(BaseGame *inGame);
~XMeshOpenGL() override;
bool render(XModel *model) override;
bool renderFlatShadowModel(uint32 shadowColor) override;
private:
void renderEffect(Material *material);
};
} // namespace Wintermute
#endif // defined(USE_OPENGL_GAME)
#endif

View File

@@ -0,0 +1,289 @@
/* 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/base/gfx/xmaterial.h"
#include "engines/wintermute/base/gfx/3deffect.h"
#include "engines/wintermute/base/gfx/3deffect_params.h"
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
#include "engines/wintermute/base/gfx/base_renderer3d.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "graphics/opengl/system_headers.h"
#if defined(USE_OPENGL_SHADERS)
#include "engines/wintermute/base/gfx/opengl/base_surface_opengl3d.h"
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h"
#include "engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
XMeshOpenGLShader::XMeshOpenGLShader(BaseGame *inGame, OpenGL::Shader *shader, OpenGL::Shader *flatShadowShader) :
XMesh(inGame), _shader(shader), _flatShadowShader(flatShadowShader) {
glGenBuffers(1, &_vertexBuffer);
glGenBuffers(1, &_indexBuffer);
}
//////////////////////////////////////////////////////////////////////////
XMeshOpenGLShader::~XMeshOpenGLShader() {
glDeleteBuffers(1, &_vertexBuffer);
glDeleteBuffers(1, &_indexBuffer);
}
bool XMeshOpenGLShader::loadFromXData(const char *filename, XFileData *xobj) {
if (XMesh::loadFromXData(filename, xobj)) {
uint32 *indexData = (uint32 *)_blendedMesh->getIndexBuffer().ptr();
uint32 indexDataSize = _blendedMesh->getIndexBuffer().size() / sizeof(uint32);
float *vertexData = (float *)_blendedMesh->getVertexBuffer().ptr();
uint32 vertexSize = DXGetFVFVertexSize(_blendedMesh->getFVF()) / sizeof(float);
uint32 vertexCount = _blendedMesh->getNumVertices();
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 4 * vertexSize * vertexCount, vertexData, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 4 * indexDataSize, indexData, GL_STATIC_DRAW);
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool XMeshOpenGLShader::render(XModel *model) {
if (!_blendedMesh)
return false;
// For WME DX, mesh model is not visible, possible it's clipped.
// For OpenGL, mesh is visible, skip draw it here instead in core.
if (!_game->_renderer3D->_camera)
return false;
auto fvf = _blendedMesh->getFVF();
uint32 vertexSize = DXGetFVFVertexSize(fvf) / sizeof(float);
float *vertexData = (float *)_blendedMesh->getVertexBuffer().ptr();
if (vertexData == nullptr) {
return false;
}
uint32 offset = 0, normalOffset = 0, textureOffset = 0;
if (fvf & DXFVF_XYZ) {
offset += sizeof(DXVector3) / sizeof(float);
}
if (fvf & DXFVF_NORMAL) {
normalOffset = offset;
offset += sizeof(DXVector3) / sizeof(float);
}
if (fvf & DXFVF_DIFFUSE) {
offset += sizeof(DXColorValue) / sizeof(float);
}
if (fvf & DXFVF_TEX1) {
textureOffset = offset;
}
bool noAttrs = false;
auto attrsTable = _blendedMesh->getAttributeTable();
uint32 numAttrs = attrsTable->_size;
DXAttributeRange *attrs;
if (numAttrs == 0) {
noAttrs = true;
numAttrs = 1;
attrs = new DXAttributeRange[numAttrs];
} else {
attrs = attrsTable->_ptr;
}
if (noAttrs) {
attrs[0]._attribId = 0;
attrs[0]._vertexStart = attrs[0]._faceStart = 0;
attrs[0]._vertexCount = _blendedMesh->getNumVertices();
attrs[0]._faceCount = _blendedMesh->getNumFaces();
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
_shader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, 4 * vertexSize, 0);
_shader->enableVertexAttribute("texcoord", _vertexBuffer, 2, GL_FLOAT, false, 4 * vertexSize, 4 * textureOffset);
_shader->enableVertexAttribute("normal", _vertexBuffer, 3, GL_FLOAT, false, 4 * vertexSize, 4 * normalOffset);
_shader->use(true);
for (uint32 i = 0; i < numAttrs; i++) {
Material *mat = _materials[attrs[i]._attribId];
if (mat->getSurface()) {
glEnable(GL_TEXTURE_2D);
static_cast<BaseSurfaceOpenGL3D *>(mat->getSurface())->setTexture();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glGenerateMipmap(GL_TEXTURE_2D);
_shader->setUniform("useTexture", true);
} else {
_shader->setUniform("useTexture", false);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}
if (mat->getEffect()) {
renderEffect(mat);
} else {
Math::Vector4d diffuse(mat->_material._diffuse._data);
_shader->setUniform("diffuse", diffuse);
_shader->setUniform("ambient", diffuse);
}
size_t offsetFace = 4 * attrsTable->_ptr[i]._faceStart * 3;
glDrawElements(GL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, GL_UNSIGNED_INT, (void *)offsetFace);
}
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (noAttrs) {
delete[] attrs;
}
return true;
}
bool XMeshOpenGLShader::renderFlatShadowModel(uint32 shadowColor) {
if (!_blendedMesh)
return false;
// For WME DX, mesh model is not visible, possible it's clipped.
// For OpenGL, mesh is visible, skip draw it here instead in core.
if (!_game->_renderer3D->_camera)
return false;
// W/A for the scene with the table in the laboratory where the engine switches to flat shadows.
// Presumably, it's supposed to disable shadows.
// Instead, OpenGL draws graphical glitches.
// Original DX version does not have this issue due to rendering shadows differently.
if (BaseEngine::instance().getGameId() == "alphapolaris")
return false;
uint32 vertexSize = DXGetFVFVertexSize(_blendedMesh->getFVF()) / sizeof(float);
float *vertexData = (float *)_blendedMesh->getVertexBuffer().ptr();
if (vertexData == nullptr) {
return false;
}
bool noAttrs = false;
auto attrsTable = _blendedMesh->getAttributeTable();
uint32 numAttrs = attrsTable->_size;
DXAttributeRange *attrs;
if (numAttrs == 0) {
noAttrs = true;
numAttrs = 1;
attrs = new DXAttributeRange[numAttrs];
} else {
attrs = attrsTable->_ptr;
}
if (noAttrs) {
attrs[0]._attribId = 0;
attrs[0]._vertexStart = attrs[0]._faceStart = 0;
attrs[0]._vertexCount = _blendedMesh->getNumVertices();
attrs[0]._faceCount = _blendedMesh->getNumFaces();
}
Math::Vector4d color;
color.x() = RGBCOLGetR(shadowColor) / 255.0f;
color.y() = RGBCOLGetG(shadowColor) / 255.0f;
color.z() = RGBCOLGetB(shadowColor) / 255.0f;
color.w() = RGBCOLGetA(shadowColor) / 255.0f;
_flatShadowShader->enableVertexAttribute("position", _vertexBuffer, 3, GL_FLOAT, false, 4 * vertexSize, 0);
_flatShadowShader->use(true);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, (GLuint)~0);
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
for (uint32 i = 0; i < numAttrs; i++) {
size_t offsetFace = 4 * attrsTable->_ptr[i]._faceStart * 3;
glDrawElements(GL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, GL_UNSIGNED_INT, (void *)offsetFace);
}
glStencilFunc(GL_EQUAL, 1, (GLuint)~0);
glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
_flatShadowShader->setUniform("shadowColor", color);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_TRUE);
for (uint32 i = 0; i < numAttrs; i++) {
size_t offsetFace = 4 * attrsTable->_ptr[i]._faceStart * 3;
glDrawElements(GL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, GL_UNSIGNED_INT, (void *)offsetFace);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (noAttrs) {
delete[] attrs;
}
glDisable(GL_BLEND);
glDisable(GL_STENCIL_TEST);
return true;
}
bool XMeshOpenGLShader::update(FrameNode *parentFrame) {
XMesh::update(parentFrame);
float *vertexData = (float *)_blendedMesh->getVertexBuffer().ptr();
uint32 vertexSize = DXGetFVFVertexSize(_blendedMesh->getFVF()) / sizeof(float);
uint32 vertexCount = _blendedMesh->getNumVertices();
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * vertexSize * vertexCount, vertexData);
return true;
}
void XMeshOpenGLShader::renderEffect(Material *material) {
Math::Vector4d diffuse(material->_material._diffuse._data);
_shader->setUniform("diffuse", diffuse);
_shader->setUniform("ambient", diffuse);
}
} // namespace Wintermute
#endif // defined(USE_OPENGL_SHADERS)

View File

@@ -0,0 +1,67 @@
/* 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
*/
#ifndef WINTERMUTE_XMESH_OPENGL_SHADER_H
#define WINTERMUTE_XMESH_OPENGL_SHADER_H
#include "engines/wintermute/base/gfx/xmesh.h"
class Effect3D;
class Effect3DParams;
#if defined(USE_OPENGL_SHADERS)
#include "graphics/opengl/shader.h"
namespace Wintermute {
class XMeshOpenGLShader : public XMesh {
public:
XMeshOpenGLShader(BaseGame *inGame, OpenGL::Shader *shader, OpenGL::Shader *flatShadowShader);
~XMeshOpenGLShader() override;
bool loadFromXData(const char *filename, XFileData *xobj) override;
bool render(XModel *model) override;
bool renderFlatShadowModel(uint32 shadowColor) override;
bool update(FrameNode *parentFrame) override;
private:
void renderEffect(Material *material);
protected:
GLuint _vertexBuffer;
GLuint _indexBuffer;
OpenGL::Shader *_shader;
OpenGL::Shader *_flatShadowShader;
};
} // namespace Wintermute
#endif // defined(USE_OPENGL_SHADERS)
#endif

View File

@@ -0,0 +1,7 @@
in vec4 Color;
OUTPUT
void main() {
outColor = Color;
}

View File

@@ -0,0 +1,11 @@
in vec3 position;
uniform highp mat4 projMatrix;
uniform vec4 color;
out vec4 Color;
void main() {
gl_Position = projMatrix * vec4(position, 1.0);
Color = color;
}

View File

@@ -0,0 +1,7 @@
uniform vec4 shadowColor;
OUTPUT
void main() {
outColor = shadowColor;
}

View File

@@ -0,0 +1,9 @@
in vec3 position;
uniform highp mat4 modelMatrix;
uniform highp mat4 viewMatrix;
uniform highp mat4 projMatrix;
void main() {
gl_Position = projMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}

View File

@@ -0,0 +1,7 @@
in vec4 Color;
OUTPUT
void main() {
outColor = Color;
}

View File

@@ -0,0 +1,12 @@
in vec3 position;
in vec4 color;
uniform highp mat4 viewMatrix;
uniform highp mat4 projMatrix;
out vec4 Color;
void main() {
gl_Position = projMatrix * viewMatrix * vec4(position, 1.0);
Color = color;
}

View File

@@ -0,0 +1,14 @@
in vec4 Color;
uniform float alphaRef;
uniform UBOOL alphaTest;
OUTPUT
void main() {
outColor = Color;
if (UBOOL_TEST(alphaTest) && outColor.a < alphaRef) {
discard;
}
}

View File

@@ -0,0 +1,11 @@
in vec3 position;
uniform highp mat4 projMatrix;
uniform vec4 color;
out vec4 Color;
void main() {
gl_Position = projMatrix * vec4(position, 1.0);
Color = color;
}

View File

@@ -0,0 +1,29 @@
in vec2 Texcoord;
in vec4 Color;
uniform sampler2D tex;
uniform float alphaRef;
uniform UBOOL alphaTest;
uniform UBOOL useTexture;
uniform UBOOL enableFog;
uniform vec4 fogColor;
varying float fogFactor;
OUTPUT
void main() {
outColor = Color;
if (useTexture) {
outColor = texture(tex, Texcoord) * outColor;
}
if (enableFog) {
outColor.rgb = mix(fogColor.rgb, outColor.rgb, fogFactor);
}
if (UBOOL_TEST(alphaTest) && outColor.a < alphaRef) {
discard;
}
}

View File

@@ -0,0 +1,78 @@
in vec3 position;
in vec2 texcoord;
in vec3 normal;
uniform highp mat4 modelMatrix;
uniform highp mat4 viewMatrix;
uniform highp mat4 projMatrix;
uniform highp mat4 normalMatrix;
uniform vec4 ambientLight;
uniform vec4 diffuse;
uniform vec4 ambient;
uniform float fogStart;
uniform float fogEnd;
varying float fogFactor;
struct Light {
vec4 _position;
vec4 _direction;
vec4 _color;
float enabled;
};
const int maxLights = 8;
uniform Light lights[maxLights];
out vec2 Texcoord;
out vec4 Color;
out vec3 Normal;
void main() {
vec4 viewCoords = viewMatrix * modelMatrix * vec4(position, 1.0);
gl_Position = projMatrix * viewCoords;
Texcoord = texcoord;
Color = diffuse;
vec3 light = vec3(0.0, 0.0, 0.0);
vec3 normalEye = normalize((normalMatrix * vec4(normal, 0.0)).xyz);
float fogCoord = abs(viewCoords.z);
fogFactor = clamp((fogEnd - fogCoord) / (fogEnd - fogStart), 0.0, 1.0);
for (int i = 0; i < maxLights; ++i) {
if (lights[i].enabled < 0.0) {
continue;
}
float intensity = 1.0;
vec4 lightPosition = viewMatrix * lights[i]._position;
vec3 vertexToLight = lightPosition.xyz - viewCoords.xyz;
if (lights[i]._direction.w < 0.0) { // Spotlight
vec4 lightDirection = viewMatrix * vec4(lights[i]._direction.xyz, 0.0);
// See DirectX spotlight documentation
float cosAngle = -dot(normalize(vertexToLight), normalize(lightDirection.xyz)); // rho
float cosPenumbra = 0.968912; // cos(1 / 4)
float cosUmbra = 0.877582; // cos(1 / 2)
if (cosAngle <= cosPenumbra) {
if (cosAngle < cosUmbra || cosPenumbra == cosUmbra) {
intensity = 0.0;
} else {
intensity *= (cosAngle - cosUmbra) / (cosPenumbra - cosUmbra);
}
}
}
intensity *= max(0.0, dot(normalEye, normalize(vertexToLight)));
light += lights[i]._color.rgb * intensity;
}
Color.rgb *= light;
Color.rgb += ambient.rgb * ambientLight.rgb;
Color.rgb = clamp(Color.rgb, 0.0, 1.0);
}

View File

@@ -0,0 +1,21 @@
varying vec2 texPos;
uniform sampler2D tex;
uniform UBOOL sepiaMode;
OUTPUT
void main() {
vec4 color = texture2D(tex, texPos);
if (sepiaMode) {
float r = color.r;
float g = color.g;
float b = color.b;
outColor.r = dot(vec3(r, g, b), vec3(0.393, 0.769, 0.189));
outColor.g = dot(vec3(r, g, b), vec3(0.349, 0.686, 0.168));
outColor.b = dot(vec3(r, g, b), vec3(0.272, 0.534, 0.131));
} else {
float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
outColor = vec4(vec3(gray), 1.0);
}
}

View File

@@ -0,0 +1,9 @@
in vec2 position;
in vec2 texcoord;
varying vec2 texPos;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
texPos = texcoord;
}

View File

@@ -0,0 +1,7 @@
in vec4 Color;
OUTPUT
void main() {
outColor = Color;
}

View File

@@ -0,0 +1,11 @@
in vec3 position;
uniform highp mat4 projMatrix;
uniform vec4 color;
out vec4 Color;
void main() {
gl_Position = projMatrix * vec4(position, 1.0);
Color = color;
}

View File

@@ -0,0 +1,2 @@
void main() {
}

View File

@@ -0,0 +1,9 @@
in vec3 position;
uniform highp mat4 modelMatrix;
uniform highp mat4 viewMatrix;
uniform highp mat4 projMatrix;
void main() {
gl_Position = projMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
}

View File

@@ -0,0 +1,15 @@
in vec2 Texcoord;
uniform sampler2D tex;
uniform float alphaRef;
uniform UBOOL alphaTest;
OUTPUT
void main() {
outColor = texture(tex, Texcoord);
if (UBOOL_TEST(alphaTest) && outColor.a < alphaRef) {
discard;
}
}

View File

@@ -0,0 +1,14 @@
in vec3 position;
in vec3 normal;
in vec2 texcoord;
out vec2 Texcoord;
uniform highp mat4 modelMatrix;
uniform highp mat4 viewMatrix;
uniform highp mat4 projMatrix;
void main() {
gl_Position = projMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
Texcoord = texcoord;
}

View File

@@ -0,0 +1,16 @@
in vec2 Texcoord;
in vec4 Color;
uniform sampler2D tex;
uniform float alphaRef;
uniform UBOOL alphaTest;
OUTPUT
void main() {
outColor = Color * texture(tex, Texcoord);
if (UBOOL_TEST(alphaTest) && outColor.a < alphaRef) {
discard;
}
}

View File

@@ -0,0 +1,16 @@
in vec3 position;
in vec2 texcoord;
in vec4 color;
uniform highp mat4 projMatrix;
uniform highp mat3 transform;
out vec2 Texcoord;
out vec4 Color;
void main() {
vec3 transformed_position = transform * vec3(position);
gl_Position = projMatrix * vec4(transformed_position.x, transformed_position.y, transformed_position.z, 1.0);
Texcoord = texcoord;
Color = color;
}

View File

@@ -0,0 +1,197 @@
/* 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/base/base_game.h"
#include "engines/wintermute/dcgf.h"
#include "graphics/opengl/system_headers.h"
#if defined(USE_OPENGL_GAME)
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d.h"
#include "engines/wintermute/base/gfx/opengl/shadow_volume_opengl.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
ShadowVolumeOpenGL::ShadowVolumeOpenGL(BaseGame *inGame) : ShadowVolume(inGame) {
}
//////////////////////////////////////////////////////////////////////////
ShadowVolumeOpenGL::~ShadowVolumeOpenGL() {
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeOpenGL::render() {
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
_game->_renderer3D->_lastTexture = nullptr;
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, _vertices.getData());
glDrawArrays(GL_TRIANGLES, 0, _vertices.getSize());
glDisableClientState(GL_VERTEX_ARRAY);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeOpenGL::renderToStencilBuffer() {
// Disable z-buffer/color writes (note: z-testing still occurs), and enable the
// stencil-buffer
glDepthMask(GL_FALSE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDisable(GL_TEXTURE_2D);
glDisable(GL_LIGHTING);
glEnable(GL_STENCIL_TEST);
glEnable(GL_CULL_FACE);
// Set up stencil compare fuction, reference value, and masks.
// Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
// Note: since we set up the stencil-test to always pass, the STENCILFAIL
// renderstate is really not needed.
glStencilFunc(GL_ALWAYS, 0x1, (GLuint)~0);
glShadeModel(GL_FLAT);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
// Draw back-side of shadow volume in stencil/z only
glFrontFace(GL_CCW);
render();
// Decrement stencil buffer value
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
// Draw front-side of shadow volume in stencil/z only
glFrontFace(GL_CW);
render();
// Restore render states
glEnable(GL_LIGHTING);
glFrontFace(GL_CCW);
glShadeModel(GL_SMOOTH);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeOpenGL::renderToScene() {
initMask();
glDisable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Only write where stencil val >= 1 (count indicates # of shadows that overlap that pixel)
glStencilFunc(GL_LEQUAL, 0x1, (GLuint)~0);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glDisable(GL_FOG);
glDisable(GL_LIGHTING);
glDisable(GL_ALPHA_TEST);
glBindTexture(GL_TEXTURE_2D, 0);
BaseRenderOpenGL3D *renderer = dynamic_cast<BaseRenderOpenGL3D *>(_game->_renderer3D);
renderer->setProjection2D();
glFrontFace(GL_CW);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
// Draw a big, gray square
glVertexPointer(3, GL_FLOAT, sizeof(ShadowVertex), &_shadowMask[0].x);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ShadowVertex), &_shadowMask[0].r);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
// Restore render states
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
_game->_renderer3D->setup3D(nullptr, true);
// clear stencil buffer
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeOpenGL::initMask() {
auto *rend = _game->_renderer3D;
// bottom left
_shadowMask[0].x = 0.0f;
_shadowMask[0].y = rend->getHeight();
_shadowMask[0].z = 1.0f;
// top left
_shadowMask[1].x = 0.0f;
_shadowMask[1].y = 0.0f;
_shadowMask[1].z = 1.0f;
// bottom right
_shadowMask[2].x = rend->getWidth();
_shadowMask[2].y = rend->getHeight();
_shadowMask[2].z = 1.0f;
// top right
_shadowMask[3].x = rend->getWidth();
_shadowMask[3].y = 0.0f;
_shadowMask[3].z = 1.0f;
byte a = RGBCOLGetA(_color);
byte r = RGBCOLGetR(_color);
byte g = RGBCOLGetG(_color);
byte b = RGBCOLGetB(_color);
for (int i = 0; i < 4; ++i) {
_shadowMask[i].r = r;
_shadowMask[i].g = g;
_shadowMask[i].b = b;
_shadowMask[i].a = a;
}
return true;
}
} // namespace Wintermute
#endif // defined(USE_OPENGL_GAME)

View File

@@ -0,0 +1,55 @@
/* 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
*/
#ifndef WINTERMUTE_SHADOW_VOLUME_OPENGL_H
#define WINTERMUTE_SHADOW_VOLUME_OPENGL_H
#include "engines/wintermute/base/gfx/3dshadow_volume.h"
#if defined(USE_OPENGL_GAME)
namespace Wintermute {
class ShadowVolumeOpenGL : public ShadowVolume {
public:
ShadowVolumeOpenGL(BaseGame *inGame);
virtual ~ShadowVolumeOpenGL();
bool renderToStencilBuffer() override;
bool renderToScene() override;
private:
bool render();
ShadowVertex _shadowMask[4]{};
bool initMask() override;
};
} // namespace Wintermute
#endif // defined(USE_OPENGL_GAME)
#endif

View File

@@ -0,0 +1,210 @@
/* 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/base/base_game.h"
#include "engines/wintermute/dcgf.h"
#include "graphics/opengl/system_headers.h"
#if defined(USE_OPENGL_SHADERS)
#include "engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h"
#include "engines/wintermute/base/gfx/opengl/shadow_volume_opengl_shader.h"
namespace Wintermute {
struct ShadowVertexShader {
float x;
float y;
float z;
};
//////////////////////////////////////////////////////////////////////////
ShadowVolumeOpenGLShader::ShadowVolumeOpenGLShader(BaseGame *inGame, OpenGL::Shader *volumeShader, OpenGL::Shader *maskShader)
: ShadowVolume(inGame), _volumeShader(volumeShader), _maskShader(maskShader) {
_shadowVolumeVertexBuffer = 0;
glGenBuffers(1, &_shadowVolumeVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _shadowVolumeVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 12 * _vertices.getSize(), _vertices.getData(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &_shadowMaskVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _shadowMaskVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(ShadowVertexShader), nullptr, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
//////////////////////////////////////////////////////////////////////////
ShadowVolumeOpenGLShader::~ShadowVolumeOpenGLShader() {
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeOpenGLShader::render() {
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
_game->_renderer3D->_lastTexture = nullptr;
glDrawArrays(GL_TRIANGLES, 0, _vertices.getSize());
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeOpenGLShader::renderToStencilBuffer() {
// since the vertex count of the volume might change,
// we just create a new buffer per frame
// we might as well use the number of vertices of the mesh as an upper bound
// or get rid of this completely by moving everything onto the gpu
glDeleteBuffers(1, &_shadowVolumeVertexBuffer);
glGenBuffers(1, &_shadowVolumeVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _shadowVolumeVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, 12 * _vertices.getSize(), _vertices.getData(), GL_STATIC_DRAW);
_volumeShader->enableVertexAttribute("position", _shadowVolumeVertexBuffer, 3, GL_FLOAT, false, 12, 0);
_volumeShader->use(true);
// Disable z-buffer/color writes (note: z-testing still occurs), and enable the
// stencil-buffer
glDepthMask(GL_FALSE);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDisable(GL_TEXTURE_2D);
glEnable(GL_STENCIL_TEST);
glEnable(GL_CULL_FACE);
// Set up stencil compare fuction, reference value, and masks.
// Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
// Note: since we set up the stencil-test to always pass, the STENCILFAIL
// renderstate is really not needed.
glStencilFunc(GL_ALWAYS, 0x1, (GLuint)~0);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
// Draw back-side of shadow volume in stencil/z only
glFrontFace(GL_CCW);
render();
// Decrement stencil buffer value
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
// Draw front-side of shadow volume in stencil/z only
glFrontFace(GL_CW);
render();
// Restore render states
glFrontFace(GL_CCW);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_STENCIL_TEST);
glDisable(GL_BLEND);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeOpenGLShader::renderToScene() {
initMask();
glDisable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Only write where stencil val >= 1 (count indicates # of shadows that overlap that pixel)
glStencilFunc(GL_LEQUAL, 0x1, (GLuint)~0);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glBindTexture(GL_TEXTURE_2D, 0);
BaseRenderOpenGL3DShader *renderer = dynamic_cast<BaseRenderOpenGL3DShader *>(_game->_renderer3D);
renderer->_shadowMaskShader->use();
renderer->setProjection2D(renderer->_shadowMaskShader);
_maskShader->enableVertexAttribute("position", _shadowMaskVertexBuffer, 3, GL_FLOAT, false, 12, 0);
_maskShader->use(true);
glFrontFace(GL_CW);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Restore render states
glEnable(GL_DEPTH_TEST);
glDisable(GL_STENCIL_TEST);
_game->_renderer3D->setup3D(nullptr, true);
// clear stencil buffer
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeOpenGLShader::initMask() {
auto *rend = _game->_renderer3D;
ShadowVertexShader shadowMask[4];
// bottom left
shadowMask[0].x = 0.0f;
shadowMask[0].y = rend->getHeight();
shadowMask[0].z = 1.0f;
// top left
shadowMask[1].x = 0.0f;
shadowMask[1].y = 0.0f;
shadowMask[1].z = 1.0f;
// bottom right
shadowMask[2].x = rend->getWidth();
shadowMask[2].y = rend->getHeight();
shadowMask[2].z = 1.0f;
// top right
shadowMask[3].x = rend->getWidth();
shadowMask[3].y = 0.0f;
shadowMask[3].z = 1.0f;
glBindBuffer(GL_ARRAY_BUFFER, _shadowMaskVertexBuffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, 4 * sizeof(ShadowVertexShader), shadowMask);
Math::Vector4d color;
color.x() = RGBCOLGetR(_color) / 255.0f;
color.y() = RGBCOLGetG(_color) / 255.0f;
color.z() = RGBCOLGetB(_color) / 255.0f;
color.w() = RGBCOLGetA(_color) / 255.0f;
_maskShader->use();
_maskShader->setUniform("color", color);
return true;
}
} // namespace Wintermute
#endif // defined(USE_OPENGL_SHADERS)

View File

@@ -0,0 +1,62 @@
/* 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
*/
#ifndef WINTERMUTE_SHADOW_VOLUME_OPENGL_SHADER_H
#define WINTERMUTE_SHADOW_VOLUME_OPENGL_SHADER_H
#include "engines/wintermute/base/gfx/3dshadow_volume.h"
#include "graphics/opengl/system_headers.h"
#if defined(USE_OPENGL_SHADERS)
#include "graphics/opengl/shader.h"
namespace Wintermute {
class ShadowVolumeOpenGLShader : public ShadowVolume {
public:
ShadowVolumeOpenGLShader(BaseGame *inGame, OpenGL::Shader *volumeShader, OpenGL::Shader *maskShader);
virtual ~ShadowVolumeOpenGLShader();
bool renderToStencilBuffer() override;
bool renderToScene() override;
private:
bool render();
bool initMask() override;
GLuint _shadowVolumeVertexBuffer;
GLuint _shadowMaskVertexBuffer;
OpenGL::Shader *_volumeShader;
OpenGL::Shader *_maskShader;
};
} // namespace Wintermute
#endif // defined(USE_OPENGL_SHADERS)
#endif

View File

@@ -0,0 +1,580 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/gfx/osystem/base_render_osystem.h"
#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h"
#include "engines/wintermute/base/gfx/osystem/render_ticket.h"
#include "engines/wintermute/base/base_surface_storage.h"
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/math/math_util.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_sprite.h"
#include "engines/util.h"
#include "common/system.h"
#include "common/queue.h"
#include "common/config-manager.h"
#define DIRTY_RECT_LIMIT 800
namespace Wintermute {
BaseRenderer *makeOSystemRenderer(BaseGame *inGame) {
return new BaseRenderOSystem(inGame);
}
//////////////////////////////////////////////////////////////////////////
BaseRenderOSystem::BaseRenderOSystem(BaseGame *inGame) : BaseRenderer(inGame) {
_renderSurface = new Graphics::ManagedSurface();
_lastFrameIter = _renderQueue.end();
_needsFlip = true;
_skipThisFrame = false;
_borderLeft = _borderRight = _borderTop = _borderBottom = 0;
_ratioX = _ratioY = 1.0f;
_dirtyRect = nullptr;
_disableDirtyRects = false;
if (ConfMan.hasKey("dirty_rects")) {
_disableDirtyRects = !ConfMan.getBool("dirty_rects");
}
_lastScreenChangeID = g_system->getScreenChangeID();
}
//////////////////////////////////////////////////////////////////////////
BaseRenderOSystem::~BaseRenderOSystem() {
RenderQueueIterator it = _renderQueue.begin();
while (it != _renderQueue.end()) {
RenderTicket *ticket = *it;
it = _renderQueue.erase(it);
delete ticket;
}
delete _dirtyRect;
_renderSurface->free();
delete _renderSurface;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) {
_width = width;
_height = height;
_renderRect.setWidth(_width);
_renderRect.setHeight(_height);
_realWidth = width;
_realHeight = height;
float origAspect = (float)_width / (float)_height;
float realAspect = (float)_realWidth / (float)_realHeight;
float ratio;
if (origAspect < realAspect) {
// normal to wide
ratio = (float)_realHeight / (float)_height;
} else {
// wide to normal
ratio = (float)_realWidth / (float)_width;
}
_borderLeft = (int)((_realWidth - (_width * ratio)) / 2);
_borderRight = (int)(_realWidth - (_width * ratio) - _borderLeft);
_borderTop = (int)((_realHeight - (_height * ratio)) / 2);
_borderBottom = (int)(_realHeight - (_height * ratio) - _borderTop);
_ratioX = (float)(_realWidth - _borderLeft - _borderRight) / (float)_width;
_ratioY = (float)(_realHeight - _borderTop - _borderBottom) / (float)_height;
_windowed = !ConfMan.getBool("fullscreen");
Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
initGraphics(_width, _height, &format);
if (g_system->getScreenFormat() != format) {
warning("Couldn't setup GFX-backend for %dx%dx%d", _width, _height, format.bytesPerPixel * 8);
return STATUS_FAILED;
}
g_system->showMouse(false);
_renderSurface->create(g_system->getWidth(), g_system->getHeight(), g_system->getScreenFormat());
_active = true;
_clearColor = _renderSurface->format.ARGBToColor(255, 0, 0, 0);
return STATUS_OK;
}
bool BaseRenderOSystem::indicatorFlip(int32 x, int32 y, int32 width, int32 height) {
if (width > 0 && height > 0) {
g_system->copyRectToScreen(_renderSurface->getBasePtr(x, y), _renderSurface->pitch, x, y, width, height);
g_system->updateScreen();
}
return STATUS_OK;
}
bool BaseRenderOSystem::forcedFlip() {
g_system->copyRectToScreen(_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h);
g_system->updateScreen();
return STATUS_OK;
}
bool BaseRenderOSystem::flip() {
if (_skipThisFrame) {
_skipThisFrame = false;
delete _dirtyRect;
_dirtyRect = nullptr;
g_system->updateScreen();
_needsFlip = false;
// Reset ticketing state
_lastFrameIter = _renderQueue.end();
RenderQueueIterator it;
for (it = _renderQueue.begin(); it != _renderQueue.end(); ++it) {
(*it)->_wantsDraw = false;
}
addDirtyRect(_renderRect);
return true;
}
if (!_disableDirtyRects) {
drawTickets();
} else {
// Clear the scale-buffered tickets that wasn't reused.
RenderQueueIterator it = _renderQueue.begin();
while (it != _renderQueue.end()) {
if ((*it)->_wantsDraw == false) {
RenderTicket *ticket = *it;
it = _renderQueue.erase(it);
delete ticket;
} else {
(*it)->_wantsDraw = false;
++it;
}
}
}
int oldScreenChangeID = _lastScreenChangeID;
_lastScreenChangeID = g_system->getScreenChangeID();
bool screenChanged = _lastScreenChangeID != oldScreenChangeID;
if (_needsFlip || _disableDirtyRects || screenChanged) {
if (_disableDirtyRects || screenChanged) {
g_system->copyRectToScreen(_renderSurface->getPixels(), _renderSurface->pitch, 0, 0, _renderSurface->w, _renderSurface->h);
}
delete _dirtyRect;
_dirtyRect = nullptr;
_needsFlip = false;
}
_lastFrameIter = _renderQueue.end();
g_system->updateScreen();
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////
void BaseRenderOSystem::onWindowChange() {
_windowed = !g_system->getFeatureState(OSystem::kFeatureFullscreenMode);
}
//////////////////////////////////////////////////////////////////////
void BaseRenderOSystem::setWindowed(bool windowed) {
ConfMan.setBool("fullscreen", !windowed);
g_system->beginGFXTransaction();
g_system->setFeatureState(OSystem::kFeatureFullscreenMode, !windowed);
g_system->endGFXTransaction();
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderOSystem::clear() {
if (!_disableDirtyRects) {
return STATUS_OK;
}
// TODO: This doesn't work with dirty rects
_renderSurface->fillRect(_renderRect, _clearColor);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderOSystem::fade(uint16 alpha) {
byte dwAlpha = (byte)(255 - alpha);
return fadeToColor(0, 0, 0, dwAlpha);
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderOSystem::fadeToColor(byte r, byte g, byte b, byte a) {
Common::Rect fillRect;
Common::Rect32 rc;
_game->getCurrentViewportRect(&rc);
fillRect.left = (int16)rc.left;
fillRect.top = (int16)rc.top;
fillRect.setWidth((int16)(rc.right - rc.left));
fillRect.setHeight((int16)(rc.bottom - rc.top));
modTargetRect(&fillRect);
Common::Rect sizeRect(fillRect.width(), fillRect.height());
Graphics::TransformStruct temp = Graphics::TransformStruct();
temp._rgbaMod = MS_ARGB(a, r, g, b);
temp._alphaDisable = (a == 0xff);
drawSurface(nullptr, nullptr, &sizeRect, &fillRect, temp);
return true;
}
Graphics::PixelFormat BaseRenderOSystem::getPixelFormat() const {
return _renderSurface->format;
}
void BaseRenderOSystem::drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf,
Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct &transform) {
if (_disableDirtyRects) {
RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform);
ticket->_wantsDraw = true;
_renderQueue.push_back(ticket);
drawFromSurface(ticket);
return;
}
// Skip rects that are completely outside the screen:
if ((dstRect->left < 0 && dstRect->right < 0) || (dstRect->top < 0 && dstRect->bottom < 0)) {
return;
}
if (owner) { // Fade-tickets are owner-less
RenderTicket compare(owner, nullptr, srcRect, dstRect, transform);
RenderQueueIterator it = _lastFrameIter;
++it;
// Avoid calling end() and operator* every time, when potentially going through
// LOTS of tickets.
RenderQueueIterator endIterator = _renderQueue.end();
RenderTicket *compareTicket = nullptr;
for (; it != endIterator; ++it) {
compareTicket = *it;
if (*(compareTicket) == compare && compareTicket->_isValid) {
if (_disableDirtyRects) {
drawFromSurface(compareTicket);
} else {
drawFromQueuedTicket(it);
}
return;
}
}
}
RenderTicket *ticket = new RenderTicket(owner, surf, srcRect, dstRect, transform);
if (!_disableDirtyRects) {
drawFromTicket(ticket);
} else {
ticket->_wantsDraw = true;
_renderQueue.push_back(ticket);
drawFromSurface(ticket);
}
}
void BaseRenderOSystem::invalidateTicket(RenderTicket *renderTicket) {
addDirtyRect(renderTicket->_dstRect);
renderTicket->_isValid = false;
// renderTicket->_canDelete = true; // TODO: Maybe readd this, to avoid even more duplicates.
}
void BaseRenderOSystem::invalidateTicketsFromSurface(BaseSurfaceOSystem *surf) {
RenderQueueIterator it;
for (it = _renderQueue.begin(); it != _renderQueue.end(); ++it) {
if ((*it)->_owner == surf) {
invalidateTicket(*it);
}
}
}
void BaseRenderOSystem::drawFromTicket(RenderTicket *renderTicket) {
renderTicket->_wantsDraw = true;
++_lastFrameIter;
// In-order
if (_renderQueue.empty() || _lastFrameIter == _renderQueue.end()) {
_lastFrameIter--;
_renderQueue.push_back(renderTicket);
++_lastFrameIter;
addDirtyRect(renderTicket->_dstRect);
} else {
// Before something
RenderQueueIterator pos = _lastFrameIter;
_renderQueue.insert(pos, renderTicket);
--_lastFrameIter;
addDirtyRect(renderTicket->_dstRect);
}
}
void BaseRenderOSystem::drawFromQueuedTicket(const RenderQueueIterator &ticket) {
RenderTicket *renderTicket = *ticket;
assert(!renderTicket->_wantsDraw);
renderTicket->_wantsDraw = true;
++_lastFrameIter;
// Not in the same order?
if (*_lastFrameIter != renderTicket) {
--_lastFrameIter;
// Remove the ticket from the list
assert(*_lastFrameIter != renderTicket);
_renderQueue.erase(ticket);
// Is not in order, so readd it as if it was a new ticket
drawFromTicket(renderTicket);
}
}
void BaseRenderOSystem::addDirtyRect(const Common::Rect &rect) {
if (!_dirtyRect) {
_dirtyRect = new Common::Rect(rect);
} else {
_dirtyRect->extend(rect);
}
_dirtyRect->clip(_renderRect);
}
void BaseRenderOSystem::drawTickets() {
RenderQueueIterator it = _renderQueue.begin();
// Clean out the old tickets
// Note: We draw invalid tickets too, otherwise we wouldn't be honoring
// the draw request they obviously made BEFORE becoming invalid, either way
// we have a copy of their data, so their invalidness won't affect us.
while (it != _renderQueue.end()) {
if ((*it)->_wantsDraw == false) {
RenderTicket *ticket = *it;
addDirtyRect((*it)->_dstRect);
it = _renderQueue.erase(it);
delete ticket;
} else {
++it;
}
}
if (!_dirtyRect || _dirtyRect->width() == 0 || _dirtyRect->height() == 0) {
it = _renderQueue.begin();
while (it != _renderQueue.end()) {
RenderTicket *ticket = *it;
ticket->_wantsDraw = false;
++it;
}
return;
}
it = _renderQueue.begin();
_lastFrameIter = _renderQueue.end();
// A special case: If the screen has one giant OPAQUE rect to be drawn, then we skip filling
// the background color. Typical use-case: Fullscreen FMVs.
// Caveat: The FPS-counter will invalidate this.
if (it != _lastFrameIter && _renderQueue.front() == _renderQueue.back() && (*it)->_transform._alphaDisable == true) {
// If our single opaque rect fills the dirty rect, we can skip filling.
if (*_dirtyRect != (*it)->_dstRect) {
// Apply the clear-color to the dirty rect.
_renderSurface->fillRect(*_dirtyRect, _clearColor);
}
// Otherwise Do NOT fill.
} else {
// Apply the clear-color to the dirty rect.
_renderSurface->fillRect(*_dirtyRect, _clearColor);
}
for (; it != _renderQueue.end(); ++it) {
RenderTicket *ticket = *it;
if (ticket->_dstRect.intersects(*_dirtyRect)) {
// dstClip is the area we want redrawn.
Common::Rect dstClip(ticket->_dstRect);
// reduce it to the dirty rect
dstClip.clip(*_dirtyRect);
// we need to keep track of the position to redraw the dirty rect
Common::Rect pos(dstClip);
int16 offsetX = ticket->_dstRect.left;
int16 offsetY = ticket->_dstRect.top;
// convert from screen-coords to surface-coords.
dstClip.translate(-offsetX, -offsetY);
drawFromSurface(ticket, &pos, &dstClip);
_needsFlip = true;
}
// Some tickets want redraw but don't actually clip the dirty area (typically the ones that shouldn't become clear-color)
ticket->_wantsDraw = false;
}
g_system->copyRectToScreen(_renderSurface->getBasePtr(_dirtyRect->left, _dirtyRect->top), _renderSurface->pitch, _dirtyRect->left, _dirtyRect->top, _dirtyRect->width(), _dirtyRect->height());
it = _renderQueue.begin();
// Clean out the old tickets
while (it != _renderQueue.end()) {
if ((*it)->_isValid == false) {
RenderTicket *ticket = *it;
addDirtyRect((*it)->_dstRect);
it = _renderQueue.erase(it);
delete ticket;
} else {
++it;
}
}
}
// Replacement for SDL2's SDL_RenderCopy
void BaseRenderOSystem::drawFromSurface(RenderTicket *ticket) {
ticket->drawToSurface(_renderSurface);
}
void BaseRenderOSystem::drawFromSurface(RenderTicket *ticket, Common::Rect *dstRect, Common::Rect *clipRect) {
ticket->drawToSurface(_renderSurface, dstRect, clipRect);
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderOSystem::drawLine(int x1, int y1, int x2, int y2, uint32 color) {
#if 0
byte r = RGBCOLGetR(color);
byte g = RGBCOLGetG(color);
byte b = RGBCOLGetB(color);
byte a = RGBCOLGetA(color);
#endif
Common::Point32 point1, point2;
point1.x = x1;
point1.y = y1;
pointToScreen(&point1);
point2.x = x2;
point2.y = y2;
pointToScreen(&point2);
// TODO
#if 0
uint32 colorVal = _renderSurface->format.ARGBToColor(a, r, g, b);
_renderSurface->drawLine(point1.x, point1.y, point2.x + 1, point2.y + 1, colorVal);
#endif
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderOSystem::fillRect(int x, int y, int w, int h, uint32 color) {
// This function isn't used outside of indicator-displaying, and thus quite unused in
// BaseRenderOSystem when dirty-rects are enabled.
if (!_disableDirtyRects && !_game->_indicatorDisplay) {
error("BaseRenderOSystem::fillRect - doesn't work for dirty rects yet");
}
byte r = RGBCOLGetR(color);
byte g = RGBCOLGetG(color);
byte b = RGBCOLGetB(color);
byte a = RGBCOLGetA(color);
Common::Rect fillRect(x, y, x + w, y + w);
modTargetRect(&fillRect);
uint32 colorVal = _renderSurface->format.ARGBToColor(a, r, g, b);
_renderSurface->fillRect(fillRect, colorVal);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
BaseImage *BaseRenderOSystem::takeScreenshot(int newWidth, int newHeight) {
// TODO: Clip by viewport.
BaseImage *screenshot = new BaseImage();
screenshot->copyFrom(_renderSurface->surfacePtr(), newWidth, newHeight);
return screenshot;
}
//////////////////////////////////////////////////////////////////////////
Common::String BaseRenderOSystem::getName() const {
return "ScummVM-OSystem-renderer";
}
//////////////////////////////////////////////////////////////////////////
bool BaseRenderOSystem::setViewport(int left, int top, int right, int bottom) {
Common::Rect rect;
rect.left = (int16)(left + _borderLeft);
rect.top = (int16)(top + _borderTop);
rect.setWidth((int16)((right - left) * _ratioX));
rect.setHeight((int16)((bottom - top) * _ratioY));
_renderRect = rect;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
void BaseRenderOSystem::modTargetRect(Common::Rect *rect) {
return;
int newWidth = (int16)MathUtil::roundUp(rect->width() * _ratioX);
int newHeight = (int16)MathUtil::roundUp(rect->height() * _ratioY);
rect->left = (int16)MathUtil::round(rect->left * _ratioX + _borderLeft);
rect->top = (int16)MathUtil::round(rect->top * _ratioY + _borderTop);
rect->setWidth(newWidth);
rect->setHeight(newHeight);
}
//////////////////////////////////////////////////////////////////////////
void BaseRenderOSystem::pointFromScreen(Common::Point32 *point) {
point->x = (int16)(point->x / _ratioX - _borderLeft / _ratioX + _renderRect.left);
point->y = (int16)(point->y / _ratioY - _borderTop / _ratioY + _renderRect.top);
}
//////////////////////////////////////////////////////////////////////////
void BaseRenderOSystem::pointToScreen(Common::Point32 *point) {
point->x = (int16)MathUtil::roundUp(point->x * _ratioX) + _borderLeft - _renderRect.left;
point->y = (int16)MathUtil::roundUp(point->y * _ratioY) + _borderTop - _renderRect.top;
}
BaseSurface *BaseRenderOSystem::createSurface() {
return new BaseSurfaceOSystem(_game);
}
void BaseRenderOSystem::endSaveLoad() {
BaseRenderer::endSaveLoad();
// Clear the scale-buffered tickets as we just loaded.
RenderQueueIterator it = _renderQueue.begin();
while (it != _renderQueue.end()) {
RenderTicket *ticket = *it;
it = _renderQueue.erase(it);
delete ticket;
}
// HACK: After a save the buffer will be drawn before the scripts get to update it,
// so just skip this single frame.
_skipThisFrame = true;
_lastFrameIter = _renderQueue.end();
_renderSurface->fillRect(Common::Rect(0, 0, _renderSurface->w, _renderSurface->h), _renderSurface->format.ARGBToColor(255, 0, 0, 0));
g_system->fillScreen(Common::Rect(0, 0, _renderSurface->w, _renderSurface->h), _renderSurface->format.ARGBToColor(255, 0, 0, 0));
g_system->updateScreen();
}
bool BaseRenderOSystem::startSpriteBatch() {
return STATUS_OK;
}
bool BaseRenderOSystem::endSpriteBatch() {
return STATUS_OK;
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,155 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_RENDERER_SDL_H
#define WINTERMUTE_BASE_RENDERER_SDL_H
#include "engines/wintermute/base/gfx/base_renderer.h"
#include "common/rect.h"
#include "common/list.h"
#include "graphics/managed_surface.h"
#include "graphics/transform_struct.h"
namespace Wintermute {
class BaseSurfaceOSystem;
class RenderTicket;
/**
* A 2D-renderer implementation for WME.
* This renderer makes use of a "ticket"-system, where all draw-calls
* are stored as tickets until flip() is called, and compared against the tickets
* from last frame, to determine which calls were the same as last round
* (i.e. in the exact same order, with the exact same arguments), and thus
* figure out which parts of the screen need to be redrawn.
*
* Important concepts to handle here, is the ordered number of any ticket
* which is called the "drawNum", every frame this starts from scratch, and
* then the incoming tickets created from the draw-calls are checked to see whether
* they came before, on, or after the drawNum they had last frame. Everything else
* being equal, this information is then used to check whether the draw order changed,
* which will then create a need for redrawing, as we draw with an alpha-channel here.
*
* There is also a draw path that draws without tickets, for debugging purposes,
* as well as to accommodate situations with large enough amounts of draw calls,
* that there will be too much overhead involved with comparing the generated tickets.
*/
class BaseRenderOSystem : public BaseRenderer {
public:
BaseRenderOSystem(BaseGame *inGame);
~BaseRenderOSystem() override;
typedef Common::List<RenderTicket *>::iterator RenderQueueIterator;
Common::String getName() const override;
bool initRenderer(int width, int height, bool windowed) override;
bool flip() override;
bool indicatorFlip(int32 x, int32 y, int32 width, int32 height) override;
bool forcedFlip() override;
bool clear() override;
Graphics::PixelFormat getPixelFormat() const override;
bool fade(uint16 alpha) override;
bool fadeToColor(byte r, byte g, byte b, byte a) override;
bool drawLine(int x1, int y1, int x2, int y2, uint32 color) override;
bool fillRect(int x, int y, int w, int h, uint32 color) override;
BaseImage *takeScreenshot(int newWidth = 0, int newHeight = 0) override;
void onWindowChange() override;
void setWindowed(bool windowed) override;
void invalidateTicket(RenderTicket *renderTicket);
void invalidateTicketsFromSurface(BaseSurfaceOSystem *surf);
/**
* Insert a new ticket into the queue, adding a dirty rect
* @param renderTicket the ticket to be added.
*/
void drawFromTicket(RenderTicket *renderTicket);
/**
* Re-insert an existing ticket into the queue, adding a dirty rect
* out-of-order from last draw from the ticket.
* @param ticket iterator pointing to the ticket to be added.
*/
void drawFromQueuedTicket(const RenderQueueIterator &ticket);
bool setViewport(int left, int top, int right, int bottom) override;
bool setViewport(Common::Rect32 *rect) override { return BaseRenderer::setViewport(rect); }
void modTargetRect(Common::Rect *rect);
void pointFromScreen(Common::Point32 *point);
void pointToScreen(Common::Point32 *point);
float getScaleRatioX() const override {
return _ratioX;
}
float getScaleRatioY() const override {
return _ratioY;
}
bool startSpriteBatch() override;
bool endSpriteBatch() override;
void endSaveLoad() override;
void drawSurface(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct &transform);
BaseSurface *createSurface() override;
private:
/**
* Mark a specified rect of the screen as dirty.
* @param rect the region to be marked as dirty
*/
void addDirtyRect(const Common::Rect &rect);
/**
* Traverse the tickets that are dirty, and draw them
*/
void drawTickets();
// Non-dirty-rects:
void drawFromSurface(RenderTicket *ticket);
// Dirty-rects:
void drawFromSurface(RenderTicket *ticket, Common::Rect *dstRect, Common::Rect *clipRect);
Common::Rect *_dirtyRect;
Common::List<RenderTicket *> _renderQueue;
bool _needsFlip;
RenderQueueIterator _lastFrameIter;
Common::Rect _renderRect;
Graphics::ManagedSurface *_renderSurface;
int _borderLeft;
int _borderTop;
int _borderRight;
int _borderBottom;
bool _disableDirtyRects;
float _ratioX;
float _ratioY;
uint32 _clearColor;
bool _skipThisFrame;
int _lastScreenChangeID; // previous value of OSystem::getScreenChangeID()
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,477 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h"
#include "engines/wintermute/base/gfx/osystem/base_render_osystem.h"
#include "engines/wintermute/base/gfx/base_image.h"
#include "engines/wintermute/platform_osystem.h"
#include "graphics/managed_surface.h"
#include "graphics/transform_tools.h"
#include "graphics/pixelformat.h"
#include "graphics/surface.h"
#include "common/stream.h"
#include "common/system.h"
#define TS_COLOR(wmeColor) \
MS_ARGB(RGBCOLGetA(wmeColor), RGBCOLGetR(wmeColor), RGBCOLGetG(wmeColor), RGBCOLGetB(wmeColor))
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
BaseSurfaceOSystem::BaseSurfaceOSystem(BaseGame *inGame) : BaseSurface(inGame) {
_surface = new Graphics::Surface();
_pixelOpReady = false;
_alphaMask = nullptr;
_alphaType = Graphics::ALPHA_FULL;
_alphaMaskType = Graphics::ALPHA_OPAQUE;
_rotation = 0;
_surfaceModified = false;
}
//////////////////////////////////////////////////////////////////////////
BaseSurfaceOSystem::~BaseSurfaceOSystem() {
if (_surface) {
if (_valid)
_game->addMem(-_width * _height * 4);
_surface->free();
delete _surface;
_surface = nullptr;
}
if (_alphaMask) {
_alphaMask->free();
delete _alphaMask;
_alphaMask = nullptr;
}
BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_game->_renderer);
renderer->invalidateTicketsFromSurface(this);
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::create(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime, bool keepLoaded) {
if (defaultCK) {
ckRed = 255;
ckGreen = 0;
ckBlue = 255;
}
BaseImage img = BaseImage();
if (!img.getImageInfo(filename, _width, _height)) {
return false;
}
if (lifeTime != -1 && _lifeTime == 0) {
_valid = false;
}
_ckDefault = defaultCK;
_ckRed = ckRed;
_ckGreen = ckGreen;
_ckBlue = ckBlue;
if (!_filename || scumm_stricmp(_filename, filename) != 0) {
setFilename(filename);
}
if (_lifeTime == 0 || lifeTime == -1 || lifeTime > _lifeTime) {
_lifeTime = lifeTime;
}
_keepLoaded = keepLoaded;
if (_keepLoaded) {
_lifeTime = -1;
}
return STATUS_OK;
}
bool BaseSurfaceOSystem::loadImage() {
if (!_filename || !_filename[0]) {
return false;
}
Common::String filename = _filename;
BaseImage *image = new BaseImage();
if (!image->loadFile(filename)) {
delete image;
return false;
}
if (_surface) {
if (_valid)
_game->addMem(-_width * _height * 4);
_surface->free();
delete _surface;
_surface = nullptr;
}
_width = image->getSurface()->w;
_height = image->getSurface()->h;
bool needsColorKey = false;
bool replaceAlpha = true;
if (image->getSurface()->format.bytesPerPixel == 1) {
if (!image->getPalette()) {
error("Missing palette while loading 8bit image %s", _filename);
}
_surface = image->getSurface()->convertTo(g_system->getScreenFormat(), image->getPalette(), image->getPaletteCount());
} else if (image->getSurface()->format != g_system->getScreenFormat()) {
_surface = image->getSurface()->convertTo(g_system->getScreenFormat());
} else {
_surface = new Graphics::Surface();
_surface->copyFrom(*image->getSurface());
}
_game->addMem(_width * _height * 4);
if (filename.matchString("savegame:*g", true)) {
uint8 r, g, b, a;
for (int x = 0; x < _surface->w; x++) {
for (int y = 0; y < _surface->h; y++) {
_surface->format.colorToARGB(_surface->getPixel(x, y), a, r, g, b);
uint8 grey = (uint8)((0.2126f * r + 0.7152f * g + 0.0722f * b) + 0.5f);
_surface->setPixel(x, y, _surface->format.ARGBToColor(a, grey, grey, grey));
}
}
}
if (filename.hasSuffix(".bmp")) {
// Ignores alpha channel for BMPs
needsColorKey = true;
} else if (filename.hasSuffix(".jpg")) {
// Ignores alpha channel for JPEGs
needsColorKey = true;
} else if (BaseEngine::instance().getTargetExecutable() < WME_LITE) {
// WME 1.x always use colorkey, even for images with transparency
needsColorKey = true;
replaceAlpha = false;
} else if (BaseEngine::instance().isFoxTail()) {
// FoxTail does not use colorkey
needsColorKey = false;
} else if (image->getSurface()->format.aBits() == 0) {
// generic WME Lite does not use colorkey for non-BMPs with transparency
needsColorKey = true;
}
if (needsColorKey) {
// We set the pixel color to transparent black,
// like D3DX, if it matches the color key.
bool applied = _surface->applyColorKey(_ckRed, _ckGreen, _ckBlue, replaceAlpha, 0, 0, 0);
if (replaceAlpha || image->getSurface()->format.aBits() == 0 || image->getSurface()->format.isCLUT8())
_alphaType = applied ? Graphics::ALPHA_BINARY : Graphics::ALPHA_OPAQUE;
else
_alphaType = _surface->detectAlpha();
} else {
_alphaType = image->getSurface()->detectAlpha();
}
_valid = true;
delete image;
// Bug #6572 WME: Rosemary - Sprite flaw on going upwards
// Some Rosemary sprites have non-fully transparent pixels
// In original WME it wasn't seen because sprites were downscaled
// Let's set alpha to 0 if it is smaller then some treshold
if (BaseEngine::instance().getGameId() == "rosemary" && filename.hasPrefix("actors") &&
_alphaType == Graphics::ALPHA_FULL && _surface->format.aBits() > 4) {
uint32 mask = _surface->format.ARGBToColor(255, 0, 0, 0);
uint32 treshold = _surface->format.ARGBToColor(16, 0, 0, 0);
uint32 blank = _surface->format.ARGBToColor(0, 0, 0, 0);
for (int x = 0; x < _surface->w; x++) {
for (int y = 0; y < _surface->h; y++) {
uint32 pixel = _surface->getPixel(x, y);
if ((pixel & mask) > blank && (pixel & mask) < treshold) {
_surface->setPixel(x, y, blank);
}
}
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::create(int width, int height) {
if (_valid)
_game->addMem(-_width * _height * 4);
_surface->free();
_width = width;
_height = height;
_surface->create(_width, _height, g_system->getScreenFormat());
_game->addMem(_width * _height * 4);
_valid = true;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::invalidate() {
if (_pixelOpReady) {
return STATUS_FAILED;
}
if (_valid) {
_game->addMem(-_width * _height * 4);
_surface->free();
_valid = false;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::isTransparentAtLite(int x, int y) const {
if (!_pixelOpReady) {
return false;
}
if (x < 0 || x >= _surface->w || y < 0 || y >= _surface->h) {
return true;
}
uint32 pixel = _surface->getPixel(x, y);
uint8 r, g, b, a;
_surface->format.colorToARGB(pixel, a, r, g, b);
// This implements the WME Lite logic by comparing alpha against 128.
// This differs from the original WME1 sources, where alpha is compared against 0.
// The likely reason for this discrepancy is a difference in how bitmaps are
// converted after loading.
if (a <= 128) {
return true;
} else {
return false;
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::startPixelOp() {
if (!_valid) {
if (DID_FAIL(loadImage())) {
return STATUS_FAILED;
}
}
_pixelOpReady = true;
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::endPixelOp() {
_lastUsedTime = _game->_liveTimer;
_pixelOpReady = false;
if (_surfaceModified) {
BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_game->_renderer);
renderer->invalidateTicketsFromSurface(this);
_surfaceModified = false;
}
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::display(int x, int y, Common::Rect32 rect, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
_rotation = 0;
return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct(Graphics::kDefaultZoomX, Graphics::kDefaultZoomY, mirrorX, mirrorY));
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::displayTrans(int x, int y, Common::Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
_rotation = 0;
return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct(Graphics::kDefaultZoomX, Graphics::kDefaultZoomY, Graphics::kDefaultAngle, Graphics::kDefaultHotspotX, Graphics::kDefaultHotspotY, blendMode, TS_COLOR(alpha), mirrorX, mirrorY, offsetX, offsetY));
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::displayTransZoom(int x, int y, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
_rotation = 0;
return drawSprite(x, y, &rect, nullptr, Graphics::TransformStruct((int32)zoomX, (int32)zoomY, blendMode, TS_COLOR(alpha), mirrorX, mirrorY));
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::displayTransRotate(int x, int y, float rotate, int32 hotspotX, int32 hotspotY, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
Common::Point newHotspot;
Common::Rect oldRect(rect.left, rect.top, rect.right, rect.bottom);
Graphics::TransformStruct transform = Graphics::TransformStruct(zoomX, zoomY, rotate, hotspotX, hotspotY, blendMode, TS_COLOR(alpha), mirrorX, mirrorY, 0, 0);
Common::Rect newRect = Graphics::TransformTools::newRect(oldRect, transform, &newHotspot);
Common::Rect32 newRect32(newRect.left, newRect.top, newRect.right, newRect.bottom);
x -= newHotspot.x;
y -= newHotspot.y;
_rotation = transform._angle;
if (transform._angle < 0.0f) {
warning("Negative rotation: %d %d", (int32)transform._angle, (int32)_rotation);
_rotation = 360.0f + transform._angle;
warning("Negative post rotation: %d %d", (int32)transform._angle, (int32)_rotation);
}
return drawSprite(x, y, &rect, &newRect32, transform);
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::displayTiled(int x, int y, Common::Rect32 rect, int numTimesX, int numTimesY) {
assert(numTimesX > 0 && numTimesY > 0);
Graphics::TransformStruct transform(numTimesX, numTimesY);
return drawSprite(x, y, &rect, nullptr, transform);
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::drawSprite(int x, int y, Common::Rect32 *rect, Common::Rect32 *newRect, Graphics::TransformStruct transform) {
BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_game->_renderer);
_lastUsedTime = _game->_liveTimer;
// TODO: Skip this check if we can reuse an existing ticket?
if (!_valid) {
loadImage();
}
if (renderer->_forceAlphaColor != 0) {
transform._rgbaMod = TS_COLOR(renderer->_forceAlphaColor);
}
// TODO: This _might_ miss the intended behaviour by 1 in each direction
// But I think it fits the model used in Wintermute.
Common::Rect srcRect;
srcRect.left = rect->left;
srcRect.top = rect->top;
srcRect.setWidth(rect->right - rect->left);
srcRect.setHeight(rect->bottom - rect->top);
Common::Rect position;
if (newRect) {
position.top = y;
position.left = x;
position.setWidth(newRect->width());
position.setHeight(newRect->height());
} else {
Common::Rect r;
r.top = 0;
r.left = 0;
r.setWidth(rect->width());
r.setHeight(rect->height());
r = Graphics::TransformTools::newRect(r, transform, 0);
position.top = r.top + y + transform._offset.y;
position.left = r.left + x + transform._offset.x;
position.setWidth(r.width() * transform._numTimesX);
position.setHeight(r.height() * transform._numTimesY);
}
renderer->modTargetRect(&position);
// TODO: This actually requires us to have the SAME source-offsets every time,
// But no checking is in place for that yet.
// Optimize by not doing alpha-blits if we lack alpha
// If angle is not 0, then transparent regions are added near the corners
if (_alphaType == Graphics::ALPHA_OPAQUE && _alphaMaskType == Graphics::ALPHA_OPAQUE &&
transform._angle == 0) {
transform._alphaDisable = true;
}
renderer->drawSurface(this, _surface, &srcRect, &position, transform);
return STATUS_OK;
}
bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAlpha) {
_surface->copyRectToSurface(surface, 0, 0, Common::Rect(surface.w, surface.h));
writeAlpha(_surface, _alphaMask);
if (hasAlpha) {
_alphaType = _surface->detectAlpha();
} else {
_alphaType = _alphaMaskType;
}
BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_game->_renderer);
renderer->invalidateTicketsFromSurface(this);
return STATUS_OK;
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceOSystem::setAlphaImage(const char *filename) {
BaseImage *alphaImage = new BaseImage();
if (!alphaImage->loadFile(filename)) {
delete alphaImage;
return false;
}
if (_alphaMask) {
_alphaMask->free();
delete _alphaMask;
_alphaMask = nullptr;
}
_alphaMaskType = alphaImage->getSurface()->detectAlpha();
if (_alphaMaskType != Graphics::ALPHA_OPAQUE) {
_alphaMask = alphaImage->getSurface()->convertTo(g_system->getScreenFormat());
}
delete alphaImage;
return true;
}
void BaseSurfaceOSystem::writeAlpha(Graphics::Surface *surface, const Graphics::Surface *mask) {
if (mask && surface->w == mask->w && surface->h == mask->h) {
assert(mask->pitch == mask->w * 4);
assert(mask->format.bytesPerPixel == 4);
assert(surface->pitch == surface->w * 4);
assert(surface->format.bytesPerPixel == 4);
const byte *alphaData = (const byte *)mask->getPixels();
#ifdef SCUMM_LITTLE_ENDIAN
int alphaPlace = (mask->format.aShift / 8);
#else
int alphaPlace = 3 - (mask->format.aShift / 8);
#endif
alphaData += alphaPlace;
byte *imgData = (byte *)surface->getPixels();
#ifdef SCUMM_LITTLE_ENDIAN
imgData += (surface->format.aShift / 8);
#else
imgData += 3 - (surface->format.aShift / 8);
#endif
for (int i = 0; i < surface->w * surface->h; i++) {
*imgData = *alphaData;
alphaData += 4;
imgData += 4;
}
}
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,107 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_BASE_SURFACESDL_H
#define WINTERMUTE_BASE_SURFACESDL_H
#include "graphics/surface.h"
#include "graphics/transform_struct.h" // for Graphics::AlphaType
#include "engines/wintermute/base/gfx/base_surface.h"
#include "common/list.h"
namespace Wintermute {
class BaseImage;
class BaseSurfaceOSystem : public BaseSurface {
public:
BaseSurfaceOSystem(BaseGame *inGame);
~BaseSurfaceOSystem() override;
bool create(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) override;
bool create(int width, int height) override;
bool setAlphaImage(const char *filename) override;
bool invalidate() override;
bool isTransparentAtLite(int x, int y) const override;
bool startPixelOp() override;
bool endPixelOp() override;
bool displayTransRotate(int x, int y, float rotate, int32 hotspotX, int32 hotspotY, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTransZoom(int x, int y, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTrans(int x, int y, Common::Rect32 rect, uint32 alpha = Graphics::kDefaultRgbaMod, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override;
bool display(int x, int y, Common::Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTiled(int x, int y, Common::Rect32 rect, int numTimesX, int numTimesY) override;
bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override;
int getWidth() override {
return _width;
}
int getHeight() override {
return _height;
}
bool putPixel(int x, int y, byte r, byte g, byte b, byte a) override {
if (!_pixelOpReady) {
return STATUS_FAILED;
}
if (_surface) {
_surface->setPixel(x, y, _surface->format.ARGBToColor(a, r, g, b));
_surfaceModified = true;
return STATUS_OK;
}
return STATUS_FAILED;
}
bool getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a) const override {
if (!_pixelOpReady) {
return STATUS_FAILED;
}
if (_surface) {
_surface->format.colorToARGB(_surface->getPixel(x, y), *a, *r, *g, *b);
return STATUS_OK;
}
return STATUS_FAILED;
}
Graphics::AlphaType getAlphaType() const { return _alphaType; }
private:
Graphics::Surface *_surface;
bool loadImage();
bool drawSprite(int x, int y, Common::Rect32 *rect, Common::Rect32 *newRect, Graphics::TransformStruct transformStruct);
void writeAlpha(Graphics::Surface *surface, const Graphics::Surface *mask);
bool _pixelOpReady;
bool _surfaceModified;
float _rotation;
Graphics::AlphaType _alphaType;
Graphics::Surface *_alphaMask;
Graphics::AlphaType _alphaMaskType;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,201 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/gfx/osystem/render_ticket.h"
#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h"
#include "graphics/managed_surface.h"
#include "common/textconsole.h"
namespace Wintermute {
RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf,
Common::Rect *srcRect, Common::Rect *dstRect, Graphics::TransformStruct transform) :
_owner(owner),
_srcRect(*srcRect),
_dstRect(*dstRect),
_isValid(true),
_wantsDraw(true),
_transform(transform) {
if (surf) {
assert(surf->format.bytesPerPixel == 4);
// Get a clipped view of the surface
const Graphics::Surface temp = surf->getSubArea(*srcRect);
// Then copy and scale it as necessary
//
// NB: The numTimesX/numTimesY properties don't yet mix well with
// scaling and rotation, but there is no need for that functionality at
// the moment.
// NB: Mirroring and rotation are probably done in the wrong order.
// (Mirroring should most likely be done before rotation. See also
// TransformTools.)
if (_transform._angle != Graphics::kDefaultAngle) {
_surface = temp.rotoscale(transform, owner->_game->getBilinearFiltering());
} else if ((dstRect->width() != srcRect->width() ||
dstRect->height() != srcRect->height()) &&
_transform._numTimesX * _transform._numTimesY == 1) {
_surface = temp.scale(dstRect->width(), dstRect->height(), owner->_game->getBilinearFiltering());
} else {
_surface = new Graphics::Surface();
_surface->copyFrom(temp);
}
} else {
_surface = nullptr;
}
}
RenderTicket::~RenderTicket() {
if (_surface) {
_surface->free();
delete _surface;
}
}
bool RenderTicket::operator==(const RenderTicket &t) const {
if ((t._owner != _owner) ||
(t._transform != _transform) ||
(t._dstRect != _dstRect) ||
(t._srcRect != _srcRect)
) {
return false;
}
return true;
}
// Replacement for SDL2's SDL_RenderCopy
void RenderTicket::drawToSurface(Graphics::ManagedSurface *_targetSurface) const {
if (!getSurface()) {
_targetSurface->blendFillRect(_dstRect, _transform._rgbaMod, Graphics::BLEND_NORMAL);
return;
}
Common::Rect clipRect;
clipRect.setWidth(getSurface()->w);
clipRect.setHeight(getSurface()->h);
Graphics::AlphaType alphaMode = Graphics::ALPHA_FULL;
if (_owner) {
if (_transform._alphaDisable) {
alphaMode = Graphics::ALPHA_OPAQUE;
} else if (_transform._angle) {
alphaMode = Graphics::ALPHA_FULL;
} else {
alphaMode = _owner->getAlphaType();
}
}
int y = _dstRect.top;
int w = _dstRect.width() / _transform._numTimesX;
int h = _dstRect.height() / _transform._numTimesY;
for (int ry = 0; ry < _transform._numTimesY; ++ry) {
int x = _dstRect.left;
for (int rx = 0; rx < _transform._numTimesX; ++rx) {
_targetSurface->blendBlitFrom(*getSurface(), clipRect, Common::Point(x, y),
_transform._flip, _transform._rgbaMod, Graphics::BLEND_NORMAL, alphaMode);
x += w;
}
y += h;
}
}
void RenderTicket::drawToSurface(Graphics::ManagedSurface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const {
if (!getSurface()) {
_targetSurface->blendFillRect(*dstRect, _transform._rgbaMod, _transform._blendMode);
return;
}
bool doDelete = false;
if (!clipRect) {
doDelete = true;
clipRect = new Common::Rect();
clipRect->setWidth(getSurface()->w * _transform._numTimesX);
clipRect->setHeight(getSurface()->h * _transform._numTimesY);
}
Graphics::AlphaType alphaMode = Graphics::ALPHA_FULL;
if (_owner) {
if (_transform._alphaDisable) {
alphaMode = Graphics::ALPHA_OPAQUE;
} else if (_transform._angle) {
alphaMode = Graphics::ALPHA_FULL;
} else {
alphaMode = _owner->getAlphaType();
}
}
if (_transform._numTimesX * _transform._numTimesY == 1) {
_targetSurface->blendBlitFrom(*getSurface(), *clipRect, Common::Point(dstRect->left, dstRect->top),
_transform._flip, _transform._rgbaMod, _transform._blendMode, alphaMode);
} else {
// clipRect is a subrect of the full numTimesX*numTimesY rect
Common::Rect subRect;
int y = 0;
int w = getSurface()->w;
int h = getSurface()->h;
assert(w == _dstRect.width() / _transform._numTimesX);
assert(h == _dstRect.height() / _transform._numTimesY);
int basex = dstRect->left - clipRect->left;
int basey = dstRect->top - clipRect->top;
for (int ry = 0; ry < _transform._numTimesY; ++ry) {
int x = 0;
for (int rx = 0; rx < _transform._numTimesX; ++rx) {
subRect.left = x;
subRect.top = y;
subRect.setWidth(w);
subRect.setHeight(h);
if (subRect.intersects(*clipRect)) {
subRect.clip(*clipRect);
subRect.translate(-x, -y);
_targetSurface->blendBlitFrom(*getSurface(), subRect,
Common::Point(basex + x + subRect.left, basey + y + subRect.top),
_transform._flip, _transform._rgbaMod, _transform._blendMode, alphaMode);
}
x += w;
}
y += h;
}
}
if (doDelete) {
delete clipRect;
}
}
} // End of namespace Wintermute

View File

@@ -0,0 +1,79 @@
/* 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 Lite.
* http://dead-code.org/redir.php?target=wmelite
* Copyright (c) 2011 Jan Nedoma
*/
#ifndef WINTERMUTE_RENDER_TICKET_H
#define WINTERMUTE_RENDER_TICKET_H
#include "graphics/managed_surface.h"
#include "common/rect.h"
namespace Wintermute {
class BaseSurfaceOSystem;
/**
* A single RenderTicket.
* A render ticket is a collection of the data and draw specifications made
* for a single draw-call in the OSystem-backend for WME. The ticket additionally
* holds the order in which this call was made, so that it can be detected if
* the same call is done in the following frame. Thus allowing us to potentially
* skip drawing the same region again, unless anything has changed. Since a surface
* can have a potentially large amount of draw-calls made to it, at varying rotation,
* zoom, and crop-levels we also need to hold a copy of the necessary data.
* (Video-surfaces may even change their data). The promise that is made when a ticket
* is created is that what the state was of the surface at THAT point, is what will end
* up on screen at flip() time.
*/
class RenderTicket {
public:
RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *surf, Common::Rect *srcRect, Common::Rect *dstRest, Graphics::TransformStruct transform);
RenderTicket() : _isValid(true), _wantsDraw(false), _transform(Graphics::TransformStruct()) {}
~RenderTicket();
const Graphics::Surface *getSurface() const { return _surface; }
// Non-dirty-rects:
void drawToSurface(Graphics::ManagedSurface *_targetSurface) const;
// Dirty-rects:
void drawToSurface(Graphics::ManagedSurface *_targetSurface, Common::Rect *dstRect, Common::Rect *clipRect) const;
Common::Rect _dstRect;
bool _isValid;
bool _wantsDraw;
Graphics::TransformStruct _transform;
BaseSurfaceOSystem *_owner;
bool operator==(const RenderTicket &a) const;
const Common::Rect *getSrcRect() const { return &_srcRect; }
private:
Graphics::Surface *_surface;
Common::Rect _srcRect;
};
} // End of namespace Wintermute
#endif

View File

@@ -0,0 +1,90 @@
/* 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/dcgf.h"
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
#include "engines/wintermute/base/gfx/xskinmesh.h"
#include "engines/wintermute/base/gfx/xfile_loader.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
SkinMeshHelper::SkinMeshHelper(DXMesh *mesh, DXSkinInfo *skinInfo) {
_mesh = mesh;
_skinInfo = skinInfo;
}
//////////////////////////////////////////////////////////////////////////
SkinMeshHelper::~SkinMeshHelper() {
SAFE_DELETE(_mesh);
SAFE_DELETE(_skinInfo);
}
//////////////////////////////////////////////////////////////////////////
uint SkinMeshHelper::getNumFaces() {
return _mesh->getNumFaces();
}
//////////////////////////////////////////////////////////////////////////
uint SkinMeshHelper::getNumBones() {
return _skinInfo->getNumBones();
}
//////////////////////////////////////////////////////////////////////////
bool SkinMeshHelper::getOriginalMesh(DXMesh **mesh) {
return _mesh->cloneMesh(mesh);
}
//////////////////////////////////////////////////////////////////////////
bool SkinMeshHelper::generateSkinnedMesh(uint32 *adjacencyOut, DXMesh **mesh) {
bool res = getOriginalMesh(mesh);
if (res) {
(*mesh)->generateAdjacency(adjacencyOut);
}
return res;
}
//////////////////////////////////////////////////////////////////////////
bool SkinMeshHelper::updateSkinnedMesh(const DXMatrix *boneTransforms, DXMesh *mesh) {
void *sourceVerts = reinterpret_cast<void *>(_mesh->getVertexBuffer().ptr());
void *targetVerts = reinterpret_cast<void *>(mesh->getVertexBuffer().ptr());
return _skinInfo->updateSkinnedMesh(boneTransforms, sourceVerts, targetVerts);
}
//////////////////////////////////////////////////////////////////////////
const char *SkinMeshHelper::getBoneName(uint32 boneIndex) {
return _skinInfo->getBoneName(boneIndex);
}
//////////////////////////////////////////////////////////////////////////
DXMatrix *SkinMeshHelper::getBoneOffsetMatrix(uint32 boneIndex) {
return _skinInfo->getBoneOffsetMatrix(boneIndex);
}
} // namespace Wintermute

View File

@@ -0,0 +1,65 @@
/* 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
*/
#ifndef WINTERMUTE_SKIN_MESH_HELPER_H
#define WINTERMUTE_SKIN_MESH_HELPER_H
#include "engines/wintermute/base/gfx/xmath.h"
namespace Wintermute {
class XMesh;
class XMeshOpenGL;
class XMeshOpenGLShader;
class DXMesh;
class DXSkinInfo;
class SkinMeshHelper {
friend class XMesh;
friend class XMeshOpenGL;
friend class XMeshOpenGLShader;
public:
SkinMeshHelper(DXMesh *mesh, DXSkinInfo *skinInfo);
virtual ~SkinMeshHelper();
uint getNumFaces();
uint getNumBones();
bool getOriginalMesh(DXMesh **mesh);
bool generateSkinnedMesh(uint32 *adjacencyOut, DXMesh **mesh);
bool updateSkinnedMesh(const DXMatrix *boneTransforms, DXMesh *mesh);
const char *getBoneName(uint32 boneIndex);
DXMatrix *getBoneOffsetMatrix(uint32 boneIndex);
private:
DXMesh *_mesh;
DXSkinInfo *_skinInfo;
};
} // namespace Wintermute
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,176 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_BASE_RENDER_TINYGL_H
#define WINTERMUTE_BASE_RENDER_TINYGL_H
#include "engines/wintermute/base/gfx/base_renderer3d.h"
#include "engines/wintermute/dctypes.h"
#include "graphics/transform_struct.h"
#include "graphics/tinygl/tinygl.h"
#if defined(USE_TINYGL)
namespace Wintermute {
class BaseSurfaceTinyGL;
class BaseRenderTinyGL : public BaseRenderer3D {
friend class BaseSurfaceTinyGL;
friend class Mesh3DSTinyGL;
friend class XMeshTinyGL;
friend class ShadowVolumeTinyGL;
struct SpriteVertex {
float x;
float y;
float z;
float u;
float v;
float r;
float g;
float b;
float a;
};
struct RectangleVertex {
float x;
float y;
float z;
};
struct SimpleShadowVertex {
float nx;
float ny;
float nz;
float x;
float y;
float z;
float u;
float v;
};
public:
BaseRenderTinyGL(BaseGame *inGame = nullptr);
~BaseRenderTinyGL() override;
bool invalidateTexture(BaseSurface *texture) override;
bool invalidateDeviceObjects() override;
bool restoreDeviceObjects() override;
bool resetDevice() override;
void setSpriteBlendMode(Graphics::TSpriteBlendMode blendMode, bool forceChange = false) override;
void setAmbientLightRenderState() override;
int getMaxActiveLights() override;
void lightEnable(int index, bool enable) override;
void setLightParameters(int index, const DXVector3 &position, const DXVector3 &direction, const DXVector4 &diffuse, bool spotlight) override;
void enableCulling() override;
void disableCulling() override;
bool enableShadows() override;
bool disableShadows() override;
bool shadowVolumeSupported() override;
BaseImage *takeScreenshot(int newWidth = 0, int newHeight = 0) override;
bool fadeToColor(byte r, byte g, byte b, byte a) override;
bool flip() override;
bool clear() override;
bool setViewport(int left, int top, int right, int bottom) override;
bool drawLine(int x1, int y1, int x2, int y2, uint32 color) override;
bool fillRect(int x, int y, int w, int h, uint32 color) override;
DXMatrix *buildMatrix(DXMatrix* out, const DXVector2 *centre, const DXVector2 *scaling, float angle);
void transformVertices(struct SpriteVertex *vertices, const DXVector2 *centre, const DXVector2 *scaling, float angle);
bool setProjection() override;
bool setProjection2D();
bool setWorldTransform(const DXMatrix &transform) override;
bool setViewTransform(const DXMatrix &transform) override;
bool setProjectionTransform(const DXMatrix &transform) override;
bool initRenderer(int width, int height, bool windowed) override;
bool setup2D(bool force = false) override;
bool setup3D(Camera3D *camera, bool force = false) override;
Common::String getName() const override {
return "TinyGL software renderer";
};
bool displayDebugInfo() override {
return STATUS_FAILED;
};
bool drawShaderQuad() override {
return STATUS_FAILED;
}
float getScaleRatioX() const override {
return 1.0f;
}
float getScaleRatioY() const override {
return 1.0f;
}
BaseSurface *createSurface() override;
bool startSpriteBatch() override;
bool endSpriteBatch() override;
bool commitSpriteBatch() override;
bool drawSpriteEx(BaseSurface *texture, const Common::Rect32 &rect, const DXVector2 &pos, const DXVector2 &rot, const DXVector2 &scale,
float angle, uint32 color, bool alphaDisable, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) override;
void renderSceneGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks,
const BaseArray<AdGeneric *> &generics, const BaseArray<Light3D *> &lights, Camera3D *camera) override;
void renderShadowGeometry(const BaseArray<AdWalkplane *> &planes, const BaseArray<AdBlock *> &blocks, const BaseArray<AdGeneric *> &generics, Camera3D *camera) override;
Mesh3DS *createMesh3DS() override;
XMesh *createXMesh() override;
ShadowVolume *createShadowVolume() override;
bool setViewport3D(DXViewport *viewport) override;
void postfilter() override;
void setPostfilter(PostFilter postFilter) override { _postFilterMode = postFilter; };
private:
bool setupLines();
void displaySimpleShadow(BaseObject *object) override;
Graphics::TSpriteBlendMode _blendMode;
SimpleShadowVertex _simpleShadow[4];
Common::Array<DXVector4> _lightPositions;
Common::Array<DXVector3> _lightDirections;
//TGLuint _postfilterTexture;
bool _shadowVolumesSupported;
};
} // wintermute namespace
#endif // defined(USE_TINYGL)
#endif

View File

@@ -0,0 +1,462 @@
/* 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/>.
*
*/
#include "common/algorithm.h"
#include "graphics/transform_tools.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/gfx/base_image.h"
#if defined(USE_TINYGL)
#include "engines/wintermute/base/gfx/3dutils.h"
#include "engines/wintermute/base/gfx/tinygl/base_surface_tinygl.h"
#include "engines/wintermute/base/gfx/tinygl/base_render_tinygl.h"
namespace Wintermute {
BaseSurfaceTinyGL::BaseSurfaceTinyGL(BaseGame *game, BaseRenderer3D *renderer)
: BaseSurface(game), _tex(0), _renderer(renderer), _imageData(nullptr), _maskData(nullptr), _pixelOpReady(false), _surfaceModified(false), _texture2D(true) {
_blitImage = tglGenBlitImage();
}
BaseSurfaceTinyGL::~BaseSurfaceTinyGL() {
_renderer->invalidateTexture(this);
if (_tex) {
tglDeleteTextures(1, &_tex);
_tex = 0;
}
if (_imageData) {
_imageData->free();
delete _imageData;
_imageData = nullptr;
}
if (_maskData) {
_maskData->free();
delete _maskData;
_maskData = nullptr;
}
tglDeleteBlitImage(_blitImage);
}
bool BaseSurfaceTinyGL::invalidate() {
_renderer->invalidateTexture(this);
if (_tex) {
tglDeleteTextures(1, &_tex);
_tex = 0;
}
if (_imageData) {
_imageData->free();
delete _imageData;
_imageData = nullptr;
}
_valid = false;
_surfaceModified = false;
return true;
}
bool BaseSurfaceTinyGL::prepareToDraw() {
_lastUsedTime = _game->_liveTimer;
if (!_valid) {
loadImage();
}
return true;
}
bool BaseSurfaceTinyGL::displayTransZoom(int x, int y, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
prepareToDraw();
_renderer->drawSprite(dynamic_cast<BaseSurface *>(this), rect, zoomX, zoomY, DXVector2(x, y), alpha, false, blendMode, mirrorX, mirrorY);
return true;
}
bool BaseSurfaceTinyGL::displayTrans(int x, int y, Common::Rect32 rect, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
prepareToDraw();
_renderer->drawSprite(dynamic_cast<BaseSurface *>(this), rect, 100, 100, DXVector2(x + offsetX, y + offsetY), alpha, false, blendMode, mirrorX, mirrorY);
return true;
}
bool BaseSurfaceTinyGL::display(int x, int y, Common::Rect32 rect, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
prepareToDraw();
_renderer->drawSprite(dynamic_cast<BaseSurface *>(this), rect, 100, 100, DXVector2(x, y), 0xFFFFFFFF, true, blendMode, mirrorX, mirrorY);
return true;
}
bool BaseSurfaceTinyGL::displayTransRotate(int x, int y, float rotate, int32 hotspotX, int32 hotspotY, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha, Graphics::TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY) {
prepareToDraw();
x -= hotspotX;
y -= hotspotY;
DXVector2 position(x, y);
DXVector2 rotation;
rotation._x = x + hotspotX * (zoomX / 100.0f);
rotation._y = y + hotspotY * (zoomY / 100.0f);
DXVector2 scale(zoomX / 100.0f, zoomY / 100.0f);
float angle = degToRad(rotate);
_renderer->drawSpriteEx(dynamic_cast<BaseSurface *>(this), rect, position, rotation, scale, angle, alpha, false, blendMode, mirrorX, mirrorY);
return true;
}
bool BaseSurfaceTinyGL::displayTiled(int x, int y, Common::Rect32 rect, int numTimesX, int numTimesY) {
prepareToDraw();
DXVector2 scale(numTimesX, numTimesY);
_renderer->drawSpriteEx(dynamic_cast<BaseSurface *>(this), rect, DXVector2(x, y), DXVector2(0, 0), scale, 0, 0xFFFFFFFF, false, Graphics::BLEND_NORMAL, false, false);
return true;
}
bool BaseSurfaceTinyGL::create(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime, bool keepLoaded) {
if (defaultCK) {
ckRed = 255;
ckGreen = 0;
ckBlue = 255;
}
_texture2D = texture2D;
Common::String surfacefilename = filename;
BaseImage img = BaseImage();
if (!img.getImageInfo(surfacefilename, _width, _height)) {
return false;
}
if (lifeTime != -1 && _lifeTime == 0) {
_valid = false;
}
_ckDefault = defaultCK;
_ckRed = ckRed;
_ckGreen = ckGreen;
_ckBlue = ckBlue;
if (!_filename || scumm_stricmp(_filename, filename) != 0) {
setFilename(filename);
}
if (_lifeTime == 0 || lifeTime == -1 || lifeTime > _lifeTime) {
_lifeTime = lifeTime;
}
_keepLoaded = keepLoaded;
if (_keepLoaded) {
_lifeTime = -1;
}
return true;
}
bool BaseSurfaceTinyGL::loadImage() {
if (!_filename || !_filename[0]) {
return false;
}
Common::String filename = _filename;
BaseImage img = BaseImage();
if (!img.loadFile(filename)) {
return false;
}
if (img.getSurface()->format.bytesPerPixel == 1 && img.getPalette() == nullptr) {
return false;
}
bool needsColorKey = false;
bool replaceAlpha = true;
if (_imageData) {
_imageData->free();
delete _imageData;
_imageData = nullptr;
}
_imageData = img.getSurface()->convertTo(Graphics::PixelFormat::createFormatRGBA32(), img.getPalette(), img.getPaletteCount());
if (filename.matchString("savegame:*g", true)) {
uint8 r, g, b, a;
for (int x = 0; x < _imageData->w; x++) {
for (int y = 0; y < _imageData->h; y++) {
_imageData->format.colorToARGB(_imageData->getPixel(x, y), a, r, g, b);
uint8 grey = (uint8)((0.2126f * r + 0.7152f * g + 0.0722f * b) + 0.5f);
_imageData->setPixel(x, y, _imageData->format.ARGBToColor(a, grey, grey, grey));
}
}
}
if (filename.hasSuffix(".bmp")) {
// Ignores alpha channel for BMPs
needsColorKey = true;
} else if (filename.hasSuffix(".jpg")) {
// Ignores alpha channel for JPEGs
needsColorKey = true;
} else if (BaseEngine::instance().getTargetExecutable() < WME_LITE) {
// WME 1.x always use colorkey, even for images with transparency
needsColorKey = true;
replaceAlpha = false;
} else if (BaseEngine::instance().isFoxTail()) {
// FoxTail does not use colorkey
needsColorKey = false;
} else if (img.getSurface()->format.aBits() == 0) {
// generic WME Lite does not use colorkey for non-BMPs with transparency
needsColorKey = true;
}
if (needsColorKey) {
// We set the pixel color to transparent black,
// like D3DX, if it matches the color key.
_imageData->applyColorKey(_ckRed, _ckGreen, _ckBlue, replaceAlpha, 0, 0, 0);
}
// Bug #6572 WME: Rosemary - Sprite flaw on going upwards
// Some Rosemary sprites have non-fully transparent pixels
// In original WME it wasn't seen because sprites were downscaled
// Let's set alpha to 0 if it is smaller then some treshold
if (BaseEngine::instance().getGameId() == "rosemary" && filename.hasPrefix("actors") && _imageData->format.bytesPerPixel == 4) {
uint32 mask = _imageData->format.ARGBToColor(255, 0, 0, 0);
uint32 treshold = _imageData->format.ARGBToColor(16, 0, 0, 0);
uint32 blank = _imageData->format.ARGBToColor(0, 0, 0, 0);
for (int x = 0; x < _imageData->w; x++) {
for (int y = 0; y < _imageData->h; y++) {
uint32 pixel = _imageData->getPixel(x, y);
if ((pixel & mask) > blank && (pixel & mask) < treshold) {
_imageData->setPixel(x, y, blank);
}
}
}
}
putSurface(*_imageData);
/* TODO: Delete _imageData if we no longer need to access the pixel data? */
_valid = true;
return true;
}
bool BaseSurfaceTinyGL::create(int width, int height) {
_width = width;
_height = height;
_valid = true;
return true;
}
bool BaseSurfaceTinyGL::putSurface(const Graphics::Surface &surface, bool hasAlpha) {
if (!_imageData) {
_imageData = new Graphics::Surface();
}
if (_imageData && _imageData != &surface) {
_imageData->copyFrom(surface);
writeAlpha(_imageData, _maskData);
}
_width = surface.w;
_height = surface.h;
if (_texture2D) {
tglUploadBlitImage(_blitImage, *_imageData, 0, false);
} else {
if (!_valid) {
tglGenTextures(1, &_tex);
}
_texWidth = Common::nextHigher2(_width);
_texHeight = Common::nextHigher2(_height);
tglBindTexture(TGL_TEXTURE_2D, _tex);
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_S, TGL_REPEAT);
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_WRAP_T, TGL_REPEAT);
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MIN_FILTER, TGL_LINEAR);
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MAG_FILTER, TGL_LINEAR);
tglTexImage2D(TGL_TEXTURE_2D, 0, TGL_RGBA, _width, _height, 0, TGL_RGBA, TGL_UNSIGNED_BYTE, _imageData->getPixels());
tglBindTexture(TGL_TEXTURE_2D, 0);
}
_valid = true;
return true;
}
bool BaseSurfaceTinyGL::putPixel(int x, int y, byte r, byte g, byte b, byte a) {
if (!_pixelOpReady) {
return false;
}
if (x < 0 || y < 0 || x >= _width || y >= _height) {
return false;
}
if (_imageData == nullptr) {
return false;
}
_imageData->setPixel(x, y, _imageData->format.ARGBToColor(a, r, g, b));
_surfaceModified = true;
return true;
}
bool BaseSurfaceTinyGL::getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a) const {
if (!_pixelOpReady) {
return false;
}
if (x < 0 || y < 0 || x >= _width || y >= _height) {
return false;
}
if (_imageData == nullptr) {
return false;
}
uint8 alpha, red, green, blue;
_imageData->format.colorToARGB(_imageData->getPixel(x, y), alpha, red, green, blue);
*r = red;
*g = green;
*b = blue;
*a = alpha;
return true;
}
bool BaseSurfaceTinyGL::startPixelOp() {
if (!prepareToDraw())
return false;
_pixelOpReady = true;
return true;
}
bool BaseSurfaceTinyGL::endPixelOp() {
_pixelOpReady = false;
if (_surfaceModified) {
if (_texture2D) {
tglUploadBlitImage(_blitImage, *_imageData, 0, false);
} else {
tglBindTexture(TGL_TEXTURE_2D, _tex);
tglTexImage2D(TGL_TEXTURE_2D, 0, TGL_RGBA, _width, _height, 0, TGL_RGBA, TGL_UNSIGNED_BYTE, _imageData->getPixels());
tglBindTexture(TGL_TEXTURE_2D, 0);
}
_surfaceModified = false;
}
return true;
}
bool BaseSurfaceTinyGL::isTransparentAtLite(int x, int y) const {
if (!_pixelOpReady) {
return false;
}
if (x < 0 || y < 0 || x >= _width || y >= _height) {
return false;
}
if (_imageData == nullptr) {
return false;
}
uint8 a, r, g, b;
_imageData->format.colorToARGB(_imageData->getPixel(x, y), a, r, g, b);
// Keep behavior in sync with the 2D renderer, which implements the WME Lite logic
// by comparing alpha against 128.
// This differs from the original WME1 sources, where alpha is compared against 0.
// The likely reason for this discrepancy is a difference in how bitmaps are
// converted after loading.
if (a <= 128) {
return true;
} else {
return false;
}
}
void BaseSurfaceTinyGL::setTexture() {
prepareToDraw();
if (!_texture2D) {
tglBindTexture(TGL_TEXTURE_2D, _tex);
}
}
//////////////////////////////////////////////////////////////////////////
bool BaseSurfaceTinyGL::setAlphaImage(const char *filename) {
BaseImage *alphaImage = new BaseImage();
if (!alphaImage->loadFile(filename)) {
delete alphaImage;
return false;
}
if (_maskData) {
_maskData->free();
delete _maskData;
_maskData = nullptr;
}
Graphics::AlphaType type = alphaImage->getSurface()->detectAlpha();
if (type != Graphics::ALPHA_OPAQUE) {
_maskData = alphaImage->getSurface()->convertTo(Graphics::PixelFormat::createFormatRGBA32());
}
delete alphaImage;
return true;
}
void BaseSurfaceTinyGL::writeAlpha(Graphics::Surface *surface, const Graphics::Surface *mask) {
if (mask && surface->w == mask->w && surface->h == mask->h) {
assert(mask->pitch == mask->w * 4);
assert(mask->format.bytesPerPixel == 4);
assert(surface->pitch == surface->w * 4);
assert(surface->format.bytesPerPixel == 4);
const byte *alphaData = (const byte *)mask->getPixels();
#ifdef SCUMM_LITTLE_ENDIAN
int alphaPlace = (mask->format.aShift / 8);
#else
int alphaPlace = 3 - (mask->format.aShift / 8);
#endif
alphaData += alphaPlace;
byte *imgData = (byte *)surface->getPixels();
#ifdef SCUMM_LITTLE_ENDIAN
imgData += (surface->format.aShift / 8);
#else
imgData += 3 - (surface->format.aShift / 8);
#endif
for (int i = 0; i < surface->w * surface->h; i++) {
*imgData = *alphaData;
alphaData += 4;
imgData += 4;
}
}
}
} // End of namespace Wintermute
#endif // defined(USE_TINYGL)

View File

@@ -0,0 +1,101 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_BASE_SURFACE_TINYGL_H
#define WINTERMUTE_BASE_SURFACE_TINYGL_H
#include "engines/wintermute/base/gfx/base_surface.h"
#if defined(USE_TINYGL)
#include "graphics/tinygl/tinygl.h"
namespace Wintermute {
class BaseGame;
class BaseRenderer3D;
class BaseSurfaceTinyGL : public BaseSurface {
public:
BaseSurfaceTinyGL(BaseGame *game, BaseRenderer3D *renderer);
~BaseSurfaceTinyGL();
bool invalidate() override;
bool prepareToDraw() override;
bool displayTransRotate(int x, int y, float rotate, int32 hotspotX, int32 hotspotY, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTransZoom(int x, int y, Common::Rect32 rect, float zoomX, float zoomY, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTrans(int x, int y, Common::Rect32 rect, uint32 alpha = 0xFFFFFFFF, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false, int offsetX = 0, int offsetY = 0) override;
bool display(int x, int y, Common::Rect32 rect, Graphics::TSpriteBlendMode blendMode = Graphics::BLEND_NORMAL, bool mirrorX = false, bool mirrorY = false) override;
bool displayTiled(int x, int y, Common::Rect32 rect, int numTimesX, int numTimesY) override;
bool create(const char *filename, bool texture2D, bool defaultCK, byte ckRed, byte ckGreen, byte ckBlue, int lifeTime = -1, bool keepLoaded = false) override;
bool create(int width, int height) override;
bool setAlphaImage(const char *filename) override;
bool putSurface(const Graphics::Surface &surface, bool hasAlpha = false) override;
bool putPixel(int x, int y, byte r, byte g, byte b, byte a) override;
bool getPixel(int x, int y, byte *r, byte *g, byte *b, byte *a = nullptr) const override;
bool startPixelOp() override;
bool endPixelOp() override;
bool isTransparentAtLite(int x, int y) const override;
void setTexture();
int getWidth() override {
return _width;
}
int getHeight() override {
return _height;
}
uint getGLTextureWidth() const {
return _texWidth;
}
uint getGLTextureHeight() const {
return _texHeight;
}
TinyGL::BlitImage *getBlitImage() {
return _blitImage;
}
private:
TGLuint _tex;
BaseRenderer3D *_renderer;
Graphics::Surface *_imageData;
Graphics::Surface *_maskData;
uint _texWidth{};
uint _texHeight{};
bool _pixelOpReady;
bool _surfaceModified;
TinyGL::BlitImage *_blitImage;
bool _texture2D;
bool loadImage();
void writeAlpha(Graphics::Surface *surface, const Graphics::Surface *mask);
};
} // End of namespace Wintermute
#endif // defined(USE_TINYGL)
#endif

View File

@@ -0,0 +1,60 @@
/* 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/>.
*
*/
#include "engines/wintermute/wintypes.h"
#include "graphics/opengl/system_headers.h"
#if defined(USE_TINYGL)
#include "engines/wintermute/base/gfx/tinygl/mesh3ds_tinygl.h"
namespace Wintermute {
Mesh3DSTinyGL::Mesh3DSTinyGL(BaseGame *inGame) : Mesh3DS(inGame) {
_vertexCount = 0;
_vertexData = nullptr;
}
Mesh3DSTinyGL::~Mesh3DSTinyGL() {
}
void Mesh3DSTinyGL::fillVertexBuffer() {
_vertexCount = _numFaces * 3;
_vertexData = (Mesh3DSVertex *)_vb.ptr();
}
void Mesh3DSTinyGL::render(bool color) {
if (_vertexCount == 0)
return;
tglEnableClientState(TGL_VERTEX_ARRAY);
tglEnableClientState(TGL_COLOR_ARRAY);
tglVertexPointer(3, TGL_FLOAT, sizeof(Mesh3DSVertex), &_vertexData[0]._x);
tglColorPointer(4, TGL_FLOAT, sizeof(Mesh3DSVertex), &_vertexData[0]._r);
tglDrawArrays(TGL_TRIANGLES, 0, _vertexCount);
tglDisableClientState(TGL_COLOR_ARRAY);
tglDisableClientState(TGL_VERTEX_ARRAY);
}
} // namespace Wintermute
#endif // defined(USE_TINYGL)

View File

@@ -0,0 +1,49 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_MESH_TINYGL_H
#define WINTERMUTE_MESH_TINYGL_H
#include "engines/wintermute/base/gfx/3dmesh.h"
#if defined(USE_TINYGL)
#include "graphics/tinygl/tinygl.h"
namespace Wintermute {
class Mesh3DSTinyGL : public Mesh3DS {
public:
Mesh3DSTinyGL(BaseGame *inGame);
~Mesh3DSTinyGL();
void fillVertexBuffer() override;
void render(bool color) override;
private:
Mesh3DSVertex *_vertexData;
uint16 _vertexCount;
};
} // namespace Wintermute
#endif // defined(USE_TINYGL)
#endif

View File

@@ -0,0 +1,261 @@
/* 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/base/gfx/xmaterial.h"
#include "engines/wintermute/base/gfx/3deffect.h"
#include "engines/wintermute/base/gfx/3deffect_params.h"
#include "engines/wintermute/base/gfx/skin_mesh_helper.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#if defined(USE_TINYGL)
#include "engines/wintermute/base/gfx/tinygl/base_surface_tinygl.h"
#include "engines/wintermute/base/gfx/tinygl/base_render_tinygl.h"
#include "engines/wintermute/base/gfx/tinygl/meshx_tinygl.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
XMeshTinyGL::XMeshTinyGL(BaseGame *inGame) : XMesh(inGame) {
}
//////////////////////////////////////////////////////////////////////////
XMeshTinyGL::~XMeshTinyGL() {
}
//////////////////////////////////////////////////////////////////////////
bool XMeshTinyGL::render(XModel *model) {
if (!_blendedMesh)
return false;
// For WME DX, mesh model is not visible, possible it's clipped.
// For OpenGL, mesh is visible, skip draw it here instead in core.
if (!_game->_renderer3D->_camera)
return false;
auto fvf = _blendedMesh->getFVF();
uint32 vertexSize = DXGetFVFVertexSize(fvf) / sizeof(float);
float *vertexData = (float *)_blendedMesh->getVertexBuffer().ptr();
if (vertexData == nullptr) {
return false;
}
uint32 offset = 0, normalOffset = 0, textureOffset = 0;
if (fvf & DXFVF_XYZ) {
offset += sizeof(DXVector3) / sizeof(float);
}
if (fvf & DXFVF_NORMAL) {
normalOffset = offset;
offset += sizeof(DXVector3) / sizeof(float);
}
if (fvf & DXFVF_DIFFUSE) {
offset += sizeof(DXColorValue) / sizeof(float);
}
if (fvf & DXFVF_TEX1) {
textureOffset = offset;
}
uint32 *indexData = (uint32 *)_blendedMesh->getIndexBuffer().ptr();
bool noAttrs = false;
auto attrsTable = _blendedMesh->getAttributeTable();
uint32 numAttrs = attrsTable->_size;
DXAttributeRange *attrs;
if (numAttrs == 0) {
noAttrs = true;
numAttrs = 1;
attrs = new DXAttributeRange[numAttrs];
} else {
attrs = attrsTable->_ptr;
}
if (noAttrs) {
attrs[0]._attribId = 0;
attrs[0]._vertexStart = attrs[0]._faceStart = 0;
attrs[0]._vertexCount = _blendedMesh->getNumVertices();
attrs[0]._faceCount = _blendedMesh->getNumFaces();
}
for (uint32 i = 0; i < numAttrs; i++) {
Material *mat = _materials[attrs[i]._attribId];
bool textureEnable = false;
if (mat->getSurface()) {
textureEnable = true;
tglEnable(TGL_TEXTURE_2D);
static_cast<BaseSurfaceTinyGL *>(mat->getSurface())->setTexture();
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MAG_FILTER, TGL_LINEAR);
tglTexParameteri(TGL_TEXTURE_2D, TGL_TEXTURE_MIN_FILTER, TGL_LINEAR_MIPMAP_LINEAR);
} else {
tglBindTexture(TGL_TEXTURE_2D, 0);
tglDisable(TGL_TEXTURE_2D);
}
if (mat->getEffect()) {
renderEffect(mat);
} else {
tglMaterialfv(TGL_FRONT_AND_BACK, TGL_DIFFUSE, mat->_material._diffuse._data);
tglMaterialfv(TGL_FRONT_AND_BACK, TGL_AMBIENT, mat->_material._diffuse._data);
tglMaterialfv(TGL_FRONT_AND_BACK, TGL_SPECULAR, mat->_material._specular._data);
tglMaterialfv(TGL_FRONT_AND_BACK, TGL_EMISSION, mat->_material._emissive._data);
tglMaterialf(TGL_FRONT_AND_BACK, TGL_SHININESS, mat->_material._power);
}
tglEnableClientState(TGL_VERTEX_ARRAY);
tglEnableClientState(TGL_NORMAL_ARRAY);
if (textureEnable)
tglEnableClientState(TGL_TEXTURE_COORD_ARRAY);
tglVertexPointer(3, TGL_FLOAT, vertexSize * sizeof(float), vertexData);
tglNormalPointer(TGL_FLOAT, vertexSize * sizeof(float), vertexData + normalOffset);
if (textureEnable)
tglTexCoordPointer(2, TGL_FLOAT, vertexSize * sizeof(float), vertexData + textureOffset);
tglDrawElements(TGL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, TGL_UNSIGNED_INT, indexData + attrsTable->_ptr[i]._faceStart * 3);
tglDisableClientState(TGL_VERTEX_ARRAY);
tglDisableClientState(TGL_NORMAL_ARRAY);
tglDisableClientState(TGL_TEXTURE_COORD_ARRAY);
}
tglBindTexture(TGL_TEXTURE_2D, 0);
tglDisable(TGL_TEXTURE_2D);
if (noAttrs) {
delete[] attrs;
}
return true;
}
bool XMeshTinyGL::renderFlatShadowModel(uint32 shadowColor) {
if (!_blendedMesh)
return false;
// For WME DX, mesh model is not visible, possible it's clipped.
// For OpenGL, mesh is visible, skip draw it here instead in core.
if (!_game->_renderer3D->_camera)
return false;
// W/A for the scene with the table in the laboratory where the engine switches to flat shadows.
// Presumably, it's supposed to disable shadows.
// Instead, OpenGL draws graphical glitches.
// Original DX version does not have this issue due to rendering shadows differently.
if (BaseEngine::instance().getGameId() == "alphapolaris")
return false;
uint32 vertexSize = DXGetFVFVertexSize(_blendedMesh->getFVF()) / sizeof(float);
float *vertexData = (float *)_blendedMesh->getVertexBuffer().ptr();
if (vertexData == nullptr) {
return false;
}
uint32 *indexData = (uint32 *)_blendedMesh->getIndexBuffer().ptr();
bool noAttrs = false;
auto attrsTable = _blendedMesh->getAttributeTable();
uint32 numAttrs = attrsTable->_size;
DXAttributeRange *attrs;
if (numAttrs == 0) {
noAttrs = true;
numAttrs = 1;
attrs = new DXAttributeRange[numAttrs];
} else {
attrs = attrsTable->_ptr;
}
if (noAttrs) {
attrs[0]._attribId = 0;
attrs[0]._vertexStart = attrs[0]._faceStart = 0;
attrs[0]._vertexCount = _blendedMesh->getNumVertices();
attrs[0]._faceCount = _blendedMesh->getNumFaces();
}
tglBindTexture(TGL_TEXTURE_2D, 0);
tglDisable(TGL_TEXTURE_2D);
tglDisable(TGL_LIGHTING);
tglShadeModel(TGL_FLAT);
tglColorMask(TGL_FALSE, TGL_FALSE, TGL_FALSE, TGL_FALSE);
tglDepthMask(TGL_FALSE);
tglEnable(TGL_STENCIL_TEST);
tglStencilFunc(TGL_ALWAYS, 1, 0xff);
tglStencilOp(TGL_REPLACE, TGL_REPLACE, TGL_REPLACE);
for (uint32 i = 0; i < numAttrs; i++) {
tglEnableClientState(TGL_VERTEX_ARRAY);
tglVertexPointer(3, TGL_FLOAT, vertexSize * sizeof(float), vertexData);
tglDrawElements(TGL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, TGL_UNSIGNED_INT, indexData + attrsTable->_ptr[i]._faceStart * 3);
tglDisableClientState(TGL_VERTEX_ARRAY);
}
tglStencilFunc(TGL_EQUAL, 1, 0xff);
tglStencilOp(TGL_ZERO, TGL_ZERO, TGL_ZERO);
tglColor4ub(RGBCOLGetR(shadowColor), RGBCOLGetG(shadowColor), RGBCOLGetB(shadowColor), RGBCOLGetA(shadowColor));
tglColorMask(TGL_TRUE, TGL_TRUE, TGL_TRUE, TGL_TRUE);
tglEnable(TGL_BLEND);
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
tglDepthMask(TGL_TRUE);
for (uint32 i = 0; i < numAttrs; i++) {
tglEnableClientState(TGL_VERTEX_ARRAY);
tglVertexPointer(3, TGL_FLOAT, vertexSize * sizeof(float), vertexData);
tglDrawElements(TGL_TRIANGLES, attrsTable->_ptr[i]._faceCount * 3, TGL_UNSIGNED_INT, indexData + attrsTable->_ptr[i]._faceStart * 3);
tglDisableClientState(TGL_VERTEX_ARRAY);
}
if (noAttrs) {
delete[] attrs;
}
tglDisable(TGL_BLEND);
tglDisable(TGL_STENCIL_TEST);
tglShadeModel(TGL_SMOOTH);
tglEnable(TGL_LIGHTING);
return true;
}
void XMeshTinyGL::renderEffect(Material *material) {
tglMaterialfv(TGL_FRONT_AND_BACK, TGL_DIFFUSE, material->_material._diffuse._data);
tglMaterialfv(TGL_FRONT_AND_BACK, TGL_AMBIENT, material->_material._diffuse._data);
tglMaterialfv(TGL_FRONT_AND_BACK, TGL_SPECULAR, material->_material._specular._data);
tglMaterialfv(TGL_FRONT_AND_BACK, TGL_EMISSION, material->_material._emissive._data);
tglMaterialf(TGL_FRONT_AND_BACK, TGL_SHININESS, material->_material._power);
}
} // namespace Wintermute
#endif // defined(USE_TINYGL)

View File

@@ -0,0 +1,58 @@
/* 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
*/
#ifndef WINTERMUTE_XMESH_TINYGL_H
#define WINTERMUTE_XMESH_TINYGL_H
#include "engines/wintermute/base/gfx/xmesh.h"
class Effect3D;
class Effect3DParams;
#if defined(USE_TINYGL)
#include "graphics/tinygl/tinygl.h"
namespace Wintermute {
class XMeshTinyGL : public XMesh {
public:
XMeshTinyGL(BaseGame *inGame);
~XMeshTinyGL() override;
bool render(XModel *model) override;
bool renderFlatShadowModel(uint32 shadowColor) override;
private:
void renderEffect(Material *material);
};
} // namespace Wintermute
#endif // defined(USE_TINYGL)
#endif

View File

@@ -0,0 +1,195 @@
/* 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/base/base_game.h"
#include "engines/wintermute/dcgf.h"
#if defined(USE_TINYGL)
#include "engines/wintermute/base/gfx/tinygl/base_render_tinygl.h"
#include "engines/wintermute/base/gfx/tinygl/shadow_volume_tinygl.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
ShadowVolumeTinyGL::ShadowVolumeTinyGL(BaseGame *inGame) : ShadowVolume(inGame) {
}
//////////////////////////////////////////////////////////////////////////
ShadowVolumeTinyGL::~ShadowVolumeTinyGL() {
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeTinyGL::render() {
tglBindTexture(TGL_TEXTURE_2D, 0);
tglDisable(TGL_TEXTURE_2D);
_game->_renderer3D->_lastTexture = nullptr;
tglEnableClientState(TGL_VERTEX_ARRAY);
tglVertexPointer(3, TGL_FLOAT, 0, _vertices.getData());
tglDrawArrays(TGL_TRIANGLES, 0, _vertices.getSize());
tglDisableClientState(TGL_VERTEX_ARRAY);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeTinyGL::renderToStencilBuffer() {
// Disable z-buffer/color writes (note: z-testing still occurs), and enable the
// stencil-buffer
tglDepthMask(TGL_FALSE);
tglColorMask(TGL_FALSE, TGL_FALSE, TGL_FALSE, TGL_FALSE);
tglDisable(TGL_TEXTURE_2D);
tglDisable(TGL_LIGHTING);
tglEnable(TGL_STENCIL_TEST);
tglEnable(TGL_CULL_FACE);
// Set up stencil compare fuction, reference value, and masks.
// Stencil test passes if ((ref & mask) cmpfn (stencil & mask)) is true.
// Note: since we set up the stencil-test to always pass, the STENCILFAIL
// renderstate is really not needed.
tglStencilFunc(TGL_ALWAYS, 0x1, 0xff);
tglShadeModel(TGL_FLAT);
tglStencilOp(TGL_KEEP, TGL_KEEP, TGL_INCR);
// Draw back-side of shadow volume in stencil/z only
tglFrontFace(TGL_CCW);
render();
// Decrement stencil buffer value
tglStencilOp(TGL_KEEP, TGL_KEEP, TGL_DECR);
// Draw front-side of shadow volume in stencil/z only
tglFrontFace(TGL_CW);
render();
// Restore render states
tglEnable(TGL_LIGHTING);
tglFrontFace(TGL_CCW);
tglShadeModel(TGL_SMOOTH);
tglDepthMask(TGL_TRUE);
tglColorMask(TGL_TRUE, TGL_TRUE, TGL_TRUE, TGL_TRUE);
tglDisable(TGL_STENCIL_TEST);
tglDisable(TGL_BLEND);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeTinyGL::renderToScene() {
initMask();
tglDisable(TGL_DEPTH_TEST);
tglEnable(TGL_STENCIL_TEST);
tglEnable(TGL_BLEND);
tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA);
// Only write where stencil val >= 1 (count indicates # of shadows that overlap that pixel)
tglStencilFunc(TGL_LEQUAL, 0x1, 0xff);
tglStencilOp(TGL_KEEP, TGL_KEEP, TGL_KEEP);
tglDisable(TGL_FOG);
tglDisable(TGL_LIGHTING);
tglDisable(TGL_ALPHA_TEST);
tglBindTexture(TGL_TEXTURE_2D, 0);
BaseRenderTinyGL *renderer = (BaseRenderTinyGL *)_game->_renderer3D;
renderer->setProjection2D();
// FIXME: CW->CCW Why it differ from OpenGL?
tglFrontFace(TGL_CCW);
tglEnableClientState(TGL_COLOR_ARRAY);
tglEnableClientState(TGL_VERTEX_ARRAY);
// Draw a big, gray square
tglVertexPointer(3, TGL_FLOAT, sizeof(ShadowVertex), &_shadowMask[0].x);
tglColorPointer(4, TGL_UNSIGNED_BYTE, sizeof(ShadowVertex), &_shadowMask[0].r);
tglDrawArrays(TGL_TRIANGLE_STRIP, 0, 4);
tglDisableClientState(TGL_COLOR_ARRAY);
tglDisableClientState(TGL_VERTEX_ARRAY);
// Restore render states
tglEnable(TGL_DEPTH_TEST);
tglDisable(TGL_STENCIL_TEST);
_game->_renderer3D->setup3D(nullptr, true);
// clear stencil buffer
tglClearStencil(0);
tglClear(TGL_STENCIL_BUFFER_BIT);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ShadowVolumeTinyGL::initMask() {
auto *rend = _game->_renderer3D;
// bottom left
_shadowMask[0].x = 0.0f;
_shadowMask[0].y = rend->getHeight();
_shadowMask[0].z = 1.0f;
// top left
_shadowMask[1].x = 0.0f;
_shadowMask[1].y = 0.0f;
_shadowMask[1].z = 1.0f;
// bottom right
_shadowMask[2].x = rend->getWidth();
_shadowMask[2].y = rend->getHeight();
_shadowMask[2].z = 1.0f;
// top right
_shadowMask[3].x = rend->getWidth();
_shadowMask[3].y = 0.0f;
_shadowMask[3].z = 1.0f;
byte a = RGBCOLGetA(_color);
byte r = RGBCOLGetR(_color);
byte g = RGBCOLGetG(_color);
byte b = RGBCOLGetB(_color);
for (int i = 0; i < 4; ++i) {
_shadowMask[i].r = r;
_shadowMask[i].g = g;
_shadowMask[i].b = b;
_shadowMask[i].a = a;
}
return true;
}
} // namespace Wintermute
#endif // defined(USE_TINYGL)

View File

@@ -0,0 +1,57 @@
/* 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
*/
#ifndef WINTERMUTE_SHADOW_VOLUME_TINYGL_H
#define WINTERMUTE_SHADOW_VOLUME_TINYGL_H
#include "engines/wintermute/base/gfx/3dshadow_volume.h"
#if defined(USE_TINYGL)
#include "graphics/tinygl/tinygl.h"
namespace Wintermute {
class ShadowVolumeTinyGL : public ShadowVolume {
public:
ShadowVolumeTinyGL(BaseGame *inGame);
virtual ~ShadowVolumeTinyGL();
bool renderToStencilBuffer() override;
bool renderToScene() override;
private:
bool render();
ShadowVertex _shadowMask[4]{};
bool initMask() override;
};
} // namespace Wintermute
#endif // defined(USE_TINYGL)
#endif

View File

@@ -0,0 +1,172 @@
/* 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/base/base_game.h"
#include "engines/wintermute/base/gfx/xactive_animation.h"
#include "engines/wintermute/base/gfx/xmodel.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
ActiveAnimation::ActiveAnimation(BaseGame *inGame, XModel *model) : BaseClass(inGame) {
_model = model;
_animation = nullptr;
_looping = false;
_finished = true;
_startTime = 0;
_lastLocalTime = 0;
_currentFrame = -1;
}
//////////////////////////////////////////////////////////////////////////
ActiveAnimation::~ActiveAnimation() {
_animation = nullptr; // ref only
_model = nullptr; // ref only
}
//////////////////////////////////////////////////////////////////////////
bool ActiveAnimation::start(AnimationSet *animation, bool looping) {
_animation = animation;
_startTime = _game->_currentTime;
_looping = looping;
_finished = false;
_currentFrame = -1;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ActiveAnimation::resetStartTime() {
_startTime = _game->_currentTime;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ActiveAnimation::update(int slot, bool prevFrameOnly, float lerpValue, bool forceStartFrame) {
// PrevFrameOnly means: don't update, just use the last pose, since
// we're transitioning from it to another animation
if (!_animation) {
return false;
}
uint32 localTime = 0;
//_game->LOG(0, "%s %d %d %f %d", _animation->_name, slot, prevFrameOnly, lerpValue, forceStartFrame);
if (prevFrameOnly) {
localTime = _lastLocalTime;
} else {
if (!_finished) {
localTime = _game->_currentTime - _startTime;
if (localTime > _animation->getTotalTime()) {
if (_looping) {
if (_animation->getTotalTime() == 0) {
localTime = 0;
} else {
localTime %= _animation->getTotalTime();
}
} else {
_finished = true;
}
}
}
}
if (_finished) {
localTime = _animation->getTotalTime();
// prevent corner case
if (localTime != 0)
localTime--;
}
_lastLocalTime = localTime;
if (forceStartFrame) {
localTime = 0;
}
// handle events
int frame = 0;
if (_animation->getFrameTime() > 0) {
frame = localTime / _animation->getFrameTime() + 1;
}
if (frame != _currentFrame) {
// don't trigger events when transitioning
if (!prevFrameOnly) {
_animation->onFrameChanged(frame, _currentFrame);
}
_currentFrame = frame;
}
//_game->LOG(0, "%s %d %f", _animation->_name, localTime, lerpValue);
return _animation->update(slot, localTime, lerpValue);
}
//////////////////////////////////////////////////////////////////////////
char *ActiveAnimation::getName() {
if (_animation) {
return _animation->_name;
} else {
return nullptr;
}
}
//////////////////////////////////////////////////////////////////////////
bool ActiveAnimation::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferSint32(TMEMBER(_currentFrame));
persistMgr->transferUint32(TMEMBER(_startTime));
persistMgr->transferBool(TMEMBER(_looping));
persistMgr->transferBool(TMEMBER(_finished));
persistMgr->transferUint32(TMEMBER(_lastLocalTime));
if (persistMgr->getIsSaving()) {
persistMgr->transferCharPtr(TMEMBER(_animation->_name));
} else {
char *animName;
persistMgr->transferCharPtr(TMEMBER(animName));
if (animName) {
_animation = _model->getAnimationSetByName(animName);
} else {
_animation = nullptr;
}
SAFE_DELETE_ARRAY(animName);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool ActiveAnimation::setLooping(bool looping) {
_looping = looping;
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,76 @@
/* 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
*/
#ifndef WINTERMUTE_ACTIVE_ANIMATION_H
#define WINTERMUTE_ACTIVE_ANIMATION_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/gfx/xanimation_set.h"
namespace Wintermute {
class BasePersistenceManager;
class ActiveAnimation : public BaseClass {
public:
ActiveAnimation(BaseGame *inGame, XModel *model);
virtual ~ActiveAnimation();
bool start(AnimationSet *animation, bool looping = false);
bool update(int slot = 0, bool prevFrameOnly = false, float lerpValue = 0.0f, bool forceStartFrame = false);
bool resetStartTime();
bool persist(BasePersistenceManager *persistMgr);
bool setLooping(bool looping);
char *getName();
AnimationSet *getAnimSet() {
return _animation;
};
bool isLooping() {
return _looping;
};
bool isFinished() {
return _finished;
};
private:
XModel *_model;
int32 _currentFrame;
uint32 _startTime;
bool _looping;
bool _finished;
uint32 _lastLocalTime;
AnimationSet *_animation;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,435 @@
/* 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/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/gfx/3dutils.h"
#include "engines/wintermute/base/gfx/xanimation.h"
#include "engines/wintermute/base/gfx/xanimation_set.h"
#include "engines/wintermute/base/gfx/xframe_node.h"
#include "engines/wintermute/base/gfx/xmodel.h"
#include "engines/wintermute/base/gfx/xfile_loader.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
Animation::Animation(BaseGame *inGame) : BaseClass(inGame) {
_targetFrame = nullptr;
}
//////////////////////////////////////////////////////////////////////////
Animation::~Animation() {
for (int32 i = 0; i < _posKeys.getSize(); i++) {
delete _posKeys[i];
}
_posKeys.removeAll();
for (int32 i = 0; i < _rotKeys.getSize(); i++) {
delete _rotKeys[i];
}
_rotKeys.removeAll();
for (int32 i = 0; i < _scaleKeys.getSize(); i++) {
delete _scaleKeys[i];
}
_scaleKeys.removeAll();
}
//////////////////////////////////////////////////////////////////////////
bool Animation::findBone(FrameNode *rootFrame) {
if (!_targetName.empty()) {
_targetFrame = rootFrame->findFrame(_targetName.c_str());
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Animation::load(XFileData *xobj, AnimationSet *parentAnimSet) {
bool result;
XClassType objectType;
// Query the child for it's FileDataReference
if (xobj->isReference()) {
// The original data is found
result = xobj->getType(objectType);
if (!result) {
BaseEngine::LOG(0, "Couldn't retrieve object type while loading animation");
return result;
}
// The object must be a frame
if (objectType == kXClassFrame) {
// The frame is found, get its name
// The name will be used later by the findBone function to get
// a pointer to the target frame
if (_targetFrame) {
BaseEngine::LOG(0, "Animation frame name reference duplicated");
return false;
}
// get name
result = XModel::loadName(_targetName, xobj);
if (!result) {
BaseEngine::LOG(0, "Error retrieving frame name while loading animation");
return false;
}
}
} else {
// a data object is found, get its type
result = xobj->getType(objectType);
if (!result)
return false;
if (objectType == kXClassAnimationKey) {
// an animation key is found, load the data
XAnimationKeyObject *animationKey = xobj->getXAnimationKeyObject();
if (!animationKey)
return false;
result = loadAnimationKeyData(animationKey);
if (!result)
return false;
} else if (objectType == kXClassAnimationOptions) {
XAnimationOptionsObject *animationOptions = xobj->getXAnimationOptionsObject();
if (!animationOptions)
return false;
result = loadAnimationOptionData(animationOptions, parentAnimSet);
if (!result)
return false;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Animation::loadAnimationOptionData(XAnimationOptionsObject *animationOptionData, AnimationSet *parentAnimSet) {
if (animationOptionData->_openclosed && parentAnimSet)
parentAnimSet->_looping = true;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Animation::loadAnimationKeyData(XAnimationKeyObject *animationKey) {
// get the type and count of the key
uint32 keyType = animationKey->_keyType;
uint32 numKeys = animationKey->_numKeys;
if (keyType == 0) { // rotation key
if (_rotKeys.getSize() != 0) {
BaseEngine::LOG(0, "Rotation key duplicated");
return false;
}
for (uint32 key = 0; key < numKeys; key++) {
const XTimedFloatKeys *fileRotKey = &animationKey->_keys[key];
assert(fileRotKey->_numTfkeys == 4);
BoneRotationKey *rotKey = new BoneRotationKey;
rotKey->_time = fileRotKey->_time;
// NOTE x files are w x y z and QUATERNIONS are x y z w
rotKey->_rotation._w = fileRotKey->_tfkeys[0];
rotKey->_rotation._x = fileRotKey->_tfkeys[1];
rotKey->_rotation._y = fileRotKey->_tfkeys[2];
rotKey->_rotation._z = fileRotKey->_tfkeys[3];
_rotKeys.add(rotKey);
}
} else if (keyType == 1) { // scale key
if (_scaleKeys.getSize() != 0) {
BaseEngine::LOG(0, "Scale key duplicated");
return false;
}
for (uint32 key = 0; key < numKeys; key++) {
const XTimedFloatKeys *fileScaleKey = &animationKey->_keys[key];
assert(fileScaleKey->_numTfkeys == 3);
BoneScaleKey *scaleKey = new BoneScaleKey;
scaleKey->_time = fileScaleKey->_time;
scaleKey->_scale._x = fileScaleKey->_tfkeys[0];
scaleKey->_scale._y = fileScaleKey->_tfkeys[1];
scaleKey->_scale._z = fileScaleKey->_tfkeys[2];
_scaleKeys.add(scaleKey);
}
} else if (keyType == 2) { // position key
if (_posKeys.getSize() != 0) {
BaseEngine::LOG(0, "Position key duplicated");
return false;
}
for (uint32 key = 0; key < numKeys; key++) {
const XTimedFloatKeys *filePosKey = &animationKey->_keys[key];
assert(filePosKey->_numTfkeys == 3);
BonePositionKey *posKey = new BonePositionKey;
posKey->_time = filePosKey->_time;
posKey->_pos._x = filePosKey->_tfkeys[0];
posKey->_pos._y = filePosKey->_tfkeys[1];
posKey->_pos._z = filePosKey->_tfkeys[2];
_posKeys.add(posKey);
}
} else if (keyType == 4) { // matrix key
if (_rotKeys.getSize() != 0 || _scaleKeys.getSize() != 0 || _posKeys.getSize() != 0) {
BaseEngine::LOG(0, "Matrix key duplicated");
return false;
}
DXQuaternion qRot;
DXVector3 transVec;
DXVector3 scaleVec;
for (uint32 key = 0; key < numKeys; key++) {
const XTimedFloatKeys *fileMatrixKey = &animationKey->_keys[key];
uint32 time = fileMatrixKey->_time;
assert(fileMatrixKey->_numTfkeys == 16);
DXMatrix keyData;
for (uint32 i = 0; i < 16; ++i) {
keyData._m4x4[i] = fileMatrixKey->_tfkeys[i];
}
// we always convert matrix keys to T-R-S
C3DUtils::decomposeMatrixSimple(&keyData, &transVec, &scaleVec, &qRot);
BonePositionKey *positionKey = new BonePositionKey;
positionKey->_time = time;
positionKey->_pos = transVec;
_posKeys.add(positionKey);
BoneScaleKey *scaleKey = new BoneScaleKey;
scaleKey->_time = time;
scaleKey->_scale = scaleVec;
_scaleKeys.add(scaleKey);
BoneRotationKey *rotationKey = new BoneRotationKey;
rotationKey->_time = time;
rotationKey->_rotation = qRot;
rotationKey->_rotation._x = -rotationKey->_rotation._x;
rotationKey->_rotation._y = -rotationKey->_rotation._y;
rotationKey->_rotation._z = -rotationKey->_rotation._z;
_rotKeys.add(rotationKey);
}
} else {
// the type is unknown, report the error
BaseEngine::LOG(0, "Unexpected animation key type (%d)", keyType);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Animation::update(int slot, uint32 localTime, float animLerpValue) {
// no target frame = no animation keys
if (!_targetFrame) {
return true;
}
DXVector3 resultPos(0.0f, 0.0f, 0.0f);
DXVector3 resultScale(1.0f, 1.0f, 1.0f);
DXQuaternion resultRot(0.0f, 0.0f, 0.0f, 1.0f);
int keyIndex1, keyIndex2;
uint32 time1, time2;
float lerpValue;
bool animate = false;
// scale keys
if (_scaleKeys.getSize() > 0) {
keyIndex1 = keyIndex2 = 0;
// get the two keys between which the time is currently in
for (int32 key = 0; key < _scaleKeys.getSize(); key++) {
if (_scaleKeys[key]->_time > localTime) {
keyIndex2 = key;
if (key > 0) {
keyIndex1 = key - 1;
} else { // when ikey == 0, then dwp2 == 0
keyIndex1 = key;
}
break;
}
}
time1 = _scaleKeys[keyIndex1]->_time;
time2 = _scaleKeys[keyIndex2]->_time;
// get the lerp value
if ((time2 - time1) == 0) {
lerpValue = 0;
} else {
lerpValue = float(localTime - time1) / float(time2 - time1);
}
// apply the lerp function on the scale vector
DXVec3Lerp(&resultScale, &_scaleKeys[keyIndex1]->_scale, &_scaleKeys[keyIndex2]->_scale, lerpValue);
animate = true;
}
// rotation keys
if (_rotKeys.getSize() > 0) {
keyIndex1 = keyIndex2 = 0;
// get the two keys surrounding the current time value
for (int32 key = 0; key < _rotKeys.getSize(); key++) {
if (_rotKeys[key]->_time > localTime) {
keyIndex2 = key;
if (key > 0) {
keyIndex1 = key - 1;
} else { // when ikey == 0, then dwp2 == 0
keyIndex1 = key;
}
break;
}
}
time1 = _rotKeys[keyIndex1]->_time;
time2 = _rotKeys[keyIndex2]->_time;
// get the lerp value
if ((time2 - time1) == 0) {
lerpValue = 0;
} else {
lerpValue = float(localTime - time1) / float(time2 - time1);
}
// apply spherical lerp function
DXQuaternion q1, q2;
q1._x = -_rotKeys[keyIndex1]->_rotation._x;
q1._y = -_rotKeys[keyIndex1]->_rotation._y;
q1._z = -_rotKeys[keyIndex1]->_rotation._z;
q1._w = _rotKeys[keyIndex1]->_rotation._w;
q2._x = -_rotKeys[keyIndex2]->_rotation._x;
q2._y = -_rotKeys[keyIndex2]->_rotation._y;
q2._z = -_rotKeys[keyIndex2]->_rotation._z;
q2._w = _rotKeys[keyIndex2]->_rotation._w;
DXQuaternionSlerp(&resultRot, &q1, &q2, lerpValue);
animate = true;
}
// position keys
if (_posKeys.getSize() > 0) {
keyIndex1 = keyIndex2 = 0;
// get the two keys surrounding the time value
for (int32 key = 0; key < _posKeys.getSize(); key++) {
if (_posKeys[key]->_time > localTime) {
keyIndex2 = key;
if (key > 0) {
keyIndex1 = key - 1;
} else { // when ikey == 0, then dwp2 == 0
keyIndex1 = key;
}
break;
}
}
time1 = _posKeys[keyIndex1]->_time;
time2 = _posKeys[keyIndex2]->_time;
// get the lerp value
if (time2 - time1 == 0)
lerpValue = 0;
else
lerpValue = float(localTime - time1) / float(time2 - time1);
// apply the lerp function
DXVec3Lerp(&resultPos, &_posKeys[keyIndex1]->_pos, &_posKeys[keyIndex2]->_pos, lerpValue);
animate = true;
}
if (animate) {
_targetFrame->setTransformation(slot, resultPos, resultScale, resultRot, animLerpValue);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
int Animation::getFrameTime() {
uint32 frameTime = 0;
uint32 prevTime;
// get the shortest frame time
prevTime = 0;
for (int32 i = 0; i < _rotKeys.getSize(); i++) {
if (frameTime == 0 || _rotKeys[i]->_time - prevTime < frameTime)
frameTime = _rotKeys[i]->_time - prevTime;
prevTime = _rotKeys[i]->_time;
}
prevTime = 0;
for (int32 i = 0; i < _posKeys.getSize(); i++) {
if (frameTime == 0 || _posKeys[i]->_time - prevTime < frameTime)
frameTime = _posKeys[i]->_time - prevTime;
prevTime = _posKeys[i]->_time;
}
prevTime = 0;
for (int32 i = 0; i < _scaleKeys.getSize(); i++) {
if (frameTime == 0 || _scaleKeys[i]->_time - prevTime < frameTime)
frameTime = _scaleKeys[i]->_time - prevTime;
prevTime = _scaleKeys[i]->_time;
}
return frameTime;
}
//////////////////////////////////////////////////////////////////////////
uint32 Animation::getTotalTime() {
uint32 totalTime = 0;
if (_rotKeys.getSize() > 0) {
totalTime = MAX(totalTime, _rotKeys[_rotKeys.getSize() - 1]->_time);
}
if (_posKeys.getSize() > 0) {
totalTime = MAX(totalTime, _posKeys[_posKeys.getSize() - 1]->_time);
}
if (_scaleKeys.getSize() > 0) {
totalTime = MAX(totalTime, _scaleKeys[_scaleKeys.getSize() - 1]->_time);
}
return totalTime;
}
} // namespace Wintermute

View File

@@ -0,0 +1,87 @@
/* 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
*/
#ifndef WINTERMUTE_ANIMATION_H
#define WINTERMUTE_ANIMATION_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/coll_templ.h"
namespace Wintermute {
class FrameNode;
class AnimationSet;
class XFileData;
struct XAnimationKeyObject;
struct XAnimationOptionsObject;
class Animation : public BaseClass {
public:
Animation(BaseGame *inGame);
virtual ~Animation();
bool load(XFileData *xobj, AnimationSet *parentAnimSet);
bool findBone(FrameNode *rootFrame);
bool update(int slot, uint32 localTime, float animLerpValue);
int getFrameTime();
uint32 getTotalTime();
// data types
protected:
struct BonePositionKey {
uint32 _time;
DXVector3 _pos;
};
struct BoneScaleKey {
uint32 _time;
DXVector3 _scale;
};
struct BoneRotationKey {
uint32 _time;
DXQuaternion _rotation;
};
protected:
Common::String _targetName;
FrameNode *_targetFrame;
BaseArray<BonePositionKey *> _posKeys;
BaseArray<BoneRotationKey *> _rotKeys;
BaseArray<BoneScaleKey *> _scaleKeys;
private:
bool loadAnimationKeyData(XAnimationKeyObject *animationKey);
bool loadAnimationOptionData(XAnimationOptionsObject *animationSet, AnimationSet *parentAnimSet);
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,221 @@
/* 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/base/base_game.h"
#include "engines/wintermute/base/gfx/xanimation_channel.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
AnimationChannel::AnimationChannel(BaseGame *inGame, XModel *model) : BaseClass(inGame) {
_anim[0] = _anim[1] = nullptr;
_transitioning = false;
_transitionStart = _transtitionTime = 0,
_stopTransitionTime = 0;
_model = model;
}
//////////////////////////////////////////////////////////////////////////
AnimationChannel::~AnimationChannel() {
SAFE_DELETE(_anim[0]);
SAFE_DELETE(_anim[1]);
_model = nullptr; // ref only
}
//////////////////////////////////////////////////////////////////////////
bool AnimationChannel::playAnim(AnimationSet *animSet, uint32 transitionTime, uint32 stopTransitionTime) {
_stopTransitionTime = stopTransitionTime;
ActiveAnimation *anim = nullptr;
if (animSet != nullptr) {
anim = new ActiveAnimation(_game, _model);
anim->start(animSet, animSet->_looping);
}
if (transitionTime == 0) {
SAFE_DELETE(_anim[0]);
SAFE_DELETE(_anim[1]);
_anim[0] = anim;
_transitioning = false;
} else {
SAFE_DELETE(_anim[1]);
if (_anim[0]) {
_anim[1] = anim;
_transitioning = (anim != nullptr);
_transtitionTime = transitionTime;
_transitionStart = _game->_currentTime;
} else {
_anim[0] = anim;
SAFE_DELETE(_anim[1]);
_transitioning = false;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AnimationChannel::stopAnim(uint32 transitionTime) {
if (transitionTime == 0 || !_anim[0]) {
_transitioning = false;
SAFE_DELETE(_anim[0]);
SAFE_DELETE(_anim[1]);
} else {
SAFE_DELETE(_anim[1]);
if (_anim[0]) {
_anim[0]->setLooping(false);
}
_transitioning = true;
_transtitionTime = transitionTime;
_transitionStart = _game->_currentTime;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AnimationChannel::update(bool debug) {
if (_transitioning) {
uint32 delta = _game->_currentTime - _transitionStart;
if (delta >= _transtitionTime) {
_transitioning = false;
// shift second animation to first slot and update it
SAFE_DELETE(_anim[0]);
_anim[0] = _anim[1];
_anim[1] = nullptr;
if (_anim[0]) {
// we have to reset the start time because we wasted some on transitioning
_anim[0]->resetStartTime();
return _anim[0]->update();
}
} else {
float lerpValue = float(_game->_currentTime - _transitionStart) / float(_transtitionTime);
if (_anim[0]) {
_anim[0]->update(0, true, lerpValue);
}
if (_anim[1]) {
_anim[1]->update(1, true);
} else {
// disabled in WME 1.8.7, was causing glitches
//m_Anim[0]->Update(1, true, 0, true);
}
return true;
}
} else {
if (_anim[0]) {
//return m_Anim[0]->Update();
_anim[0]->update();
if (_anim[0]->isFinished()) {
stopAnim(_stopTransitionTime);
}
return true;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AnimationChannel::isPlaying() {
if (_anim[1] && !_anim[1]->isFinished()) {
return true;
} else if (_anim[0] && !_anim[0]->isFinished()) {
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
char *AnimationChannel::getName() {
if (_anim[1]) {
return _anim[1]->getName();
} else if (_anim[0]) {
return _anim[0]->getName();
} else {
return nullptr;
}
}
//////////////////////////////////////////////////////////////////////////
bool AnimationChannel::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferBool(TMEMBER(_transitioning));
persistMgr->transferUint32(TMEMBER(_transitionStart));
persistMgr->transferUint32(TMEMBER(_transtitionTime));
persistMgr->transferUint32(TMEMBER(_stopTransitionTime));
for (int i = 0; i < 2; i++) {
bool animExists = false;
if (persistMgr->getIsSaving()) {
animExists = (_anim[i] != nullptr);
}
persistMgr->transferBool(TMEMBER(animExists));
if (!persistMgr->getIsSaving()) {
if (animExists)
_anim[i] = new ActiveAnimation(_game, _model);
else
_anim[i] = nullptr;
}
if (_anim[i]) {
_anim[i]->persist(persistMgr);
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AnimationChannel::unloadAnim(AnimationSet *animSet) {
if (_anim[0] && _anim[0]->getAnimSet() == animSet) {
SAFE_DELETE(_anim[0]);
}
if (_anim[1] && _anim[1]->getAnimSet() == animSet) {
SAFE_DELETE(_anim[1]);
}
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,64 @@
/* 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
*/
#ifndef WINTERMUTE_ANIMATION_CHANNEL_H
#define WINTERMUTE_ANIMATION_CHANNEL_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/gfx/xactive_animation.h"
#include "engines/wintermute/base/gfx/xanimation_set.h"
namespace Wintermute {
class AnimationChannel : public BaseClass {
public:
AnimationChannel(BaseGame *inGame, XModel *model);
virtual ~AnimationChannel();
bool playAnim(AnimationSet *animSet, uint32 transitionTime = 0, uint32 stopTransitionTime = 0);
bool stopAnim(uint32 transitionTime);
bool update(bool debug);
bool isPlaying();
char *getName();
bool persist(BasePersistenceManager *persistMgr);
bool unloadAnim(AnimationSet *animSet);
private:
XModel *_model;
ActiveAnimation *_anim[2];
bool _transitioning;
uint32 _transitionStart;
uint32 _transtitionTime;
uint32 _stopTransitionTime;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,193 @@
/* 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/base/base_game.h"
#include "engines/wintermute/base/gfx/xanimation_set.h"
#include "engines/wintermute/base/gfx/xmodel.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
AnimationSet::AnimationSet(BaseGame *inGame, XModel *model) : BaseNamedObject(inGame) {
_frameTime = -1;
_totalTime = 0;
_looping = false;
_model = model;
}
//////////////////////////////////////////////////////////////////////////
AnimationSet::~AnimationSet() {
// remove child animations
for (int32 i = 0; i < _animations.getSize(); i++) {
delete _animations[i];
}
_animations.removeAll();
// remove events
for (int32 i = 0; i < _events.getSize(); i++) {
delete _events[i];
}
_events.removeAll();
}
//////////////////////////////////////////////////////////////////////////
bool AnimationSet::findBones(FrameNode *rootFrame) {
for (int32 i = 0; i < _animations.getSize(); i++) {
_animations[i]->findBone(rootFrame);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AnimationSet::addAnimation(Animation *anim) {
if (!anim) {
return false;
} else {
_animations.add(anim);
return true;
}
}
//////////////////////////////////////////////////////////////////////////
bool AnimationSet::addEvent(AnimationEvent *event) {
if (!event) {
return false;
} else {
int frameTime = getFrameTime();
if (frameTime < 0) {
_game->LOG(0, "Error adding animation event %s, no keyframes found", event->_eventName);
SAFE_DELETE(event);
return false;
}
int totalFrames = 0;
if (frameTime > 0)
totalFrames = getTotalTime() / frameTime + 1;
if (event->_frame < 1)
event->_frame = 1;
if (event->_frame > totalFrames)
event->_frame = totalFrames;
_events.add(event);
return true;
}
}
//////////////////////////////////////////////////////////////////////////
bool AnimationSet::update(int slot, uint32 localTime, float lerpValue) {
bool res;
for (int32 i = 0; i < _animations.getSize(); i++) {
res = _animations[i]->update(slot, localTime * ((float)_model->_ticksPerSecond / 1000.0f), lerpValue);
if (!res) {
return res;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
int AnimationSet::getFrameTime() {
if (_frameTime >= 0) {
return _frameTime;
}
_frameTime = 0;
for (int32 i = 0; i < _animations.getSize(); i++) {
int frameTime = _animations[i]->getFrameTime();
if (_frameTime == 0) {
_frameTime = frameTime / ((float)_model->_ticksPerSecond / 1000.0f);
} else if (frameTime > 0) {
_frameTime = MIN(float(_frameTime), frameTime / ((float)_model->_ticksPerSecond / 1000.0f));
}
}
return _frameTime;
}
//////////////////////////////////////////////////////////////////////////
uint32 AnimationSet::getTotalTime() {
if (_totalTime > 0) {
return _totalTime;
}
_totalTime = 0;
for (int32 i = 0; i < _animations.getSize(); i++) {
_totalTime = MAX((float)_totalTime, _animations[i]->getTotalTime() / ((float)_model->_ticksPerSecond / 1000.0f));
}
return _totalTime;
}
//////////////////////////////////////////////////////////////////////////
bool AnimationSet::onFrameChanged(int currentFrame, int prevFrame) {
if (!_model || !_model->_owner) {
return true;
}
if (prevFrame > currentFrame) {
for (int32 i = 0; i < _events.getSize(); i++) {
if (_events[i]->_frame > prevFrame) {
_model->_owner->applyEvent(_events[i]->_eventName);
}
}
prevFrame = -1;
}
for (int32 i = 0; i < _events.getSize(); i++) {
if (_events[i]->_frame > prevFrame && _events[i]->_frame <= currentFrame) {
_model->_owner->applyEvent(_events[i]->_eventName);
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool AnimationSet::persist(BasePersistenceManager *persistMgr) {
persistMgr->transferBool(TMEMBER(_looping));
// persist events
int32 numEvents;
if (persistMgr->getIsSaving()) {
numEvents = _events.getSize();
}
persistMgr->transferSint32(TMEMBER(numEvents));
for (int i = 0; i < numEvents; i++) {
if (persistMgr->getIsSaving()) {
_events[i]->persist(persistMgr);
} else {
AnimationEvent *rvent = new AnimationEvent();
rvent->persist(persistMgr);
_events.add(rvent);
}
}
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,101 @@
/* 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
*/
#ifndef WINTERMUTE_ANIMATION_SET_H
#define WINTERMUTE_ANIMATION_SET_H
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/gfx/xanimation.h"
#include "engines/wintermute/base/gfx/xframe_node.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/coll_templ.h"
#include "engines/wintermute/persistent.h"
namespace Wintermute {
class XModel;
class AnimationSet : public BaseNamedObject {
public:
//////////////////////////////////////////////////////////////////////////
class AnimationEvent {
public:
char *_eventName;
int32 _frame;
AnimationEvent() {
_eventName = nullptr;
_frame = -1;
}
AnimationEvent(char *name, int frame) {
_eventName = nullptr;
BaseUtils::setString(&_eventName, name);
_frame = frame;
}
virtual ~AnimationEvent() {
if (_eventName) {
delete[] _eventName;
}
}
bool persist(BasePersistenceManager *persistMgr) {
persistMgr->transferCharPtr(TMEMBER(_eventName));
persistMgr->transferSint32(TMEMBER(_frame));
return true;
}
};
AnimationSet(BaseGame *inGame, XModel *model);
virtual ~AnimationSet();
bool findBones(FrameNode *rootFrame);
bool addAnimation(Animation *anim);
bool addEvent(AnimationEvent *event);
bool update(int slot, uint32 localTime, float lerpValue);
bool onFrameChanged(int currentFrame, int prevFrame);
int getFrameTime();
uint32 getTotalTime();
bool _looping;
bool persist(BasePersistenceManager *persistMgr);
protected:
BaseArray<Animation *> _animations;
BaseArray<AnimationEvent *> _events;
int _frameTime;
uint32 _totalTime;
XModel *_model;
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,79 @@
/* 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/>.
*
*/
#ifndef WINTERMUTE_XBUFFER_H
#define WINTERMUTE_XBUFFER_H
#include "common/types.h"
#include "common/util.h"
namespace Wintermute {
struct DXBuffer {
private:
byte *_ptr;
uint64 _size;
public:
DXBuffer() {
_ptr = nullptr;
_size = 0;
}
DXBuffer(uint64 size) {
_ptr = new uint8_t[size];
if (_ptr == nullptr) {
size = 0;
return;
}
_size = size;
}
DXBuffer(const uint8 *ptr, uint64 size) {
_ptr = new uint8[size];
if (_ptr == nullptr) {
size = 0;
return;
}
memcpy(_ptr, ptr, size);
_size = size;
}
void free() {
delete[] _ptr;
_ptr = nullptr;
_size = 0;
}
byte *ptr() const {
return _ptr;
}
uint64 size() const {
return _size;
}
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,88 @@
/* 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/base/base_file_manager.h"
#include "engines/wintermute/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/gfx/xfile.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
XFile::XFile(BaseGame *inGame) : BaseClass(inGame) {
_xfile = nullptr;
}
//////////////////////////////////////////////////////////////////////////
XFile::~XFile() {
closeFile();
}
//////////////////////////////////////////////////////////////////////////
bool XFile::closeFile() {
SAFE_DELETE(_xfile);
return true;
}
//////////////////////////////////////////////////////////////////////////
bool XFile::openFile(const char *filename) {
closeFile();
// load file
uint32 size;
byte *buffer = BaseFileManager::getEngineInstance()->readWholeFile(filename, &size);
if (!buffer) {
closeFile();
return false;
}
_xfile = new XFileLoader();
if (!_xfile) {
delete[] buffer;
return false;
}
bool res = _xfile->load(buffer, size);
delete[] buffer;
if (!res) {
BaseEngine::LOG(0, "Error loading X file '%s'", filename);
return false;
}
// create enum object
if (!res || !_xfile->createEnumObject(_xenum)) {
BaseEngine::LOG(res, "Error creating XFile enum object for '%s'", filename);
closeFile();
return false;
}
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,56 @@
/* 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
*/
#ifndef WINTERMUTE_XFILE_H
#define WINTERMUTE_XFILE_H
#include "engines/wintermute/base/base.h"
#include "engines/wintermute/base/gfx/xfile_loader.h"
namespace Wintermute {
class XFile : public BaseClass {
public:
XFile(BaseGame *inGame);
virtual ~XFile();
bool openFile(const char *filename);
bool closeFile();
XFileEnumObject getEnum() {
return _xenum;
}
private:
XFileLoader *_xfile;
XFileEnumObject _xenum;
};
} // namespace Wintermute
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,573 @@
/* 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/>.
*
*/
/*
* Partially based on XFile parser code from Wine sources.
* Copyright 2008 Christian Costa
*/
#ifndef WINTERMUTE_XFILE_LOADER_H
#define WINTERMUTE_XFILE_LOADER_H
#include "common/str.h"
#include "common/stack.h"
namespace Wintermute {
enum XTokenType : uint16 {
XTOKEN_ERROR = 0xffff,
XTOKEN_NONE = 0,
XTOKEN_NAME = 1,
XTOKEN_STRING = 2,
XTOKEN_INTEGER = 3,
XTOKEN_GUID = 5,
XTOKEN_INTEGER_LIST = 6,
XTOKEN_FLOAT_LIST = 7,
XTOKEN_OBRACE = 10,
XTOKEN_CBRACE = 11,
XTOKEN_OPAREN = 12,
XTOKEN_CPAREN = 13,
XTOKEN_OBRACKET = 14,
XTOKEN_CBRACKET = 15,
XTOKEN_OANGLE = 16,
XTOKEN_CANGLE = 17,
XTOKEN_DOT = 18,
XTOKEN_COMMA = 19,
XTOKEN_SEMICOLON = 20,
XTOKEN_TEMPLATE = 31,
XTOKEN_WORD = 40,
XTOKEN_DWORD = 41,
XTOKEN_FLOAT = 42,
XTOKEN_DOUBLE = 43,
XTOKEN_CHAR = 44,
XTOKEN_UCHAR = 45,
XTOKEN_SWORD = 46,
XTOKEN_SDWORD = 47,
XTOKEN_VOID = 48,
XTOKEN_LPSTR = 49,
XTOKEN_UNICODE = 50,
XTOKEN_CSTRING = 51,
XTOKEN_ARRAY = 52
};
#define XMAX_NAME_LEN 120
#define XMAX_STRING_LEN 500
struct XToken {
XTokenType _type;
char _textVal[XMAX_STRING_LEN];
uint32 _integerVal;
float _floatVal;
};
struct XVector3 {
float _x;
float _y;
float _z;
};
struct XVector4 {
float _x;
float _y;
float _z;
float _w;
};
struct XCoords2d {
float _u;
float _v;
};
struct XMeshFace {
uint32 _numFaceVertexIndices;
uint32 _faceVertexIndices[4];
};
struct XTimedFloatKeys {
float _time;
uint32 _numTfkeys;
float _tfkeys[16];
};
struct XIndexedColor {
uint32 _index;
float _indexColorR;
float _indexColorG;
float _indexColorB;
float _indexColorA;
};
struct XVertexElement {
uint32 _type;
uint32 _method;
uint32 _usage;
uint32 _usageIndex;
};
struct XMeshMaterialListObject {
uint32 _nMaterials;
uint32 _numFaceIndexes;
uint32 *_faceIndexes{};
~XMeshMaterialListObject() {
delete[] _faceIndexes;
}
};
struct XVertexDuplicationIndicesObject {
uint32 _nOriginalVertices;
uint32 _numIndices;
uint32 *_indices{};
~XVertexDuplicationIndicesObject() {
delete[] _indices;
}
};
struct XSkinMeshHeaderObject{
uint32 _nMaxSkinWeightsPerVertex;
uint32 _nMaxSkinWeightsPerFace;
uint32 _nBones;
};
struct XSkinWeightsObject {
char _transformNodeName[XMAX_NAME_LEN];
uint32 _numVertexIndices;
uint32 *_vertexIndices{};
uint32 _numWeights;
float *_weights{};
float _matrixOffset[16];
~XSkinWeightsObject() {
delete[] _vertexIndices;
delete[] _weights;
}
};
struct XMeshObject {
uint32 _numVertices;
XVector3 *_vertices{};
uint32 _numFaces;
XMeshFace *_faces{};
~XMeshObject() {
delete[] _vertices;
delete[] _faces;
}
};
struct XMeshNormalsObject {
uint32 _numNormals;
XVector3 *_normals{};
uint32 _numFaceNormals;
XMeshFace *_faceNormals{};
~XMeshNormalsObject() {
delete[] _normals;
delete[] _faceNormals;
}
};
struct XMeshVertexColorsObject {
uint32 _numVertexColors;
XIndexedColor *_vertexColors{};
~XMeshVertexColorsObject() {
delete[] _vertexColors;
}
};
struct XMeshTextureCoordsObject {
uint32 _numTextureCoords;
XCoords2d *_textureCoords{};
~XMeshTextureCoordsObject() {
delete[] _textureCoords;
}
};
struct XMaterialObject {
float _colorR;
float _colorG;
float _colorB;
float _colorA;
float _power;
float _specularR;
float _specularG;
float _specularB;
float _emissiveR;
float _emissiveG;
float _emissiveB;
};
struct XTextureFilenameObject {
char _filename[XMAX_NAME_LEN];
};
struct XAnimTicksPerSecondObject {
uint32 _animTicksPerSecond;
};
struct XAnimationSetObject{
};
struct XAnimationObject{
};
struct XAnimationKeyObject {
uint32 _keyType;
uint32 _numKeys;
XTimedFloatKeys *_keys{};
~XAnimationKeyObject() {
delete[] _keys;
}
};
struct XAnimationOptionsObject {
uint32 _openclosed;
uint32 _positionquality;
};
struct XFrameObject {
};
struct XFrameTransformMatrixObject {
float _frameMatrix[16];
};
struct XDeclDataObject {
uint32 _numElements;
XVertexElement *_elements{};
uint32 _numData;
uint32 *_data{};
~XDeclDataObject() {
delete[] _elements;
delete[] _data;
}
};
struct XFVFDataObject {
uint32 _dwFVF;
uint32 _numData;
uint32 *_data{};
~XFVFDataObject() {
delete[] _data;
}
};
enum XClassType {
kXClassUnknown = 0,
kXClassAnimTicksPerSecond,
kXClassFrameTransformMatrix,
kXClassFrame,
kXClassMesh,
kXClassMeshNormals,
kXClassMeshVertexColors,
kXClassMeshTextureCoords,
kXClassMeshMaterialList,
kXClassVertexDuplicationIndices,
kXClassMaterial,
kXClassTextureFilename,
kXClassSkinMeshHeader,
kXClassSkinWeights,
kXClassAnimationSet,
kXClassAnimation,
kXClassAnimationKey,
kXClassAnimationOptions,
kXClassDeclData,
kXClassFVFData,
};
class XFileEnumObject;
class XObject {
friend class XFileLoader;
friend class XFileData;
friend class XFileEnumObject;
private:
Common::String _name;
XClassType _classType{};
void *_object{};
XObject *_targetObject{};
Common::Stack<XObject *> _children;
public:
void deinit() {
switch (_classType) {
case kXClassAnimTicksPerSecond:
delete (XAnimTicksPerSecondObject *)_object;
break;
case kXClassAnimationKey:
delete (XAnimationKeyObject *)_object;
break;
case kXClassAnimation:
delete (XAnimationObject *)_object;
break;
case kXClassAnimationOptions:
delete (XAnimationOptionsObject *)_object;
break;
case kXClassAnimationSet:
delete (XAnimationSetObject *)_object;
break;
case kXClassDeclData:
delete (XDeclDataObject *)_object;
break;
case kXClassFrame:
delete (XFrameObject *)_object;
break;
case kXClassFrameTransformMatrix:
delete (XFrameTransformMatrixObject *)_object;
break;
case kXClassFVFData:
delete (XFVFDataObject *)_object;
break;
case kXClassMaterial:
delete (XMaterialObject *)_object;
break;
case kXClassMesh:
delete (XMeshObject *)_object;
break;
case kXClassMeshMaterialList:
delete (XMeshMaterialListObject *)_object;
break;
case kXClassMeshNormals:
delete (XMeshNormalsObject *)_object;
break;
case kXClassMeshVertexColors:
delete (XMeshVertexColorsObject *)_object;
break;
case kXClassMeshTextureCoords:
delete (XMeshTextureCoordsObject *)_object;
break;
case kXClassSkinMeshHeader:
delete (XSkinMeshHeaderObject *)_object;
break;
case kXClassSkinWeights:
delete (XSkinWeightsObject *)_object;
break;
case kXClassVertexDuplicationIndices:
delete (XVertexDuplicationIndicesObject *)_object;
break;
case kXClassTextureFilename:
delete (XTextureFilenameObject *)_object;
break;
case kXClassUnknown:
break;
}
}
};
class XFileLoader {
friend class XFileEnumObject;
private:
const int kCabBlockSize = 0x8000;
const int kCabInputmax = kCabBlockSize + 12;
bool _initialised{};
XToken _currentToken{};
byte *_decompBuffer{};
byte *_buffer{};
uint32 _bufferLeft;
bool _isText;
uint32 _listNbElements;
bool _listTypeFloat;
bool _listSeparator;
bool _tokenPresent;
Common::Stack<XObject *> _xobjects;
public:
XFileLoader();
~XFileLoader();
bool load(byte *buffer, uint32 bufferSize);
bool createEnumObject(XFileEnumObject &xobj);
private:
void init();
void deinit();
FORCEINLINE bool readChar(char &c);
FORCEINLINE void rewindBytes(uint32 size);
bool readBytes(void *data, uint32 size);
bool readLE16(uint16 *data);
bool readLE32(uint32 *data);
bool readBE32(uint32 *data);
FORCEINLINE bool getInteger(uint32 &value);
FORCEINLINE bool getFloat(float &value);
FORCEINLINE bool getString(char *str, uint maxLen);
FORCEINLINE bool skipSemicolonComma();
FORCEINLINE bool isSpace(char c);
FORCEINLINE bool isOperator(char c);
FORCEINLINE bool isSeparator(char c);
FORCEINLINE bool isPrimitiveType(XTokenType token);
FORCEINLINE bool isGuid();
FORCEINLINE bool isName();
FORCEINLINE bool isFloat();
FORCEINLINE bool isInteger();
FORCEINLINE bool isString();
FORCEINLINE bool isKeyword(const char *keyword, uint len);
FORCEINLINE XTokenType getKeywordToken();
FORCEINLINE XTokenType checkToken();
XTokenType getToken();
void parseToken();
bool decompressMsZipData();
bool parseHeader();
bool parseTemplate();
bool parseTemplateParts();
bool parseTemplateOptionInfo();
bool parseTemplateMembersList();
XObject *resolveChildObject(XObject *object, const Common::String &referenceName);
bool resolveObject(XObject *referenceObject, const Common::String &referenceName);
bool parseObject(XObject *object);
bool parseChildObjects(XObject *object);
bool parseObjectParts(XObject *object);
};
class XFileData {
friend class XFileEnumObject;
private:
XObject *_xobject{};
bool _reference{};
public:
bool getChild(uint id, XFileData &child) {
if (_xobject) {
if (id < _xobject->_children.size()) {
child._xobject = _xobject->_children[id];
if (child._xobject->_targetObject) {
child._xobject = child._xobject->_targetObject;
child._reference = true;
}
return true;
}
}
return false;
}
bool getChildren(uint32 &num) {
if (_xobject) {
num = _xobject->_children.size();
return true;
}
return false;
}
bool getName(Common::String &name) {
if (_xobject) {
name = _xobject->_name;
return true;
}
return false;
}
bool getType(XClassType &classType) {
if (_xobject) {
classType = _xobject->_classType;
return true;
}
return false;
}
bool isReference() {
if (_xobject) {
return _reference;
}
return false;
}
#define GET_OBJECT_FUNC(objectName) \
objectName *get ## objectName() { \
if (_xobject) \
return static_cast<objectName *>(_xobject->_object); \
else \
return nullptr; \
}
GET_OBJECT_FUNC(XAnimTicksPerSecondObject)
GET_OBJECT_FUNC(XAnimationKeyObject)
GET_OBJECT_FUNC(XAnimationObject)
GET_OBJECT_FUNC(XAnimationOptionsObject)
GET_OBJECT_FUNC(XAnimationSetObject)
GET_OBJECT_FUNC(XDeclDataObject)
GET_OBJECT_FUNC(XFrameObject)
GET_OBJECT_FUNC(XFrameTransformMatrixObject)
GET_OBJECT_FUNC(XFVFDataObject)
GET_OBJECT_FUNC(XMaterialObject)
GET_OBJECT_FUNC(XMeshObject)
GET_OBJECT_FUNC(XMeshMaterialListObject)
GET_OBJECT_FUNC(XMeshNormalsObject)
GET_OBJECT_FUNC(XMeshVertexColorsObject)
GET_OBJECT_FUNC(XMeshTextureCoordsObject)
GET_OBJECT_FUNC(XSkinMeshHeaderObject)
GET_OBJECT_FUNC(XSkinWeightsObject)
GET_OBJECT_FUNC(XVertexDuplicationIndicesObject)
GET_OBJECT_FUNC(XTextureFilenameObject)
};
class XFileEnumObject {
friend class XFileLoader;
private:
XFileLoader *_file{};
public:
bool getChild(uint id, XFileData &child) {
if (_file) {
if (id < _file->_xobjects.size()) {
child._xobject = _file->_xobjects[id];
return true;
}
}
return false;
}
bool getChildren(uint32 &num) {
if (_file) {
num = _file->_xobjects.size();
return true;
}
return false;
}
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,499 @@
/* 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/base/base_game.h"
#include "engines/wintermute/base/base_engine.h"
#include "engines/wintermute/base/gfx/base_renderer3d.h"
#include "engines/wintermute/base/gfx/xmaterial.h"
#include "engines/wintermute/base/gfx/xframe_node.h"
#include "engines/wintermute/base/gfx/xmath.h"
#include "engines/wintermute/base/gfx/xmodel.h"
#include "engines/wintermute/base/gfx/xfile_loader.h"
#include "engines/wintermute/dcgf.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////////
FrameNode::FrameNode(BaseGame *inGame) : BaseNamedObject(inGame) {
DXMatrixIdentity(&_transformationMatrix);
DXMatrixIdentity(&_originalMatrix);
DXMatrixIdentity(&_combinedMatrix);
for (int i = 0; i < 2; i++) {
_transPos[i] = DXVector3(0.0f, 0.0f, 0.0f);
_transScale[i] = DXVector3(1.0f, 1.0f, 1.0f);
_transRot[i] = DXQuaternion(0.0f, 0.0f, 0.0f, 1.0f);
_lerpValue[i] = 0.0f;
_transUsed[i] = false;
}
}
//////////////////////////////////////////////////////////////////////////
FrameNode::~FrameNode() {
// remove child frames
for (int32 i = 0; i < _frames.getSize(); i++) {
delete _frames[i];
}
_frames.removeAll();
// remove meshes
for (int32 i = 0; i < _meshes.getSize(); i++) {
delete _meshes[i];
}
_meshes.removeAll();
}
//////////////////////////////////////////////////////////////////////////
DXMatrix *FrameNode::getCombinedMatrix() {
return &_combinedMatrix;
}
//////////////////////////////////////////////////////////////////////////
DXMatrix *FrameNode::getOriginalMatrix() {
return &_originalMatrix;
}
//////////////////////////////////////////////////////////////////////////
void FrameNode::setTransformationMatrix(DXMatrix *mat) {
_transformationMatrix = *mat;
}
//////////////////////////////////////////////////////////////////////////
void FrameNode::setTransformation(int slot, DXVector3 pos, DXVector3 scale, DXQuaternion rot, float lerpValue) {
if (slot < 0 || slot > 1)
return;
_transPos[slot] = pos;
_transScale[slot] = scale;
_transRot[slot] = rot;
_lerpValue[slot] = lerpValue;
_transUsed[slot] = true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::loadFromXData(const char *filename, XModel *model, XFileData *xobj) {
_game->miniUpdate();
bool res = true;
// get the type of the object
XClassType objectType = kXClassUnknown;
res = xobj->getType(objectType);
if (!res) {
BaseEngine::LOG(0, "Error getting object type");
return res;
}
if (objectType == kXClassMesh) { // load a child mesh
XMesh *mesh = _game->_renderer3D->createXMesh();
res = mesh->loadFromXData(filename, xobj);
if (res) {
_meshes.add(mesh);
return true;
} else {
SAFE_DELETE(mesh);
return false;
}
} else if (objectType == kXClassFrameTransformMatrix) { // load the transformation matrix
XFrameTransformMatrixObject *frameTransformMatrix = xobj->getXFrameTransformMatrixObject();
if (!frameTransformMatrix) {
BaseEngine::LOG(0, "Error loading transformation matrix");
return false;
} else {
for (int i = 0; i < 16; ++i) {
_transformationMatrix._m4x4[i] = frameTransformMatrix->_frameMatrix[i];
}
_originalMatrix = _transformationMatrix;
return true;
}
} else if (objectType == kXClassAnimationSet) { // load animation set
return model->loadAnimationSet(filename, xobj);
} else if (objectType == kXClassAnimation) { // load a single animation (shouldn't happen here)
return model->loadAnimation(filename, xobj);
} else if (objectType == kXClassFrame) { // create a new child frame
FrameNode *childFrame = new FrameNode(_game);
// get the name of the child frame
res = XModel::loadName(childFrame, xobj);
if (!res) {
BaseEngine::LOG(0, "Error loading frame name");
SAFE_DELETE(childFrame);
return res;
}
// Enumerate child objects.
res = false;
uint32 numChildren = 0;
xobj->getChildren(numChildren);
for (uint32 i = 0; i < numChildren; i++) {
XFileData xchildData;
res = xobj->getChild(i, xchildData);
if (res)
res = childFrame->loadFromXData(filename, model, &xchildData);
}
if (res)
_frames.add(childFrame);
else
SAFE_DELETE(childFrame);
return res;
} else if (objectType == kXClassAnimTicksPerSecond) {
if (!xobj->getXAnimTicksPerSecondObject()) {
BaseEngine::LOG(0, "Error loading ticks per seconds info");
return res;
} else {
model->_ticksPerSecond = xobj->getXAnimTicksPerSecondObject()->_animTicksPerSecond;
return true;
}
}
return true;
}
bool FrameNode::mergeFromXData(const char *filename, XModel *model, XFileData *xobj) {
bool res = true;
// get the type of the object
XClassType objectType;
res = xobj->getType(objectType);
if (!res) {
BaseEngine::LOG(0, "Error getting object type");
return res;
} else if (objectType == kXClassAnimationSet) { // load animation set
return model->loadAnimationSet(filename, xobj);
} else if (objectType == kXClassAnimation) { // load a single animation (shouldn't happen here)
return model->loadAnimation(filename, xobj);
} else if (objectType == kXClassFrame) { // scan child frames
// Enumerate child objects.
res = false;
uint32 numChildren = 0;
xobj->getChildren(numChildren);
for (uint32 i = 0; i < numChildren; i++) {
XFileData xchildData;
res = xobj->getChild(i, xchildData);
if (res)
res = mergeFromXData(filename, model, &xchildData);
}
return res;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::findBones(FrameNode *rootFrame) {
// find the bones of the meshes
for (int32 i = 0; i < _meshes.getSize(); i++) {
_meshes[i]->findBones(rootFrame);
}
// find the bones for the child frames
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->findBones(rootFrame);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
FrameNode *FrameNode::findFrame(const char *frameName) {
if (_name && strcmp(_name, frameName) == 0) {
return this;
} else {
for (int32 i = 0; i < _frames.getSize(); i++) {
FrameNode *foundFrame = _frames[i]->findFrame(frameName);
if (foundFrame) {
return foundFrame;
}
}
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::updateMatrices(DXMatrix *parentMat) {
if (_transUsed[0]) {
DXVector3 transPos = _transPos[0];
DXVector3 transScale = _transScale[0];
DXQuaternion transRot = _transRot[0];
float lerpValue = _lerpValue[0];
if (_transUsed[1]) {
DXVec3Lerp(&transScale, &transScale, &_transScale[1], lerpValue);
DXQuaternionSlerp(&transRot, &transRot, &_transRot[1], lerpValue);
DXVec3Lerp(&transPos, &transPos, &_transPos[1], lerpValue);
}
// prepare local transformation matrix
DXMatrixIdentity(&_transformationMatrix);
DXMatrix scaleMat;
DXMatrixScaling(&scaleMat, transScale._x, transScale._y, transScale._z);
DXMatrixMultiply(&_transformationMatrix, &_transformationMatrix, &scaleMat);
DXMatrix rotMat;
DXMatrixRotationQuaternion(&rotMat, &transRot);
DXMatrixMultiply(&_transformationMatrix, &_transformationMatrix, &rotMat);
DXMatrix posMat;
DXMatrixTranslation(&posMat, transPos._x, transPos._y, transPos._z);
DXMatrixMultiply(&_transformationMatrix, &_transformationMatrix, &posMat);
}
_transUsed[0] = _transUsed[1] = false;
// multiply by parent transformation
DXMatrixMultiply(&_combinedMatrix, &_transformationMatrix, parentMat);
// update child frames
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->updateMatrices(&_combinedMatrix);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::updateMeshes() {
bool res = true;
// update meshes
for (int32 i = 0; i < _meshes.getSize(); i++) {
res = _meshes[i]->update(this);
if (!res) {
return res;
}
}
// render child frames
for (int32 i = 0; i < _frames.getSize(); i++) {
res = _frames[i]->updateMeshes();
if (!res) {
return res;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::resetMatrices() {
_transformationMatrix = _originalMatrix;
// update child frames
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->resetMatrices();
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::updateShadowVol(ShadowVolume *shadow, DXMatrix *modelMat, DXVector3 *light, float extrusionDepth) {
bool res = true;
// meshes
for (int32 i = 0; i < _meshes.getSize(); i++) {
res = _meshes[i]->updateShadowVol(shadow, modelMat, light, extrusionDepth);
if (!res) {
return res;
}
}
// child frames
for (int32 i = 0; i < _frames.getSize(); i++) {
res = _frames[i]->updateShadowVol(shadow, modelMat, light, extrusionDepth);
if (!res) {
return res;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::render(XModel *model) {
bool res = true;
// render meshes
for (int32 i = 0; i < _meshes.getSize(); i++) {
res = _meshes[i]->render(model);
if (!res) {
return res;
}
}
// render child frames
for (int32 i = 0; i < _frames.getSize(); i++) {
res = _frames[i]->render(model);
if (!res) {
return res;
}
}
return true;
}
bool FrameNode::renderFlatShadowModel(uint32 shadowColor) {
bool res = true;
for (int32 i = 0; i < _meshes.getSize(); i++) {
res = _meshes[i]->renderFlatShadowModel(shadowColor);
if (!res) {
return res;
}
}
for (int32 i = 0; i < _frames.getSize(); i++) {
res = _frames[i]->renderFlatShadowModel(shadowColor);
if (!res) {
return res;
}
}
return res;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::pickPoly(DXVector3 *pickRayOrig, DXVector3 *pickRayDir) {
bool found = false;
for (int32 i = 0; i < _meshes.getSize(); i++) {
found = _meshes[i]->pickPoly(pickRayOrig, pickRayDir);
if (found) {
return true;
}
}
for (int32 i = 0; i < _frames.getSize(); i++) {
found = _frames[i]->pickPoly(pickRayOrig, pickRayDir);
if (found) {
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::getBoundingBox(DXVector3 *boxStart, DXVector3 *boxEnd) {
for (int32 i = 0; i < _meshes.getSize(); i++) {
boxStart->_x = MIN(boxStart->_x, _meshes[i]->_BBoxStart._x);
boxStart->_y = MIN(boxStart->_y, _meshes[i]->_BBoxStart._y);
boxStart->_z = MIN(boxStart->_z, _meshes[i]->_BBoxStart._z);
boxEnd->_x = MAX(boxEnd->_x, _meshes[i]->_BBoxEnd._x);
boxEnd->_y = MAX(boxEnd->_y, _meshes[i]->_BBoxEnd._y);
boxEnd->_z = MAX(boxEnd->_z, _meshes[i]->_BBoxEnd._z);
}
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->getBoundingBox(boxStart, boxEnd);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::hasChildren() {
return _frames.getSize() > 0;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::setMaterialSprite(char *matName, BaseSprite *sprite) {
for (int32 i = 0; i < _meshes.getSize(); i++) {
_meshes[i]->setMaterialSprite(matName, sprite);
}
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->setMaterialSprite(matName, sprite);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::setMaterialTheora(char *matName, VideoTheoraPlayer *theora) {
for (int32 i = 0; i < _meshes.getSize(); i++) {
_meshes[i]->setMaterialTheora(matName, theora);
}
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->setMaterialTheora(matName, theora);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::setMaterialEffect(char *matName, Effect3D *effect, Effect3DParams *params) {
for (int32 i = 0; i < _meshes.getSize(); i++) {
_meshes[i]->setMaterialEffect(matName, effect, params);
}
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->setMaterialEffect(matName, effect, params);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::removeMaterialEffect(const char *matName) {
for (int32 i = 0; i < _meshes.getSize(); i++) {
_meshes[i]->removeMaterialEffect(matName);
}
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->removeMaterialEffect(matName);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::invalidateDeviceObjects() {
for (int32 i = 0; i < _meshes.getSize(); i++) {
_meshes[i]->invalidateDeviceObjects();
}
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->invalidateDeviceObjects();
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool FrameNode::restoreDeviceObjects() {
for (int32 i = 0; i < _meshes.getSize(); i++) {
_meshes[i]->restoreDeviceObjects();
}
for (int32 i = 0; i < _frames.getSize(); i++) {
_frames[i]->restoreDeviceObjects();
}
return true;
}
} // namespace Wintermute

View File

@@ -0,0 +1,95 @@
/* 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
*/
#ifndef WINTERMUTE_XFRAME_NODE_H
#define WINTERMUTE_XFRAME_NODE_H
#include "engines/wintermute/base/base_named_object.h"
#include "engines/wintermute/base/gfx/xmesh.h"
#include "engines/wintermute/base/gfx/xmodel.h"
#include "engines/wintermute/coll_templ.h"
namespace Wintermute {
class XModel;
class XFileData;
class BaseSprite;
class Effect3D;
class Effect3DParams;
class FrameNode : public BaseNamedObject {
public:
FrameNode(BaseGame *inGame);
virtual ~FrameNode();
bool updateMatrices(DXMatrix *parentMat);
bool updateMeshes();
bool resetMatrices();
bool render(XModel *model);
bool renderFlatShadowModel(uint32 shadowColor);
bool updateShadowVol(ShadowVolume *shadow, DXMatrix *modelMat, DXVector3 *light, float extrusionDepth);
bool loadFromXData(const char *filename, XModel *model, XFileData *xobj);
bool mergeFromXData(const char *filename, XModel *model, XFileData *xobj);
bool findBones(FrameNode *rootFrame);
FrameNode *findFrame(const char *frameName);
DXMatrix *getCombinedMatrix();
DXMatrix *getOriginalMatrix();
void setTransformationMatrix(DXMatrix *mat);
bool pickPoly(DXVector3 *pickRayOrig, DXVector3 *pickRayDir);
bool getBoundingBox(DXVector3 *boxStart, DXVector3 *boxEnd);
void setTransformation(int slot, DXVector3 pos, DXVector3 scale, DXQuaternion rot, float lerpValue);
bool hasChildren();
bool setMaterialSprite(char *matName, BaseSprite *sprite);
bool setMaterialTheora(char *matName, VideoTheoraPlayer *theora);
bool setMaterialEffect(char *matName, Effect3D *effect, Effect3DParams *params);
bool removeMaterialEffect(const char *matName);
bool invalidateDeviceObjects();
bool restoreDeviceObjects();
protected:
BaseArray<FrameNode *> _frames;
BaseArray<XMesh *> _meshes;
DXMatrix _transformationMatrix;
DXMatrix _originalMatrix;
DXMatrix _combinedMatrix;
DXVector3 _transPos[2];
DXVector3 _transScale[2];
DXQuaternion _transRot[2];
bool _transUsed[2];
float _lerpValue[2];
};
} // namespace Wintermute
#endif

View File

@@ -0,0 +1,175 @@
/* 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/base/base_game.h"
#include "engines/wintermute/base/base_sprite.h"
#include "engines/wintermute/base/base_surface_storage.h"
#include "engines/wintermute/base/gfx/base_surface.h"
#include "engines/wintermute/base/gfx/xmaterial.h"
#include "engines/wintermute/base/gfx/3deffect.h"
#include "engines/wintermute/base/gfx/xfile_loader.h"
#include "engines/wintermute/dcgf.h"
#include "engines/wintermute/utils/path_util.h"
#include "engines/wintermute/utils/utils.h"
#include "engines/wintermute/video/video_theora_player.h"
namespace Wintermute {
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Material::Material(BaseGame *inGame) : BaseNamedObject(inGame) {
memset(&_material, 0, sizeof(_material));
_textureFilename = nullptr;
_surface = nullptr;
_ownedSurface = false;
_sprite = nullptr;
_theora = nullptr;
_effect = nullptr;
_params = nullptr;
}
//////////////////////////////////////////////////////////////////////////
Material::~Material() {
SAFE_DELETE_ARRAY(_textureFilename);
if (_surface && _ownedSurface) {
_game->_surfaceStorage->removeSurface(_surface);
}
_sprite = nullptr; // ref only
_theora = nullptr;
_effect = nullptr;
_params = nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool Material::invalidateDeviceObjects() {
if (_effect)
return _effect->invalidateDeviceObjects();
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Material::restoreDeviceObjects() {
if (_effect)
return _effect->restoreDeviceObjects();
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Material::setTexture(const char *filename, bool adoptName) {
if (adoptName) {
setName(PathUtil::getFileNameWithoutExtension(filename).c_str());
}
BaseUtils::setString(&_textureFilename, filename);
if (_surface && _ownedSurface) {
_game->_surfaceStorage->removeSurface(_surface);
}
_surface = _game->_surfaceStorage->addSurface(_textureFilename, false);
_ownedSurface = true;
_sprite = nullptr;
return _surface != nullptr;
}
//////////////////////////////////////////////////////////////////////////
bool Material::setSprite(BaseSprite *sprite, bool adoptName) {
if (adoptName) {
setName(PathUtil::getFileNameWithoutExtension(sprite->_filename).c_str());
}
BaseUtils::setString(&_textureFilename, sprite->_filename);
if (_surface && _ownedSurface) {
_game->_surfaceStorage->removeSurface(_surface);
}
_surface = nullptr;
_sprite = sprite;
_ownedSurface = false;
_theora = nullptr;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Material::setTheora(VideoTheoraPlayer *theora, bool adoptName) {
if (adoptName) {
setName(PathUtil::getFileNameWithoutExtension(theora->_filename).c_str());
}
BaseUtils::setString(&_textureFilename, theora->_filename.c_str());
if (_surface && _ownedSurface) {
_game->_surfaceStorage->removeSurface(_surface);
}
_surface = nullptr;
_theora = theora;
_ownedSurface = false;
return true;
}
//////////////////////////////////////////////////////////////////////////
bool Material::setEffect(Effect3D *effect, Effect3DParams *params, bool adoptName) {
if (!effect) {
_effect = nullptr;
_params = nullptr;
return true;
}
if (adoptName) {
setName(PathUtil::getFileNameWithoutExtension(effect->getFileName()).c_str());
}
BaseUtils::setString(&_textureFilename, effect->getFileName());
_effect = effect;
_params = params;
return true;
}
//////////////////////////////////////////////////////////////////////////
BaseSurface *Material::getSurface() {
if (_theora) {
_theora->update();
return _theora->getTexture();
} else if (_sprite) {
_sprite->getCurrentFrame();
return _sprite->getSurface();
} else {
return _surface;
}
}
} // namespace Wintermute

Some files were not shown because too many files have changed in this diff Show More