Initial commit
This commit is contained in:
111
engines/wintermute/base/gfx/3dcamera.cpp
Normal file
111
engines/wintermute/base/gfx/3dcamera.cpp
Normal 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
|
||||
58
engines/wintermute/base/gfx/3dcamera.h
Normal file
58
engines/wintermute/base/gfx/3dcamera.h
Normal 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
|
||||
78
engines/wintermute/base/gfx/3deffect.cpp
Normal file
78
engines/wintermute/base/gfx/3deffect.cpp
Normal 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
|
||||
54
engines/wintermute/base/gfx/3deffect.h
Normal file
54
engines/wintermute/base/gfx/3deffect.h
Normal 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
|
||||
203
engines/wintermute/base/gfx/3deffect_params.cpp
Normal file
203
engines/wintermute/base/gfx/3deffect_params.cpp
Normal 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
|
||||
96
engines/wintermute/base/gfx/3deffect_params.h
Normal file
96
engines/wintermute/base/gfx/3deffect_params.h
Normal 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
|
||||
49
engines/wintermute/base/gfx/3dface.cpp
Normal file
49
engines/wintermute/base/gfx/3dface.cpp
Normal 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
|
||||
45
engines/wintermute/base/gfx/3dface.h
Normal file
45
engines/wintermute/base/gfx/3dface.h
Normal 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
|
||||
89
engines/wintermute/base/gfx/3dlight.cpp
Normal file
89
engines/wintermute/base/gfx/3dlight.cpp
Normal 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
|
||||
59
engines/wintermute/base/gfx/3dlight.h
Normal file
59
engines/wintermute/base/gfx/3dlight.h
Normal 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
|
||||
525
engines/wintermute/base/gfx/3dloader_3ds.cpp
Normal file
525
engines/wintermute/base/gfx/3dloader_3ds.cpp
Normal 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
|
||||
94
engines/wintermute/base/gfx/3dloader_3ds.h
Normal file
94
engines/wintermute/base/gfx/3dloader_3ds.h
Normal 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
|
||||
172
engines/wintermute/base/gfx/3dmesh.cpp
Normal file
172
engines/wintermute/base/gfx/3dmesh.cpp
Normal 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
|
||||
77
engines/wintermute/base/gfx/3dmesh.h
Normal file
77
engines/wintermute/base/gfx/3dmesh.h
Normal 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
|
||||
176
engines/wintermute/base/gfx/3dshadow_volume.cpp
Normal file
176
engines/wintermute/base/gfx/3dshadow_volume.cpp
Normal 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
|
||||
73
engines/wintermute/base/gfx/3dshadow_volume.h
Normal file
73
engines/wintermute/base/gfx/3dshadow_volume.h
Normal 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
|
||||
188
engines/wintermute/base/gfx/3dutils.cpp
Normal file
188
engines/wintermute/base/gfx/3dutils.cpp
Normal 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
|
||||
57
engines/wintermute/base/gfx/3dutils.h
Normal file
57
engines/wintermute/base/gfx/3dutils.h
Normal 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
|
||||
46
engines/wintermute/base/gfx/3dvertex.cpp
Normal file
46
engines/wintermute/base/gfx/3dvertex.cpp
Normal 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
|
||||
44
engines/wintermute/base/gfx/3dvertex.h
Normal file
44
engines/wintermute/base/gfx/3dvertex.h
Normal 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
|
||||
296
engines/wintermute/base/gfx/base_image.cpp
Normal file
296
engines/wintermute/base/gfx/base_image.cpp
Normal 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
|
||||
82
engines/wintermute/base/gfx/base_image.h
Normal file
82
engines/wintermute/base/gfx/base_image.h
Normal 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
|
||||
243
engines/wintermute/base/gfx/base_renderer.cpp
Normal file
243
engines/wintermute/base/gfx/base_renderer.cpp
Normal 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
|
||||
206
engines/wintermute/base/gfx/base_renderer.h
Normal file
206
engines/wintermute/base/gfx/base_renderer.h
Normal 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
|
||||
175
engines/wintermute/base/gfx/base_renderer3d.cpp
Normal file
175
engines/wintermute/base/gfx/base_renderer3d.cpp
Normal 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
|
||||
177
engines/wintermute/base/gfx/base_renderer3d.h
Normal file
177
engines/wintermute/base/gfx/base_renderer3d.h
Normal 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
|
||||
122
engines/wintermute/base/gfx/base_surface.cpp
Normal file
122
engines/wintermute/base/gfx/base_surface.cpp
Normal 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
|
||||
98
engines/wintermute/base/gfx/base_surface.h
Normal file
98
engines/wintermute/base/gfx/base_surface.h
Normal 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
|
||||
1191
engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
Normal file
1191
engines/wintermute/base/gfx/opengl/base_render_opengl3d.cpp
Normal file
File diff suppressed because it is too large
Load Diff
176
engines/wintermute/base/gfx/opengl/base_render_opengl3d.h
Normal file
176
engines/wintermute/base/gfx/opengl/base_render_opengl3d.h
Normal 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
|
||||
1205
engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
Normal file
1205
engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
200
engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
Normal file
200
engines/wintermute/base/gfx/opengl/base_render_opengl3d_shader.h
Normal 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
|
||||
469
engines/wintermute/base/gfx/opengl/base_surface_opengl3d.cpp
Normal file
469
engines/wintermute/base/gfx/opengl/base_surface_opengl3d.cpp
Normal 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)
|
||||
100
engines/wintermute/base/gfx/opengl/base_surface_opengl3d.h
Normal file
100
engines/wintermute/base/gfx/opengl/base_surface_opengl3d.h
Normal 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
|
||||
60
engines/wintermute/base/gfx/opengl/mesh3ds_opengl.cpp
Normal file
60
engines/wintermute/base/gfx/opengl/mesh3ds_opengl.cpp
Normal 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)
|
||||
47
engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h
Normal file
47
engines/wintermute/base/gfx/opengl/mesh3ds_opengl.h
Normal 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
|
||||
66
engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
Normal file
66
engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.cpp
Normal 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)
|
||||
51
engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
Normal file
51
engines/wintermute/base/gfx/opengl/mesh3ds_opengl_shader.h
Normal 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
|
||||
264
engines/wintermute/base/gfx/opengl/meshx_opengl.cpp
Normal file
264
engines/wintermute/base/gfx/opengl/meshx_opengl.cpp
Normal 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)
|
||||
56
engines/wintermute/base/gfx/opengl/meshx_opengl.h
Normal file
56
engines/wintermute/base/gfx/opengl/meshx_opengl.h
Normal 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
|
||||
289
engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
Normal file
289
engines/wintermute/base/gfx/opengl/meshx_opengl_shader.cpp
Normal 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)
|
||||
67
engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h
Normal file
67
engines/wintermute/base/gfx/opengl/meshx_opengl_shader.h
Normal 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
|
||||
@@ -0,0 +1,7 @@
|
||||
in vec4 Color;
|
||||
|
||||
OUTPUT
|
||||
|
||||
void main() {
|
||||
outColor = Color;
|
||||
}
|
||||
11
engines/wintermute/base/gfx/opengl/shaders/wme_fade.vertex
Normal file
11
engines/wintermute/base/gfx/opengl/shaders/wme_fade.vertex
Normal 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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
uniform vec4 shadowColor;
|
||||
|
||||
OUTPUT
|
||||
|
||||
void main() {
|
||||
outColor = shadowColor;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
in vec4 Color;
|
||||
|
||||
OUTPUT
|
||||
|
||||
void main() {
|
||||
outColor = Color;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
14
engines/wintermute/base/gfx/opengl/shaders/wme_line.fragment
Normal file
14
engines/wintermute/base/gfx/opengl/shaders/wme_line.fragment
Normal 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;
|
||||
}
|
||||
}
|
||||
11
engines/wintermute/base/gfx/opengl/shaders/wme_line.vertex
Normal file
11
engines/wintermute/base/gfx/opengl/shaders/wme_line.vertex
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
78
engines/wintermute/base/gfx/opengl/shaders/wme_modelx.vertex
Normal file
78
engines/wintermute/base/gfx/opengl/shaders/wme_modelx.vertex
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
in vec4 Color;
|
||||
|
||||
OUTPUT
|
||||
|
||||
void main() {
|
||||
outColor = Color;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
void main() {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
16
engines/wintermute/base/gfx/opengl/shaders/wme_sprite.vertex
Normal file
16
engines/wintermute/base/gfx/opengl/shaders/wme_sprite.vertex
Normal 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;
|
||||
}
|
||||
197
engines/wintermute/base/gfx/opengl/shadow_volume_opengl.cpp
Normal file
197
engines/wintermute/base/gfx/opengl/shadow_volume_opengl.cpp
Normal 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)
|
||||
|
||||
55
engines/wintermute/base/gfx/opengl/shadow_volume_opengl.h
Normal file
55
engines/wintermute/base/gfx/opengl/shadow_volume_opengl.h
Normal 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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
580
engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
Normal file
580
engines/wintermute/base/gfx/osystem/base_render_osystem.cpp
Normal 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
|
||||
155
engines/wintermute/base/gfx/osystem/base_render_osystem.h
Normal file
155
engines/wintermute/base/gfx/osystem/base_render_osystem.h
Normal 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
|
||||
477
engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
Normal file
477
engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp
Normal 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
|
||||
107
engines/wintermute/base/gfx/osystem/base_surface_osystem.h
Normal file
107
engines/wintermute/base/gfx/osystem/base_surface_osystem.h
Normal 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
|
||||
201
engines/wintermute/base/gfx/osystem/render_ticket.cpp
Normal file
201
engines/wintermute/base/gfx/osystem/render_ticket.cpp
Normal 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
|
||||
79
engines/wintermute/base/gfx/osystem/render_ticket.h
Normal file
79
engines/wintermute/base/gfx/osystem/render_ticket.h
Normal 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
|
||||
90
engines/wintermute/base/gfx/skin_mesh_helper.cpp
Normal file
90
engines/wintermute/base/gfx/skin_mesh_helper.cpp
Normal 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
|
||||
65
engines/wintermute/base/gfx/skin_mesh_helper.h
Normal file
65
engines/wintermute/base/gfx/skin_mesh_helper.h
Normal 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
|
||||
1061
engines/wintermute/base/gfx/tinygl/base_render_tinygl.cpp
Normal file
1061
engines/wintermute/base/gfx/tinygl/base_render_tinygl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
176
engines/wintermute/base/gfx/tinygl/base_render_tinygl.h
Normal file
176
engines/wintermute/base/gfx/tinygl/base_render_tinygl.h
Normal 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
|
||||
462
engines/wintermute/base/gfx/tinygl/base_surface_tinygl.cpp
Normal file
462
engines/wintermute/base/gfx/tinygl/base_surface_tinygl.cpp
Normal 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)
|
||||
101
engines/wintermute/base/gfx/tinygl/base_surface_tinygl.h
Normal file
101
engines/wintermute/base/gfx/tinygl/base_surface_tinygl.h
Normal 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
|
||||
60
engines/wintermute/base/gfx/tinygl/mesh3ds_tinygl.cpp
Normal file
60
engines/wintermute/base/gfx/tinygl/mesh3ds_tinygl.cpp
Normal 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)
|
||||
49
engines/wintermute/base/gfx/tinygl/mesh3ds_tinygl.h
Normal file
49
engines/wintermute/base/gfx/tinygl/mesh3ds_tinygl.h
Normal 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
|
||||
261
engines/wintermute/base/gfx/tinygl/meshx_tinygl.cpp
Normal file
261
engines/wintermute/base/gfx/tinygl/meshx_tinygl.cpp
Normal 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)
|
||||
58
engines/wintermute/base/gfx/tinygl/meshx_tinygl.h
Normal file
58
engines/wintermute/base/gfx/tinygl/meshx_tinygl.h
Normal 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
|
||||
195
engines/wintermute/base/gfx/tinygl/shadow_volume_tinygl.cpp
Normal file
195
engines/wintermute/base/gfx/tinygl/shadow_volume_tinygl.cpp
Normal 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)
|
||||
57
engines/wintermute/base/gfx/tinygl/shadow_volume_tinygl.h
Normal file
57
engines/wintermute/base/gfx/tinygl/shadow_volume_tinygl.h
Normal 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
|
||||
172
engines/wintermute/base/gfx/xactive_animation.cpp
Normal file
172
engines/wintermute/base/gfx/xactive_animation.cpp
Normal 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
|
||||
76
engines/wintermute/base/gfx/xactive_animation.h
Normal file
76
engines/wintermute/base/gfx/xactive_animation.h
Normal 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
|
||||
435
engines/wintermute/base/gfx/xanimation.cpp
Normal file
435
engines/wintermute/base/gfx/xanimation.cpp
Normal 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
|
||||
87
engines/wintermute/base/gfx/xanimation.h
Normal file
87
engines/wintermute/base/gfx/xanimation.h
Normal 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
|
||||
221
engines/wintermute/base/gfx/xanimation_channel.cpp
Normal file
221
engines/wintermute/base/gfx/xanimation_channel.cpp
Normal 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
|
||||
64
engines/wintermute/base/gfx/xanimation_channel.h
Normal file
64
engines/wintermute/base/gfx/xanimation_channel.h
Normal 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
|
||||
193
engines/wintermute/base/gfx/xanimation_set.cpp
Normal file
193
engines/wintermute/base/gfx/xanimation_set.cpp
Normal 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
|
||||
101
engines/wintermute/base/gfx/xanimation_set.h
Normal file
101
engines/wintermute/base/gfx/xanimation_set.h
Normal 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
|
||||
79
engines/wintermute/base/gfx/xbuffer.h
Normal file
79
engines/wintermute/base/gfx/xbuffer.h
Normal 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
|
||||
88
engines/wintermute/base/gfx/xfile.cpp
Normal file
88
engines/wintermute/base/gfx/xfile.cpp
Normal 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
|
||||
56
engines/wintermute/base/gfx/xfile.h
Normal file
56
engines/wintermute/base/gfx/xfile.h
Normal 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
|
||||
1514
engines/wintermute/base/gfx/xfile_loader.cpp
Normal file
1514
engines/wintermute/base/gfx/xfile_loader.cpp
Normal file
File diff suppressed because it is too large
Load Diff
573
engines/wintermute/base/gfx/xfile_loader.h
Normal file
573
engines/wintermute/base/gfx/xfile_loader.h
Normal 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
|
||||
499
engines/wintermute/base/gfx/xframe_node.cpp
Normal file
499
engines/wintermute/base/gfx/xframe_node.cpp
Normal 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
|
||||
95
engines/wintermute/base/gfx/xframe_node.h
Normal file
95
engines/wintermute/base/gfx/xframe_node.h
Normal 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
|
||||
175
engines/wintermute/base/gfx/xmaterial.cpp
Normal file
175
engines/wintermute/base/gfx/xmaterial.cpp
Normal 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
Reference in New Issue
Block a user