Initial commit
This commit is contained in:
277
engines/qdengine/qdcore/util/2PassScale.h
Normal file
277
engines/qdengine/qdcore/util/2PassScale.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/* 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 QDENGINE_QDCORE_UTIL_2_PASS_SCALE_H
|
||||
#define QDENGINE_QDCORE_UTIL_2_PASS_SCALE_H
|
||||
|
||||
#include "qdengine/qdcore/util/Filters.h"
|
||||
|
||||
#define TRACE(a)
|
||||
#define ASSERT(a)
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
namespace scl {
|
||||
|
||||
typedef struct {
|
||||
double *weights; // Normalized weights of neighboring pixels
|
||||
int left, right; // Bounds of source pixels window
|
||||
} ContributionType; // Contirbution information for a single pixel
|
||||
|
||||
typedef struct {
|
||||
ContributionType *contribRow; // Row (or column) of contribution weights
|
||||
uint32 windowSize, // Filter window size (of affecting source pixels)
|
||||
lineLength; // Length of line (no. or rows / cols)
|
||||
} LineContribType; // Contribution information for an entire line (row or column)
|
||||
|
||||
template <class FilterClass>
|
||||
class C2PassScale {
|
||||
public:
|
||||
|
||||
C2PassScale() : _temp_buffer(65536, 0), _weights_buffer(16384, 0.0), _contribution_buffer(500) { }
|
||||
virtual ~C2PassScale() { }
|
||||
|
||||
uint32 *scale(uint32 *pOrigImage, uint32 uOrigWidth, uint32 uOrigHeight, uint32 *pDstImage, uint32 uNewWidth, uint32 uNewHeight);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Std::vector<uint32> _temp_buffer;
|
||||
|
||||
Std::vector<double> _weights_buffer;
|
||||
Std::vector<ContributionType> _contribution_buffer;
|
||||
|
||||
LineContribType *allocContributions(uint32 uLineLength, uint32 uWindowSize);
|
||||
LineContribType *calcContributions(uint32 uLineSize, uint32 uSrcSize, double dScale);
|
||||
|
||||
void scaleRow(uint32 *pSrc, uint32 uSrcWidth, uint32 *pRes, uint32 uResWidth, uint32 uRow, LineContribType *Contrib);
|
||||
void horizScale(uint32 *pSrc, uint32 uSrcWidth, uint32 uSrcHeight, uint32 *pDst, uint32 uResWidth, uint32 uResHeight);
|
||||
void scaleCol(uint32 *pSrc, uint32 uSrcWidth, uint32 *pRes, uint32 uResWidth, uint32 uResHeight, uint32 uCol, LineContribType *Contrib);
|
||||
void vertScale(uint32 *pSrc, uint32 uSrcWidth, uint32 uSrcHeight, uint32 *pDst, uint32 uResWidth, uint32 uResHeight);
|
||||
|
||||
static inline byte make_r(uint32 col) {
|
||||
return reinterpret_cast<byte *>(&col)[2];
|
||||
}
|
||||
static inline byte make_g(uint32 col) {
|
||||
return reinterpret_cast<byte *>(&col)[1];
|
||||
}
|
||||
static inline byte make_b(uint32 col) {
|
||||
return reinterpret_cast<byte *>(&col)[0];
|
||||
}
|
||||
static inline byte make_a(uint32 col) {
|
||||
return reinterpret_cast<byte *>(&col)[3];
|
||||
}
|
||||
|
||||
static inline uint32 make_rgba(byte r, byte g, byte b, byte a) {
|
||||
return (r << 16) | (g << 8) | (b << 0) | (a << 24);
|
||||
}
|
||||
};
|
||||
|
||||
template<class FilterClass>
|
||||
LineContribType *C2PassScale<FilterClass>::allocContributions(uint32 uLineLength, uint32 uWindowSize) {
|
||||
static LineContribType line_ct;
|
||||
|
||||
line_ct.windowSize = uWindowSize;
|
||||
line_ct.lineLength = uLineLength;
|
||||
|
||||
if (_contribution_buffer.size() < uLineLength)
|
||||
_contribution_buffer.resize(uLineLength);
|
||||
|
||||
line_ct.contribRow = &*_contribution_buffer.begin();
|
||||
|
||||
if (_weights_buffer.size() < uLineLength * uWindowSize)
|
||||
_weights_buffer.resize(uLineLength * uWindowSize);
|
||||
|
||||
double *p = &*_weights_buffer.begin();
|
||||
|
||||
for (uint32 u = 0; u < uLineLength; u++) {
|
||||
line_ct.contribRow[u].weights = p;
|
||||
p += uWindowSize;
|
||||
}
|
||||
return &line_ct;
|
||||
}
|
||||
|
||||
template <class FilterClass>
|
||||
LineContribType *C2PassScale<FilterClass>::calcContributions(uint32 uLineSize, uint32 uSrcSize, double dScale) {
|
||||
FilterClass curFilter;
|
||||
|
||||
double dWidth;
|
||||
double dFScale = 1.0;
|
||||
double dFilterWidth = curFilter.getWidth();
|
||||
|
||||
if (dScale < 1.0) { // Minification
|
||||
dWidth = dFilterWidth / dScale;
|
||||
dFScale = dScale;
|
||||
} else { // Magnification
|
||||
dWidth = dFilterWidth;
|
||||
}
|
||||
|
||||
// Window size is the number of sampled pixels
|
||||
int iWindowSize = 2 * (int)ceil(dWidth) + 1;
|
||||
|
||||
// Allocate a new line contributions strucutre
|
||||
LineContribType *res = allocContributions(uLineSize, iWindowSize);
|
||||
|
||||
for (uint32 u = 0; u < uLineSize; u++) {
|
||||
// Scan through line of contributions
|
||||
double dCenter = (double)u / dScale; // Reverse mapping
|
||||
// Find the significant edge points that affect the pixel
|
||||
int iLeft = MAX(0, (int)floor(dCenter - dWidth));
|
||||
int iRight = MIN((int)ceil(dCenter + dWidth), int(uSrcSize) - 1);
|
||||
|
||||
// Cut edge points to fit in filter window in case of spill-off
|
||||
if (iRight - iLeft + 1 > iWindowSize) {
|
||||
if (iLeft < (int(uSrcSize) - 1 / 2)) {
|
||||
iLeft++;
|
||||
} else {
|
||||
iRight--;
|
||||
}
|
||||
}
|
||||
|
||||
res->contribRow[u].left = iLeft;
|
||||
res->contribRow[u].right = iRight;
|
||||
|
||||
double dTotalWeight = 0.0; // Zero sum of weights
|
||||
for (int iSrc = iLeft; iSrc <= iRight; iSrc++) {
|
||||
// Calculate weights
|
||||
dTotalWeight += (res->contribRow[u].weights[iSrc - iLeft] = dFScale * curFilter.filter(dFScale * (dCenter - (double)iSrc)));
|
||||
}
|
||||
ASSERT(dTotalWeight >= 0.0); // An error in the filter function can cause this
|
||||
if (dTotalWeight > 0.0) {
|
||||
// Normalize weight of neighbouring points
|
||||
for (int iSrc = iLeft; iSrc <= iRight; iSrc++) {
|
||||
// Normalize point
|
||||
res->contribRow[u].weights[iSrc - iLeft] /= dTotalWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class FilterClass>
|
||||
void C2PassScale<FilterClass>::scaleRow(uint32 *pSrc, uint32 uSrcWidth, uint32 *pRes, uint32 uResWidth, uint32 uRow, LineContribType *contrib) {
|
||||
uint32 *pSrcRow = &(pSrc[uRow * uSrcWidth]);
|
||||
uint32 *pDstRow = &(pRes[uRow * uResWidth]);
|
||||
for (uint32 x = 0; x < uResWidth; x++) {
|
||||
// Loop through row
|
||||
double dr = 0.0;
|
||||
double dg = 0.0;
|
||||
double db = 0.0;
|
||||
double da = 0.0;
|
||||
|
||||
int iLeft = contrib->contribRow[x].left; // Retrieve left boundries
|
||||
int iRight = contrib->contribRow[x].right; // Retrieve right boundries
|
||||
for (int i = iLeft; i <= iRight; i++) {
|
||||
// Scan between boundries
|
||||
// Accumulate weighted effect of each neighboring pixel
|
||||
dr += contrib->contribRow[x].weights[i - iLeft] * (double)(make_r(pSrcRow[i]));
|
||||
dg += contrib->contribRow[x].weights[i - iLeft] * (double)(make_g(pSrcRow[i]));
|
||||
db += contrib->contribRow[x].weights[i - iLeft] * (double)(make_b(pSrcRow[i]));
|
||||
da += contrib->contribRow[x].weights[i - iLeft] * (double)(make_a(pSrcRow[i]));
|
||||
}
|
||||
|
||||
uint32 r = round(dr);
|
||||
uint32 g = round(dg);
|
||||
uint32 b = round(db);
|
||||
uint32 a = round(da);
|
||||
|
||||
pDstRow[x] = make_rgba(r, g, b, a); // Place result in destination pixel
|
||||
}
|
||||
}
|
||||
|
||||
template <class FilterClass>
|
||||
void C2PassScale<FilterClass>::horizScale(uint32 *pSrc, uint32 uSrcWidth, uint32 uSrcHeight, uint32 *pDst, uint32 uResWidth, uint32 uResHeight) {
|
||||
TRACE("Performing horizontal scaling...\n");
|
||||
if (uResWidth == uSrcWidth) {
|
||||
// No scaling required, just copy
|
||||
memcpy(pDst, pSrc, sizeof(uint32) * uSrcHeight * uSrcWidth);
|
||||
return;
|
||||
}
|
||||
// Allocate and calculate the contributions
|
||||
LineContribType *contrib = calcContributions(uResWidth, uSrcWidth, double(uResWidth) / double(uSrcWidth));
|
||||
for (uint32 u = 0; u < uResHeight; u++)
|
||||
scaleRow(pSrc, uSrcWidth, pDst, uResWidth, u, contrib); // Scale each row
|
||||
}
|
||||
|
||||
template <class FilterClass>
|
||||
void C2PassScale<FilterClass>::scaleCol(uint32 *pSrc, uint32 uSrcWidth, uint32 *pRes, uint32 uResWidth, uint32 uResHeight, uint32 uCol, LineContribType *contrib) {
|
||||
for (uint32 y = 0; y < uResHeight; y++) {
|
||||
// Loop through column
|
||||
double dr = 0.0;
|
||||
double dg = 0.0;
|
||||
double db = 0.0;
|
||||
double da = 0.0;
|
||||
|
||||
int iLeft = contrib->contribRow[y].left; // Retrieve left boundries
|
||||
int iRight = contrib->contribRow[y].right; // Retrieve right boundries
|
||||
for (int i = iLeft; i <= iRight; i++) {
|
||||
// Scan between boundries
|
||||
// Accumulate weighted effect of each neighboring pixel
|
||||
uint32 pCurSrc = pSrc[i * uSrcWidth + uCol];
|
||||
dr += contrib->contribRow[y].weights[i - iLeft] * (double)(make_r(pCurSrc));
|
||||
dg += contrib->contribRow[y].weights[i - iLeft] * (double)(make_g(pCurSrc));
|
||||
db += contrib->contribRow[y].weights[i - iLeft] * (double)(make_b(pCurSrc));
|
||||
da += contrib->contribRow[y].weights[i - iLeft] * (double)(make_a(pCurSrc));
|
||||
}
|
||||
|
||||
uint32 r = round(dr);
|
||||
uint32 g = round(dg);
|
||||
uint32 b = round(db);
|
||||
uint32 a = round(da);
|
||||
|
||||
pRes[y * uResWidth + uCol] = make_rgba(r, g, b, a); // Place result in destination pixel
|
||||
}
|
||||
}
|
||||
|
||||
template <class FilterClass>
|
||||
void C2PassScale<FilterClass>::vertScale(uint32 *pSrc, uint32 uSrcWidth, uint32 uSrcHeight, uint32 *pDst, uint32 uResWidth, uint32 uResHeight) {
|
||||
TRACE("Performing vertical scaling...");
|
||||
|
||||
if (uSrcHeight == uResHeight) {
|
||||
// No scaling required, just copy
|
||||
memcpy(pDst, pSrc, sizeof(uint32) * uSrcHeight * uSrcWidth);
|
||||
return;
|
||||
}
|
||||
// Allocate and calculate the contributions
|
||||
LineContribType *Contrib = calcContributions(uResHeight, uSrcHeight, double(uResHeight) / double(uSrcHeight));
|
||||
for (uint32 u = 0; u < uResWidth; u++)
|
||||
scaleCol(pSrc, uSrcWidth, pDst, uResWidth, uResHeight, u, Contrib); // Scale each column
|
||||
}
|
||||
|
||||
template <class FilterClass>
|
||||
uint32 *C2PassScale<FilterClass>::scale(uint32 *pOrigImage, uint32 uOrigWidth, uint32 uOrigHeight, uint32 *pDstImage, uint32 uNewWidth, uint32 uNewHeight) {
|
||||
if (_temp_buffer.size() < uNewWidth * uOrigHeight)
|
||||
_temp_buffer.resize(uNewWidth * uOrigHeight);
|
||||
|
||||
uint32 *pTemp = reinterpret_cast<uint32 *>(&*_temp_buffer.begin());
|
||||
horizScale(pOrigImage, uOrigWidth, uOrigHeight, pTemp, uNewWidth, uOrigHeight);
|
||||
|
||||
// Scale temporary image vertically into result image
|
||||
vertScale(pTemp, uNewWidth, uOrigHeight, pDstImage, uNewWidth, uNewHeight);
|
||||
|
||||
return pDstImage;
|
||||
}
|
||||
|
||||
} // namespace scl
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_2_PASS_SCALE_H
|
||||
532
engines/qdengine/qdcore/util/AIAStar.h
Normal file
532
engines/qdengine/qdcore/util/AIAStar.h
Normal file
@@ -0,0 +1,532 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//K-D Lab / Balmer
|
||||
#pragma once
|
||||
|
||||
#include "common/multimap.h"
|
||||
|
||||
|
||||
///////////////////////////AIAStar/////////////////////
|
||||
//AIAStar::FindPath поиск пути из точки from
|
||||
//в точку IsEndPoint.
|
||||
//Боле-менее оптимизированный на случай квадратной сетки
|
||||
|
||||
/*
|
||||
class Heuristic
|
||||
{
|
||||
float getH(int x,int y);//Предполагаемые затраты на продвижение из pos1 к окончанию
|
||||
float getG(int x1,int y1,int x2,int y2);//Затраты на продвижение из pos1 в pos2
|
||||
bool IsEndPoint(int x,int y);//Рекурсия должна окончиться здесь
|
||||
//то есть класс AIAStar позволяет задавать несколько точек окончания поиска пути
|
||||
};
|
||||
*/
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
template<class Heuristic, class TypeH = float>
|
||||
class AIAStar {
|
||||
public:
|
||||
typedef Common::MultiMap<TypeH, Vect2i> type_point_map;
|
||||
|
||||
struct OnePoint {
|
||||
TypeH g;//Затраты на продвижение до этой точки
|
||||
TypeH h;//Предполагаемые затраты на продвижение до финиша
|
||||
int used;
|
||||
OnePoint *parent;
|
||||
bool is_open;
|
||||
|
||||
inline TypeH f() {
|
||||
return g + h;
|
||||
}
|
||||
};
|
||||
protected:
|
||||
int _dx, _dy;
|
||||
OnePoint *_chart;
|
||||
type_point_map _open_map;
|
||||
|
||||
int _is_used_num;//Если _is_used_num==used, то ячейка используется
|
||||
|
||||
int _num_point_examine;//количество посещённых ячеек
|
||||
int _num_find_erase;//Сколько суммарно искали ячейки для удаления
|
||||
Heuristic *_heuristic;
|
||||
public:
|
||||
AIAStar();
|
||||
~AIAStar();
|
||||
|
||||
void init(int dx, int dy);
|
||||
bool findPath(Vect2i from, Heuristic *h, Std::vector<Vect2i> &path, int directions_count = 8);
|
||||
void getStatistic(int *num_point_examine, int *num_find_erase);
|
||||
|
||||
//Debug
|
||||
OnePoint *getInternalBuffer() {
|
||||
return _chart;
|
||||
};
|
||||
int getUsedNum() {
|
||||
return _is_used_num;
|
||||
}
|
||||
protected:
|
||||
void clear();
|
||||
inline Vect2i posBy(OnePoint *p) {
|
||||
int offset = p - _chart;
|
||||
Vect2i pos;
|
||||
pos.x = offset % _dx;
|
||||
pos.y = offset / _dx;
|
||||
return pos;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Heuristic, class TypeH>
|
||||
AIAStar<Heuristic, TypeH>::AIAStar() {
|
||||
_chart = NULL;
|
||||
_heuristic = NULL;
|
||||
_num_find_erase = 0;
|
||||
_dx = _dy = 0;
|
||||
_is_used_num = 0;
|
||||
_num_point_examine = 0;
|
||||
}
|
||||
|
||||
template<class Heuristic, class TypeH>
|
||||
void AIAStar<Heuristic, TypeH>::init(int dx_, int dy_) {
|
||||
_dx = dx_;
|
||||
_dy = dy_;
|
||||
|
||||
int size = _dx * _dy;
|
||||
_chart = new OnePoint[size];
|
||||
clear();
|
||||
}
|
||||
|
||||
template<class Heuristic, class TypeH>
|
||||
void AIAStar<Heuristic, TypeH>::clear() {
|
||||
int size = _dx * _dy;
|
||||
_is_used_num = 0;
|
||||
for (int i = 0; i < size; i++)
|
||||
_chart[i].used = 0;
|
||||
}
|
||||
|
||||
template<class Heuristic, class TypeH>
|
||||
AIAStar<Heuristic, TypeH>::~AIAStar() {
|
||||
delete[] _chart;
|
||||
}
|
||||
|
||||
template<class Heuristic, class TypeH>
|
||||
bool AIAStar<Heuristic, TypeH>::findPath(Vect2i from, Heuristic *hr, Std::vector<Vect2i> &path, int directions_count) {
|
||||
_num_point_examine = 0;
|
||||
_num_find_erase = 0;
|
||||
|
||||
_is_used_num++;
|
||||
_open_map.clear();
|
||||
path.clear();
|
||||
if (_is_used_num == 0)
|
||||
clear();//Для того, чтобы вызвалась эта строчка, необходимо гиганское время
|
||||
assert(from.x >= 0 && from.x < _dx && from.y >= 0 && from.y < _dy);
|
||||
_heuristic = hr;
|
||||
|
||||
OnePoint *p = _chart + from.y * _dx + from.x;
|
||||
p->g = 0;
|
||||
p->h = _heuristic->getH(from.x, from.y);
|
||||
p->used = _is_used_num;
|
||||
p->is_open = true;
|
||||
p->parent = NULL;
|
||||
|
||||
_open_map.insert(typename type_point_map::value_type(p->f(), from));
|
||||
|
||||
const int sx[8] = { 0, -1, 0, +1, -1, +1, +1, -1,};
|
||||
const int sy[8] = {-1, 0, +1, 0, -1, -1, +1, +1 };
|
||||
|
||||
// const int sx[size_child]={ 0,-1, 0,+1};
|
||||
// const int sy[size_child]={-1, 0,+1, 0};
|
||||
|
||||
const int size_child = directions_count;
|
||||
|
||||
while (!_open_map.empty()) {
|
||||
typename type_point_map::iterator low = _open_map.begin();
|
||||
Vect2i pt = (*low).second;
|
||||
OnePoint *parent = _chart + pt.y * _dx + pt.x;
|
||||
|
||||
parent->is_open = false;
|
||||
_open_map.erase(low);
|
||||
|
||||
if (_heuristic->isEndPoint(pt.x, pt.y)) {
|
||||
//сконструировать путь
|
||||
Vect2i vp;
|
||||
while (parent) {
|
||||
vp = posBy(parent);;
|
||||
path.push_back(vp);
|
||||
|
||||
if (parent->parent) {
|
||||
Vect2i pp;
|
||||
pp = posBy(parent->parent);
|
||||
assert(abs(vp.x - pp.x) <= 1 &&
|
||||
abs(vp.y - pp.y) <= 1);
|
||||
}
|
||||
|
||||
parent = parent->parent;
|
||||
}
|
||||
assert(vp.x == from.x && vp.y == from.y);
|
||||
Common::reverse(path.begin(), path.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
//для каждого наследника child узла parent
|
||||
for (int i = 0; i < size_child; i++) {
|
||||
Vect2i child = Vect2i(pt.x + sx[i], pt.y + sy[i]);
|
||||
_num_point_examine++;
|
||||
|
||||
if (child.x < 0 || child.y < 0 ||
|
||||
child.x >= _dx || child.y >= _dy)continue;
|
||||
p = _chart + child.y * _dx + child.x;
|
||||
|
||||
|
||||
TypeH addg = _heuristic->getG(pt.x, pt.y, child.x, child.y);
|
||||
TypeH newg = parent->g + addg;
|
||||
|
||||
if (p->used == _is_used_num) {
|
||||
if (!p->is_open)continue;
|
||||
if (p->g <= newg)continue;
|
||||
|
||||
//Удаляем элемент из _open_map
|
||||
TypeH f = p->f();
|
||||
typename type_point_map::iterator cur = _open_map.find(p->f());
|
||||
bool erase = false;
|
||||
while (cur != _open_map.end()) {
|
||||
if ((*cur).first != f)break;
|
||||
if ((*cur).second.x == child.x && (*cur).second.y == child.y) {
|
||||
_open_map.erase(cur);
|
||||
erase = true;
|
||||
break;
|
||||
}
|
||||
_num_find_erase++;
|
||||
cur++;
|
||||
}
|
||||
_num_find_erase++;
|
||||
//assert(erase);
|
||||
if (!erase)
|
||||
continue;
|
||||
}
|
||||
|
||||
p->parent = parent;
|
||||
/*
|
||||
{
|
||||
Vect2i pp=posBy(parent);
|
||||
Vect2i pc=posBy(p);
|
||||
assert(abs(pc.x-pp.x)<=1 &&
|
||||
abs(pc.y-pp.y)<=1);
|
||||
}
|
||||
*/
|
||||
p->g = newg;
|
||||
p->h = _heuristic->getH(child.x, child.y);
|
||||
|
||||
_open_map.insert(typename type_point_map::value_type(p->f(), child));
|
||||
|
||||
p->is_open = true;
|
||||
p->used = _is_used_num;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class Heuristic, class TypeH>
|
||||
void AIAStar<Heuristic, TypeH>::getStatistic(
|
||||
int *p_num_point_examine, int *p_num_find_erase) {
|
||||
if (p_num_point_examine)
|
||||
*p_num_point_examine = _num_point_examine;
|
||||
if (p_num_find_erase)
|
||||
*p_num_find_erase = _num_find_erase;
|
||||
}
|
||||
|
||||
///////////////////////AIAStarGraph/////////////
|
||||
//AIAStarGraph - Так-же поиск пути, но ориентированный на поиск в произвольном графе
|
||||
/*
|
||||
class Node
|
||||
{
|
||||
typedef ... iterator;
|
||||
iterator begin();//Работа со списком связанных с этой Node нод.
|
||||
iterator end();
|
||||
|
||||
void* AIAStarPointer;//Используется в AIAStarGraph
|
||||
};
|
||||
|
||||
class Heuristic
|
||||
{
|
||||
float getH(Node* pos);//Предполагаемые затраты на продвижение из pos1 к окончанию
|
||||
float getG(Node* pos1,Node* pos2);//Затраты на продвижение из pos1 в pos2
|
||||
bool IsEndPoint(Node* pos);//Рекурсия должна окончиться здесь
|
||||
//то есть класс AIAStar позволяет задавать несколько точек окончания поиска пути
|
||||
};
|
||||
*/
|
||||
|
||||
template<class Heuristic, class Node, class TypeH = float>
|
||||
class AIAStarGraph {
|
||||
public:
|
||||
struct OnePoint;
|
||||
typedef Common::MultiMap<TypeH, OnePoint *> type_point_map;
|
||||
|
||||
struct OnePoint {
|
||||
TypeH g;//Затраты на продвижение до этой точки
|
||||
TypeH h;//Предполагаемые затраты на продвижение до финиша
|
||||
int used;
|
||||
OnePoint *parent;
|
||||
bool is_open;
|
||||
|
||||
Node *node;
|
||||
typename type_point_map::iterator self_it;
|
||||
|
||||
inline TypeH f() {
|
||||
return g + h;
|
||||
}
|
||||
};
|
||||
protected:
|
||||
Std::vector<OnePoint> _chart;
|
||||
type_point_map _open_map;
|
||||
|
||||
int _is_used_num;//Если _is_used_num==used, то ячейка используется
|
||||
|
||||
int _num_point_examine;//количество посещённых ячеек
|
||||
int _num_find_erase;//Сколько суммарно искали ячейки для удаления
|
||||
Heuristic *_heuristic;
|
||||
public:
|
||||
AIAStarGraph();
|
||||
~AIAStarGraph();
|
||||
|
||||
//Общее количество узлов. Константа, которая не должна меняться,
|
||||
//пока существует класс, указывающий на неё.
|
||||
void init(Std::vector<Node> &all_node);
|
||||
|
||||
bool findPath(Node *from, Heuristic *h, Std::vector<Node *> &path);
|
||||
void getStatistic(int *num_point_examine, int *num_find_erase);
|
||||
|
||||
//Debug
|
||||
OnePoint *getInternalBuffer() {
|
||||
return _chart;
|
||||
};
|
||||
int getUsedNum() {
|
||||
return _is_used_num;
|
||||
}
|
||||
protected:
|
||||
void clear();
|
||||
inline Node *posBy(OnePoint *p) {
|
||||
return p->node;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Heuristic, class Node, class TypeH>
|
||||
AIAStarGraph<Heuristic, Node, TypeH>::AIAStarGraph() {
|
||||
_heuristic = NULL;
|
||||
_is_used_num = 0;
|
||||
_num_point_examine = 0;
|
||||
_num_find_erase = 0;
|
||||
}
|
||||
|
||||
template<class Heuristic, class Node, class TypeH>
|
||||
void AIAStarGraph<Heuristic, Node, TypeH>::init(Std::vector<Node> &all_node) {
|
||||
int size = all_node.size();
|
||||
_chart.resize(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
OnePoint *c = &_chart[i];
|
||||
c->node = &all_node[i];
|
||||
c->node->AIAStarPointer = (void *)c;
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
template<class Heuristic, class Node, class TypeH>
|
||||
void AIAStarGraph<Heuristic, Node, TypeH>::clear() {
|
||||
_is_used_num = 0;
|
||||
for (auto &it : _chart) {
|
||||
it.used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<class Heuristic, class Node, class TypeH>
|
||||
AIAStarGraph<Heuristic, Node, TypeH>::~AIAStarGraph() {
|
||||
}
|
||||
|
||||
template<class Heuristic, class Node, class TypeH>
|
||||
bool AIAStarGraph<Heuristic, Node, TypeH>::findPath(Node *from, Heuristic *hr, Std::vector<Node *> &path) {
|
||||
_num_point_examine = 0;
|
||||
_num_find_erase = 0;
|
||||
|
||||
_is_used_num++;
|
||||
_open_map.clear();
|
||||
path.clear();
|
||||
if (_is_used_num == 0)
|
||||
clear();//Для того, чтобы вызвалась эта строчка, необходимо гиганское время
|
||||
_heuristic = hr;
|
||||
|
||||
OnePoint *p = (OnePoint *)from->AIAStarPointer;
|
||||
Node *from_node = p->node;
|
||||
p->g = 0;
|
||||
p->h = _heuristic->getH(p->node);
|
||||
p->used = _is_used_num;
|
||||
p->is_open = true;
|
||||
p->parent = NULL;
|
||||
|
||||
p->self_it = _open_map.insert(type_point_map::value_type(p->f(), p));
|
||||
|
||||
while (!_open_map.empty()) {
|
||||
typename type_point_map::iterator low = _open_map.begin();
|
||||
|
||||
OnePoint *parent = low->second;
|
||||
Node *node = parent->node;
|
||||
|
||||
parent->is_open = false;
|
||||
_open_map.erase(low);
|
||||
|
||||
if (_heuristic->IsEndPoint(node)) {
|
||||
//сконструировать путь
|
||||
Node *np;
|
||||
while (parent) {
|
||||
np = PosBy(parent);
|
||||
assert(parent->used == _is_used_num);
|
||||
|
||||
path.push_back(np);
|
||||
parent = parent->parent;
|
||||
}
|
||||
assert(np == from_node);
|
||||
reverse(path.begin(), path.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
//для каждого наследника child узла parent
|
||||
for (auto &it : *node) {
|
||||
Node *cur_node = *it;
|
||||
OnePoint *op = (OnePoint *)cur_node->AIAStarPointer;
|
||||
_num_point_examine++;
|
||||
|
||||
TypeH addg = _heuristic->getG(node, cur_node);
|
||||
TypeH newg = parent->g + addg;
|
||||
|
||||
if (op->used == _is_used_num) {
|
||||
if (!op->is_open)continue;
|
||||
if (op->g <= newg)continue;
|
||||
|
||||
_open_map.erase(op->self_it);
|
||||
_num_find_erase++;
|
||||
}
|
||||
|
||||
op->parent = parent;
|
||||
op->g = newg;
|
||||
op->h = _heuristic->getH(cur_node);
|
||||
|
||||
op->self_it = _open_map.insert(type_point_map::value_type(op->f(), op));
|
||||
|
||||
op->is_open = true;
|
||||
op->used = _is_used_num;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class Heuristic, class Node, class TypeH>
|
||||
void AIAStarGraph<Heuristic, Node, TypeH>::getStatistic(
|
||||
int *p_num_point_examine, int *p_num_find_erase) {
|
||||
if (p_num_point_examine)
|
||||
*p_num_point_examine = _num_point_examine;
|
||||
if (p_num_find_erase)
|
||||
*p_num_find_erase = _num_find_erase;
|
||||
}
|
||||
|
||||
///////////////////////AIFindMaxium/////////////
|
||||
|
||||
/*
|
||||
struct Maps
|
||||
{
|
||||
//Значение чего нибудь в точке (x,y)
|
||||
TypeH get(int x,int y);
|
||||
|
||||
//Дальнейшие поиски можно прекратить
|
||||
bool IsOptiumGood(TypeH optium,int x,int y);
|
||||
};
|
||||
*/
|
||||
|
||||
//Ищет минимальное значение, но не по всей карте
|
||||
template<class Maps>
|
||||
Vect2i AIFindMinium(int x, int y,
|
||||
Maps &maps,
|
||||
int dx, int dy) {
|
||||
typename Maps::TypeH optium = maps.get(x, y);
|
||||
int optiumx = x, optiumy = y;
|
||||
|
||||
int maxi = MAX(MAX(x, dx - x), MAX(y, dy - y));
|
||||
for (int i = 1; i < maxi; i++) {
|
||||
int curx, cury;
|
||||
int xmin = MAX(0, x - i), xmax = MIN(dx - 1, x + i);
|
||||
int ymin = MAX(0, y - i), ymax = MIN(dy - 1, y + i);
|
||||
//up
|
||||
cury = y - i;
|
||||
if (cury >= 0)
|
||||
for (curx = xmin; curx <= xmax; curx++) {
|
||||
typename Maps::TypeH o = maps.get(curx, cury);
|
||||
if (o < optium) {
|
||||
optium = o;
|
||||
optiumx = curx;
|
||||
optiumy = cury;
|
||||
}
|
||||
}
|
||||
|
||||
//down
|
||||
cury = y + i;
|
||||
if (cury < dy)
|
||||
for (curx = xmin; curx <= xmax; curx++) {
|
||||
typename Maps::TypeH o = maps.get(curx, cury);
|
||||
if (o < optium) {
|
||||
optium = o;
|
||||
optiumx = curx;
|
||||
optiumy = cury;
|
||||
}
|
||||
}
|
||||
|
||||
//left
|
||||
curx = x - i;
|
||||
if (curx >= 0)
|
||||
for (cury = ymin; cury <= ymax; cury++) {
|
||||
typename Maps::TypeH o = maps.get(curx, cury);
|
||||
if (o < optium) {
|
||||
optium = o;
|
||||
optiumx = curx;
|
||||
optiumy = cury;
|
||||
}
|
||||
}
|
||||
|
||||
//right
|
||||
curx = x + i;
|
||||
if (curx < dx)
|
||||
for (cury = ymin; cury <= ymax; cury++) {
|
||||
typename Maps::TypeH o = maps.get(curx, cury);
|
||||
if (o < optium) {
|
||||
optium = o;
|
||||
optiumx = curx;
|
||||
optiumy = cury;
|
||||
}
|
||||
}
|
||||
|
||||
if (maps.IsOptiumGood(optium, optiumx, optiumy))
|
||||
break;
|
||||
}
|
||||
|
||||
Vect2i p = {optiumx, optiumy};
|
||||
return p;
|
||||
}
|
||||
} // namespace QDEngine
|
||||
74
engines/qdengine/qdcore/util/AIAStar_API.cpp
Normal file
74
engines/qdengine/qdcore/util/AIAStar_API.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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 "qdengine/qdengine.h"
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/xmath.h"
|
||||
#include "qdengine/qdcore/qd_camera.h"
|
||||
#include "qdengine/qdcore/qd_game_object_moving.h"
|
||||
#include "qdengine/qdcore/util/AIAStar_API.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
qdHeuristic::qdHeuristic() : _camera_ptr(NULL), _object_ptr(NULL) {
|
||||
}
|
||||
|
||||
qdHeuristic::~qdHeuristic() {
|
||||
}
|
||||
|
||||
int qdHeuristic::getH(int x, int y) {
|
||||
x -= _target.x;
|
||||
y -= _target.y;
|
||||
|
||||
if (g_engine->_gameVersion <= 20041201) {
|
||||
return sqrt(static_cast<float>(x * x + y * y));
|
||||
} else {
|
||||
// Достаточно будет эвристики без квадратного корня, который медленный
|
||||
return static_cast<float>(x * x + y * y);
|
||||
}
|
||||
}
|
||||
|
||||
int qdHeuristic::getG(int x1, int y1, int x2, int y2) {
|
||||
if (!_object_ptr->is_walkable(Vect2s(x2, y2)))
|
||||
return 10000;
|
||||
// Для диагональных перемещений смотрим еще и перемещения по катетам,
|
||||
// потому как туда может попасть персонаж из-за погрешностей интерполирования позиции
|
||||
if ((x1 != x2) && (y1 != y2) &&
|
||||
(
|
||||
!_object_ptr->is_walkable(Vect2s(x1, y2)) ||
|
||||
!_object_ptr->is_walkable(Vect2s(x2, y1))
|
||||
))
|
||||
return 10000;
|
||||
|
||||
//return abs(x2 - x1) + abs(y2 - y1);
|
||||
// 14 - приближение корня из 2, умноженного на 10. 10 - единица*10.
|
||||
if ((x1 != x2) && (y1 != y2))
|
||||
return 14;
|
||||
else return 10;
|
||||
}
|
||||
|
||||
void qdHeuristic::init(const Vect3f trg) {
|
||||
_target_f = trg;
|
||||
_target = _camera_ptr->get_cell_index(trg.x, trg.y);
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
66
engines/qdengine/qdcore/util/AIAStar_API.h
Normal file
66
engines/qdengine/qdcore/util/AIAStar_API.h
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_UTIL_AIASTAR_API_H
|
||||
#define QDENGINE_QDCORE_UTIL_AIASTAR_API_H
|
||||
|
||||
#include "qdengine/qdcore/util/AIAStar.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class qdCamera;
|
||||
class qdGameObjectMoving;
|
||||
|
||||
//! Эвристика для поиска пути.
|
||||
class qdHeuristic {
|
||||
public:
|
||||
qdHeuristic();
|
||||
~qdHeuristic();
|
||||
|
||||
int getH(int x, int y);
|
||||
int getG(int x1, int y1, int x2, int y2);
|
||||
bool isEndPoint(int x, int y) {
|
||||
return (x == _target.x && y == _target.y);
|
||||
}
|
||||
|
||||
void init(const Vect3f trg);
|
||||
void set_camera(const qdCamera *cam) {
|
||||
_camera_ptr = cam;
|
||||
}
|
||||
void set_object(const qdGameObjectMoving *obj) {
|
||||
_object_ptr = obj;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Vect2i _target;
|
||||
Vect3f _target_f;
|
||||
|
||||
const qdCamera *_camera_ptr;
|
||||
const qdGameObjectMoving *_object_ptr;
|
||||
};
|
||||
|
||||
typedef AIAStar<qdHeuristic, int> qdAStar;
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // _AIASTAR_API_H
|
||||
121
engines/qdengine/qdcore/util/Filters.h
Normal file
121
engines/qdengine/qdcore/util/Filters.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/* 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 QDENGINE_QDCORE_UTIL_FILTERS_H
|
||||
#define QDENGINE_QDCORE_UTIL_FILTERS_H
|
||||
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
namespace scl {
|
||||
|
||||
class CGenericFilter {
|
||||
public:
|
||||
CGenericFilter(double dWidth) : _dWidth(dWidth) {}
|
||||
virtual ~CGenericFilter() {}
|
||||
|
||||
double getWidth() const {
|
||||
return _dWidth;
|
||||
}
|
||||
void setWidth(double dWidth) {
|
||||
_dWidth = dWidth;
|
||||
}
|
||||
|
||||
virtual double filter(double dVal) = 0;
|
||||
|
||||
protected:
|
||||
|
||||
#define FILTER_PI double (3.1415926535897932384626433832795)
|
||||
#define FILTER_2PI double (2.0 * 3.1415926535897932384626433832795)
|
||||
#define FILTER_4PI double (4.0 * 3.1415926535897932384626433832795)
|
||||
|
||||
double _dWidth;
|
||||
};
|
||||
|
||||
class CBoxFilter : public CGenericFilter {
|
||||
public:
|
||||
CBoxFilter(double dWidth = double(0.5)) : CGenericFilter(dWidth) {}
|
||||
~CBoxFilter() {}
|
||||
|
||||
double filter(double dVal) {
|
||||
return (fabs(dVal) <= _dWidth ? 1.0 : 0.0);
|
||||
}
|
||||
};
|
||||
|
||||
class CBilinearFilter : public CGenericFilter {
|
||||
public:
|
||||
CBilinearFilter(double dWidth = double(1.0)) : CGenericFilter(dWidth) {}
|
||||
~CBilinearFilter() {}
|
||||
|
||||
double filter(double dVal) {
|
||||
dVal = fabs(dVal);
|
||||
return (dVal < _dWidth ? _dWidth - dVal : 0.0);
|
||||
}
|
||||
};
|
||||
|
||||
class CGaussianFilter : public CGenericFilter {
|
||||
public:
|
||||
CGaussianFilter(double dWidth = double(3.0)) : CGenericFilter(dWidth) {}
|
||||
~CGaussianFilter() {}
|
||||
|
||||
double filter(double dVal) {
|
||||
if (fabs(dVal) > _dWidth) {
|
||||
return 0.0;
|
||||
}
|
||||
return exp(-dVal * dVal / 2.0) / sqrt(FILTER_2PI);
|
||||
}
|
||||
};
|
||||
|
||||
class CHammingFilter : public CGenericFilter {
|
||||
public:
|
||||
CHammingFilter(double dWidth = double(0.5)) : CGenericFilter(dWidth) {}
|
||||
~CHammingFilter() {}
|
||||
|
||||
double filter(double dVal) {
|
||||
if (fabs(dVal) > _dWidth)
|
||||
return 0.0;
|
||||
|
||||
double dWindow = 0.54 + 0.46 * cos(FILTER_2PI * dVal);
|
||||
double dSinc = (dVal == 0) ? 1.0 : sin(FILTER_PI * dVal) / (FILTER_PI * dVal);
|
||||
return dWindow * dSinc;
|
||||
}
|
||||
};
|
||||
|
||||
class CBlackmanFilter : public CGenericFilter {
|
||||
public:
|
||||
CBlackmanFilter(double dWidth = double(0.5)) : CGenericFilter(dWidth) {}
|
||||
~CBlackmanFilter() {}
|
||||
|
||||
double filter(double dVal) {
|
||||
if (fabs(dVal) > _dWidth)
|
||||
return 0.0;
|
||||
|
||||
double dN = 2.0 * _dWidth + 1.0;
|
||||
return 0.42 + 0.5 * cos(FILTER_2PI * dVal / (dN - 1.0)) + 0.08 * cos(FILTER_4PI * dVal / (dN - 1.0));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace scl
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_FILTERS_H
|
||||
178
engines/qdengine/qdcore/util/Handle.h
Normal file
178
engines/qdengine/qdcore/util/Handle.h
Normal file
@@ -0,0 +1,178 @@
|
||||
/* 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 QDENGINE_QDCORE_UTIL_HANDLE_H
|
||||
#define QDENGINE_QDCORE_UTIL_HANDLE_H
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Автоматически удаляемый указатель
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class T>
|
||||
class PtrHandle {
|
||||
public:
|
||||
PtrHandle(T *p = 0) : ptr(p) {}
|
||||
PtrHandle(PtrHandle &p) : ptr(p.release()) {}
|
||||
~PtrHandle() {
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
void set(T *p) {
|
||||
ptr = p;
|
||||
}
|
||||
|
||||
PtrHandle &operator=(PtrHandle &p) {
|
||||
if (get() != p.get()) {
|
||||
delete ptr;
|
||||
ptr = p.release();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
PtrHandle &operator=(T *p) {
|
||||
if (get() != p)
|
||||
delete ptr;
|
||||
set(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *get() const {
|
||||
return ptr;
|
||||
}
|
||||
T *release() {
|
||||
T *tmp = ptr;
|
||||
ptr = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T *operator->() const {
|
||||
return ptr;
|
||||
}
|
||||
T &operator*() const {
|
||||
return *ptr;
|
||||
}
|
||||
T *operator()() const {
|
||||
return ptr;
|
||||
}
|
||||
operator T *() const {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
T *ptr;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Автоматически удаляемый указатель
|
||||
// с отслеживанием владельцев.
|
||||
// Обекты должны наследовать ShareHandleBase
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class T>
|
||||
class ShareHandle {
|
||||
public:
|
||||
ShareHandle(T *p = 0) {
|
||||
set(p);
|
||||
}
|
||||
ShareHandle(const ShareHandle &orig) {
|
||||
set(orig.ptr);
|
||||
}
|
||||
|
||||
~ShareHandle() {
|
||||
if (ptr && !ptr->decrRef())
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
void set(T *p) {
|
||||
ptr = p;
|
||||
if (p)
|
||||
p->addRef();
|
||||
}
|
||||
|
||||
ShareHandle &operator=(const ShareHandle &orig) {
|
||||
if (ptr && !ptr->decrRef() && ptr != orig.ptr)
|
||||
delete ptr;
|
||||
set(orig.ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ShareHandle &operator=(T *p) {
|
||||
if (ptr && !ptr->decrRef() && ptr != p)
|
||||
delete ptr;
|
||||
set(p);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T *get() const {
|
||||
return ptr;
|
||||
}
|
||||
T *release() {
|
||||
T *tmp = ptr;
|
||||
if (ptr) ptr->decrRef();
|
||||
ptr = 0;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T *operator->() const {
|
||||
return ptr;
|
||||
}
|
||||
T &operator*() const {
|
||||
return *ptr;
|
||||
}
|
||||
T *operator()() const {
|
||||
return ptr;
|
||||
}
|
||||
operator T *() const {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
T *ptr;
|
||||
};
|
||||
|
||||
class ShareHandleBase {
|
||||
public:
|
||||
ShareHandleBase() {
|
||||
handleCount = 0;
|
||||
}
|
||||
ShareHandleBase(const ShareHandleBase &) {
|
||||
handleCount = 0;
|
||||
}
|
||||
~ShareHandleBase() {}
|
||||
void addRef() {
|
||||
++handleCount;
|
||||
}
|
||||
int decrRef() {
|
||||
return --handleCount;
|
||||
}
|
||||
int numRef() const {
|
||||
return handleCount;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable int handleCount;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_HANDLE_H
|
||||
174
engines/qdengine/qdcore/util/LZ77.cpp
Normal file
174
engines/qdengine/qdcore/util/LZ77.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
// Implementation of pure LZ77 looseless compression.
|
||||
// Modification of this algorithm was used for NTFS compression.
|
||||
//
|
||||
// Implemented by Arkadi Kagan.
|
||||
//
|
||||
#include "common/endian.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "qdengine/qdcore/util/LZ77.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
#define BITS_LEN 4
|
||||
|
||||
CLZ77::CLZ77() {
|
||||
}
|
||||
CLZ77::~CLZ77() {
|
||||
}
|
||||
|
||||
int32 CLZ77::lzComp(const byte *s1, const byte *s2, int32 maxlen) {
|
||||
int32 i;
|
||||
for (i = 0; i < maxlen; i++)
|
||||
if (s1[i] != s2[i])
|
||||
return i;
|
||||
return maxlen;
|
||||
}
|
||||
const byte *CLZ77::findLZ(const byte *source, const byte *s, int32 slen, int32 border, int32 mlen, int32 &len) {
|
||||
int32 maxlen = 0;
|
||||
int32 limit = slen - (s - source);
|
||||
const byte *maxp = s - 1;
|
||||
const byte *p;
|
||||
len = 0;
|
||||
for (p = s - 1; p >= source; p--) {
|
||||
len = lzComp(p, s, limit);
|
||||
if (len > maxlen) {
|
||||
maxp = p;
|
||||
maxlen = len;
|
||||
}
|
||||
if (s - p >= border - 1) break;
|
||||
if (len >= mlen - 1) break;
|
||||
}
|
||||
len = MIN(maxlen, mlen - 1);
|
||||
return maxp;
|
||||
}
|
||||
|
||||
int32 CLZ77::getMaxEncoded(int32 len) {
|
||||
return len + sizeof(uint32);
|
||||
}
|
||||
int32 CLZ77::getMaxDecoded(byte *source) {
|
||||
return ((uint32 *)source)[0];
|
||||
}
|
||||
void CLZ77::encode(byte *target, int32 &tlen, const byte *source, int32 slen) {
|
||||
int32 len, block;
|
||||
int32 shift, border;
|
||||
const byte *s, *p;
|
||||
byte *t;
|
||||
byte *flag;
|
||||
uint16 *ptmp;
|
||||
|
||||
((uint32 *)target)[0] = slen; // save source size
|
||||
target += sizeof(uint32);
|
||||
tlen = sizeof(uint32);
|
||||
|
||||
block = 0; // block - bit in single flag byte
|
||||
shift = 16; // shift offset to most significant bits
|
||||
border = 1; // offset can`t be more then border
|
||||
flag = target; // flag for every 8 entities
|
||||
tlen++; // byte for first flag
|
||||
*flag = 0;
|
||||
s = (const byte *)source;
|
||||
t = target + 1;
|
||||
for (s = (const byte *)source; s - source < slen;) {
|
||||
if (shift > BITS_LEN)
|
||||
while (s - source >= border) {
|
||||
if (shift <= BITS_LEN) break;
|
||||
border = border << 1;
|
||||
shift--;
|
||||
}
|
||||
p = findLZ((const byte *)source, s, slen, border, (1 << shift), len);
|
||||
if (len <= 2) len = 1;
|
||||
if (len <= 1) {
|
||||
*t++ = *s++;
|
||||
tlen++;
|
||||
} else {
|
||||
ptmp = (uint16 *)t;
|
||||
*ptmp = (uint16)(((s - p - 1) << shift) + len);
|
||||
|
||||
*flag |= 1 << block;
|
||||
t += 2;
|
||||
tlen += 2;
|
||||
s += len;
|
||||
}
|
||||
if (++block >= 8) {
|
||||
flag = t++;
|
||||
*flag = 0;
|
||||
block = 0;
|
||||
tlen++;
|
||||
}
|
||||
/* if (tlen >= slen)
|
||||
{
|
||||
tlen = 0;
|
||||
return;
|
||||
}*/
|
||||
// OnStep();
|
||||
}
|
||||
}
|
||||
int32 CLZ77::decode(byte *target, int32 &tlen, const byte *source, int32 slen) {
|
||||
uint32 i;
|
||||
uint32 block, len;
|
||||
uint32 shift, border;
|
||||
const byte *s;
|
||||
byte *t, *p;
|
||||
const byte *flag;
|
||||
uint16 tmp;
|
||||
|
||||
tlen = READ_LE_UINT32(source);
|
||||
source += sizeof(uint32); // read/remove target size
|
||||
slen -= sizeof(uint32);
|
||||
|
||||
t = target;
|
||||
flag = (const byte *)source;
|
||||
block = 0; // block - bit in single flag byte
|
||||
shift = 16; // shift offset to most significant bits
|
||||
border = 1; // offset can`t be more then border
|
||||
for (s = (const byte *)source + 1; (s < source + slen) && (t - target < tlen);) {
|
||||
if (shift > BITS_LEN)
|
||||
while (t - target >= (int)border) {
|
||||
if (shift <= BITS_LEN) break;
|
||||
border = border << 1;
|
||||
shift--;
|
||||
}
|
||||
if (flag[0] & (1 << block)) {
|
||||
tmp = READ_LE_UINT16(s);
|
||||
len = ((1 << shift) - 1) & tmp;
|
||||
p = t - (tmp >> shift) - 1;
|
||||
for (i = 0; i < len; i++)
|
||||
t[i] = p[i];
|
||||
t += len;
|
||||
s += 2;
|
||||
} else {
|
||||
*t++ = *s++;
|
||||
//len = 1;
|
||||
}
|
||||
if (++block >= 8) {
|
||||
flag = s++;
|
||||
block = 0;
|
||||
}
|
||||
// OnStep();
|
||||
}
|
||||
return (s - source) + sizeof(uint32);
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
46
engines/qdengine/qdcore/util/LZ77.h
Normal file
46
engines/qdengine/qdcore/util/LZ77.h
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_UTIL_LZ77_H
|
||||
#define QDENGINE_QDCORE_UTIL_LZ77_H
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class CLZ77 {
|
||||
private:
|
||||
int32 lzComp(const byte *s1, const byte *s2, int32 maxlen);
|
||||
const byte *findLZ(const byte *source, const byte *s, int32 slen, int32 border, int32 mlen, int32 &len);
|
||||
public:
|
||||
CLZ77();
|
||||
virtual ~CLZ77();
|
||||
|
||||
void encode(byte *target, int32 &tlen, const byte *source, int32 slen);
|
||||
int32 decode(byte *target, int32 &tlen, const byte *source, int32 slen);
|
||||
int32 getMaxEncoded(int32 len);
|
||||
int32 getMaxDecoded(byte *source);
|
||||
|
||||
// virtual void OnStep() = 0;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_LZ77_H
|
||||
76
engines/qdengine/qdcore/util/ResourceDispatcher.cpp
Normal file
76
engines/qdengine/qdcore/util/ResourceDispatcher.cpp
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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
#include "qdengine/qdengine.h"
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/util/ResourceDispatcher.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
int ResourceUser::IDs;
|
||||
|
||||
void ResourceDispatcher::do_start() {
|
||||
if (_start_log) {
|
||||
_start_log = false;
|
||||
_syncro_timer.setTime(1);
|
||||
for (UserList::iterator i = users.begin(); i != users.end(); ++i)
|
||||
(*i)->time = _syncro_timer();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceDispatcher::reset() {
|
||||
for (UserList::iterator i = users.begin(); i != users.end(); ++i)
|
||||
(*i)->time = _syncro_timer();
|
||||
}
|
||||
|
||||
void ResourceDispatcher::quant() {
|
||||
debugC(9, kDebugQuant, "ResourceDispatcher::quant()");
|
||||
if (users.empty())
|
||||
return;
|
||||
|
||||
do_start();
|
||||
|
||||
_syncro_timer.next_frame();
|
||||
|
||||
for (;;) {
|
||||
time_type t_min = users.front()->time;
|
||||
ResourceUser *user_min = users.front();
|
||||
for (UserList::iterator i = users.begin(); i != users.end(); ++i) {
|
||||
ResourceUser &u = **i;
|
||||
if (t_min > u.time) {
|
||||
t_min = u.time;
|
||||
user_min = &u;
|
||||
}
|
||||
}
|
||||
if (t_min < _syncro_timer.operator()()) {
|
||||
if (!user_min->quant()) {
|
||||
debugC(3, kDebugQuant, "ResourceDispatcher::quant() user_min->time = %d", user_min->time);
|
||||
detach(user_min);
|
||||
} else
|
||||
user_min->time += user_min->time_step();
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace QDEngine
|
||||
152
engines/qdengine/qdcore/util/ResourceDispatcher.h
Normal file
152
engines/qdengine/qdcore/util/ResourceDispatcher.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/* 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 QDENGINE_QDCORE_UTIL_RESOURCE_DISPATCHER_H
|
||||
#define QDENGINE_QDCORE_UTIL_RESOURCE_DISPATCHER_H
|
||||
|
||||
#include "qdengine/qdcore/util/Handle.h"
|
||||
#include "qdengine/qdcore/util/SynchroTimer.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// General Time Resourcing
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
class ResourceUser {
|
||||
int ID;
|
||||
static int IDs;
|
||||
public:
|
||||
ResourceUser(time_type period) {
|
||||
dtime = period;
|
||||
time = 0;
|
||||
ID = ++IDs;
|
||||
}
|
||||
virtual ~ResourceUser() {}
|
||||
virtual int quant() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
time_type time;
|
||||
time_type dtime;
|
||||
|
||||
virtual void init_time(time_type time_) {
|
||||
time = time_ + time_step();
|
||||
}
|
||||
virtual time_type time_step() {
|
||||
return dtime;
|
||||
}
|
||||
|
||||
friend class ResourceDispatcher;
|
||||
};
|
||||
|
||||
class VoidFunctionCallResourceUser : public ResourceUser {
|
||||
public:
|
||||
typedef void (*type)();
|
||||
|
||||
VoidFunctionCallResourceUser(type func_, time_type dtime_) :
|
||||
ResourceUser(dtime_), func(func_) {}
|
||||
virtual ~VoidFunctionCallResourceUser() {}
|
||||
int quant() {
|
||||
func();
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
type func;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class MemberFunctionCallResourceUser : public ResourceUser {
|
||||
public:
|
||||
typedef void (T::*type)();
|
||||
|
||||
MemberFunctionCallResourceUser(T &object_, type func_, time_type dtime_) :
|
||||
ResourceUser(dtime_), object(object_), func(func_) {}
|
||||
virtual ~MemberFunctionCallResourceUser() {}
|
||||
int quant() {
|
||||
(object.*func)();
|
||||
return 1;
|
||||
}
|
||||
|
||||
protected:
|
||||
T &object;
|
||||
type func;
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Resource Dispatcher
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
class ResourceDispatcher {
|
||||
public:
|
||||
ResourceDispatcher() : _start_log(false), _max_time_interval(0) { }
|
||||
void setTimer(int syncro_by_clock, time_type time_per_frame, time_type max_time_interval_) {
|
||||
_syncro_timer.set(syncro_by_clock, time_per_frame, _max_time_interval = max_time_interval_);
|
||||
}
|
||||
|
||||
void attach(ResourceUser *user) {
|
||||
PtrHandle<ResourceUser> p(0);
|
||||
users.push_back(p);
|
||||
users.back() = user;
|
||||
user->init_time(_syncro_timer());
|
||||
}
|
||||
void attach(void (*func)(), time_type dtime) {
|
||||
attach(new VoidFunctionCallResourceUser(func, dtime));
|
||||
}
|
||||
template<class T>
|
||||
void attach(T &obj, void (T::*func)(), time_type dtime) {
|
||||
attach(new MemberFunctionCallResourceUser<T>(obj, func, dtime));
|
||||
}
|
||||
void detach(ResourceUser *user) {
|
||||
PtrHandle<ResourceUser> p(user);
|
||||
users.remove(p);
|
||||
p.set(0);
|
||||
}
|
||||
|
||||
void start() {
|
||||
_start_log = true;
|
||||
}
|
||||
void reset();
|
||||
void skip_time() {
|
||||
_syncro_timer.skip();
|
||||
}
|
||||
void quant();
|
||||
void set_speed(float speed) {
|
||||
_syncro_timer.setSpeed(speed);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typedef Std::list<PtrHandle<ResourceUser> > UserList;
|
||||
UserList users;
|
||||
|
||||
SyncroTimer _syncro_timer;
|
||||
time_type _max_time_interval;
|
||||
bool _start_log;
|
||||
|
||||
void do_start();
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_RESOURCE_DISPATCHER_H
|
||||
105
engines/qdengine/qdcore/util/SynchroTimer.h
Normal file
105
engines/qdengine/qdcore/util/SynchroTimer.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/* 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 QDENGINE_QDCORE_UTIL_SYNCRO_TIMER
|
||||
#define QDENGINE_QDCORE_UTIL_SYNCRO_TIMER
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
typedef uint32 time_type;
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class SyncroTimer {
|
||||
public:
|
||||
// Main property
|
||||
time_type operator()() const {
|
||||
return round(_time);
|
||||
}
|
||||
// Last delta
|
||||
time_type delta() const {
|
||||
return _time - _time_prev;
|
||||
}
|
||||
|
||||
SyncroTimer() {
|
||||
set(1, 15, 100);
|
||||
_time_prev = _time = 1;
|
||||
_time_offset = 0;
|
||||
_time_speed = 1;
|
||||
}
|
||||
|
||||
void set(int syncro_by_clock, time_type time_per_frame, time_type max_time_interval) {
|
||||
_syncro_by_clock = syncro_by_clock;
|
||||
_time_per_frame = time_per_frame;
|
||||
_max_time_interval = max_time_interval;
|
||||
}
|
||||
|
||||
SyncroTimer &adjust() {
|
||||
_time_prev = _time;
|
||||
|
||||
if (_syncro_by_clock) {
|
||||
float t = float(g_system->getMillis());
|
||||
float dt = (t - _time - _time_offset) * _time_speed;
|
||||
if (dt > _max_time_interval)
|
||||
dt = _max_time_interval;
|
||||
_time += dt;
|
||||
_time_offset = t - _time;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void next_frame() {
|
||||
if (_syncro_by_clock)
|
||||
adjust();
|
||||
else {
|
||||
_time_prev = _time;
|
||||
_time += _time_per_frame * _time_speed;
|
||||
// _time += round(_time_per_frame*_time_speed);
|
||||
}
|
||||
}
|
||||
|
||||
void skip() {
|
||||
if (_syncro_by_clock)
|
||||
_time_offset = g_system->getMillis() - _time;
|
||||
}
|
||||
|
||||
void setTime(time_type t) {
|
||||
_time_prev = _time = t;
|
||||
_time_offset = _syncro_by_clock ? g_system->getMillis() - _time : 0;
|
||||
}
|
||||
|
||||
void setSpeed(float speed) {
|
||||
_time_speed = speed;
|
||||
}
|
||||
|
||||
private:
|
||||
float _time;
|
||||
float _time_prev;
|
||||
float _time_offset;
|
||||
time_type _max_time_interval;
|
||||
time_type _time_per_frame;
|
||||
int _syncro_by_clock;
|
||||
float _time_speed;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_SYNCRO_TIMER
|
||||
177
engines/qdengine/qdcore/util/WinVideo.cpp
Normal file
177
engines/qdengine/qdcore/util/WinVideo.cpp
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/>.
|
||||
*
|
||||
*/
|
||||
#include "common/config-manager.h"
|
||||
#include "common/file.h"
|
||||
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
#include "video/mpegps_decoder.h"
|
||||
|
||||
#include "qdengine/qdengine.h"
|
||||
#include "qdengine/qdcore/util/WinVideo.h"
|
||||
|
||||
#include "qdengine/system/graphics/gr_dispatcher.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
bool winVideo::_is_initialized = false;
|
||||
|
||||
winVideo::winVideo() {
|
||||
_decoder = new Video::MPEGPSDecoder();
|
||||
_x = _y = 0;
|
||||
_vidWidth = _vidHeight = 0;
|
||||
_videostream = nullptr;
|
||||
}
|
||||
|
||||
winVideo::~winVideo() {
|
||||
close_file();
|
||||
delete _decoder;
|
||||
}
|
||||
|
||||
bool winVideo::init() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool winVideo::done() {
|
||||
if (!_is_initialized)
|
||||
return false;
|
||||
|
||||
_is_initialized = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void winVideo::set_window(int x, int y, int xsize, int ysize) {
|
||||
_x = x;
|
||||
_y = y;
|
||||
|
||||
_vidWidth = xsize;
|
||||
_vidHeight = ysize;
|
||||
|
||||
delete _tempSurf;
|
||||
_tempSurf = nullptr;
|
||||
|
||||
if (_vidWidth != _decoder->getWidth() || _vidHeight != _decoder->getHeight())
|
||||
_tempSurf = new Graphics::ManagedSurface(xsize, ysize, g_engine->_pixelformat);
|
||||
}
|
||||
|
||||
bool winVideo::open_file(const Common::Path &fname) {
|
||||
Common::String filename = (char *)transCyrillic(fname.toString());
|
||||
debugC(3, kDebugLoad, "winVideo::open_file(%s)", filename.c_str());
|
||||
|
||||
_videostream = new Common::File();
|
||||
|
||||
if (!_videostream->open(filename.c_str())) {
|
||||
// Try with punyencoded path
|
||||
if (!_videostream->open(Common::Path(filename).punycodeEncode())) {
|
||||
warning("WinVideo::open: Failed to open file %s", filename.c_str());
|
||||
delete _videostream;
|
||||
_videostream = nullptr;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// WORKAROUND: Fix lagging audio in mng and rybalka
|
||||
// videos by setting specific number of prebuffered packets
|
||||
// for MPEG-PS demuxer.
|
||||
Common::String gameId = g_engine->getGameId();
|
||||
if (gameId == "mng" || gameId == "rybalka") {
|
||||
_decoder->setPrebufferedPackets(600);
|
||||
}
|
||||
|
||||
if (!_decoder->loadStream(_videostream)) {
|
||||
warning("WinVideo::open: Failed to Load Stream for file '%s'", filename.c_str());
|
||||
_videostream = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool winVideo::play() {
|
||||
if (!_videostream) {
|
||||
warning("WinVideo::play: No video stream loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
_decoder->setVolume(ConfMan.getInt("music_volume"));
|
||||
_decoder->start();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool winVideo::quant() {
|
||||
debugC(9, kDebugGraphics, "WinVideo::play: Video Playback loop");
|
||||
|
||||
// Video Playback loop
|
||||
if (_decoder->needsUpdate()) {
|
||||
const Graphics::Surface *frame = _decoder->decodeNextFrame();
|
||||
int frameWidth = _decoder->getWidth();
|
||||
int frameHeight = _decoder->getHeight();
|
||||
|
||||
const Graphics::Surface *surf = frame;
|
||||
|
||||
if (frame) {
|
||||
if (_tempSurf) {
|
||||
const Common::Rect srcRect(0, 0, frameWidth, frameHeight);
|
||||
const Common::Rect destRect(0, 0, _vidWidth, _vidHeight);
|
||||
|
||||
_tempSurf->blitFrom(*frame, srcRect, destRect);
|
||||
surf = _tempSurf->surfacePtr();
|
||||
}
|
||||
|
||||
g_system->copyRectToScreen(surf->getPixels(), surf->pitch, _x, _y, _vidWidth, _vidHeight);
|
||||
}
|
||||
|
||||
g_system->delayMillis(10);
|
||||
g_system->updateScreen();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool winVideo::stop() {
|
||||
delete _tempSurf;
|
||||
_tempSurf = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool winVideo::is_playback_finished() {
|
||||
return _decoder->endOfVideo();
|
||||
}
|
||||
|
||||
bool winVideo::get_movie_size(int &sx, int &sy) {
|
||||
if (!_decoder)
|
||||
return false;
|
||||
|
||||
sx = _decoder->getWidth();
|
||||
sy = _decoder->getHeight();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void winVideo::close_file() {
|
||||
if (_videostream)
|
||||
_videostream->close();
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
86
engines/qdengine/qdcore/util/WinVideo.h
Normal file
86
engines/qdengine/qdcore/util/WinVideo.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* 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 QDENGINE_QDCORE_UTIL_WINVIDEO_H
|
||||
#define QDENGINE_QDCORE_UTIL_WINVIDEO_H
|
||||
|
||||
//#define __WINVIDEO_LOG__
|
||||
|
||||
namespace Video {
|
||||
class MPEGPSDecoder;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
class ManagedSurface;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
class File;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class winVideo {
|
||||
public:
|
||||
enum PlaybackStatus {
|
||||
VID_RUNNING,
|
||||
VID_STOPPED,
|
||||
VID_PAUSED
|
||||
};
|
||||
|
||||
winVideo();
|
||||
~winVideo();
|
||||
|
||||
static bool init(); // initialize DirectShow Lib
|
||||
static bool done(); // uninitialize DirectShow Lib
|
||||
|
||||
bool open_file(const Common::Path &fname);
|
||||
void close_file();
|
||||
|
||||
bool play();
|
||||
bool stop();
|
||||
bool quant();
|
||||
bool is_playback_finished();
|
||||
|
||||
void set_window(int x = 0, int y = 0, int xsize = 0, int ysize = 0);
|
||||
bool get_movie_size(int &sx, int &sy);
|
||||
bool set_window_size(int sx, int sy);
|
||||
|
||||
private:
|
||||
// Coordinates of the top left corner of the video
|
||||
int _x;
|
||||
int _y;
|
||||
|
||||
int _vidWidth;
|
||||
int _vidHeight;
|
||||
|
||||
Graphics::ManagedSurface *_tempSurf = nullptr;
|
||||
|
||||
// Video decoder
|
||||
Video::MPEGPSDecoder *_decoder;
|
||||
Common::File *_videostream;
|
||||
|
||||
static bool _is_initialized;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_WINVIDEO_H
|
||||
84
engines/qdengine/qdcore/util/fps_counter.cpp
Normal file
84
engines/qdengine/qdcore/util/fps_counter.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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/system.h"
|
||||
|
||||
#include "qdengine/qdcore/util/fps_counter.h"
|
||||
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
fpsCounter::fpsCounter(int period) : _start_time(0.0f),
|
||||
_prev_time(0.0f),
|
||||
_period(period),
|
||||
_frame_count(0),
|
||||
_value(-1.0f),
|
||||
_value_min(0.0f),
|
||||
_value_max(0.0f),
|
||||
_min_frame_time(1000.0f),
|
||||
_max_frame_time(0.0f) {
|
||||
}
|
||||
|
||||
bool fpsCounter::quant() {
|
||||
float time = float(g_system->getMillis());
|
||||
|
||||
if (_min_frame_time > time - _prev_time)
|
||||
_min_frame_time = time - _prev_time;
|
||||
|
||||
if (_max_frame_time < time - _prev_time)
|
||||
_max_frame_time = time - _prev_time;
|
||||
|
||||
_frame_count++;
|
||||
_prev_time = time;
|
||||
|
||||
if (_period) {
|
||||
if (_prev_time - _start_time >= _period) {
|
||||
_value = float(_frame_count) / (_prev_time - _start_time) * 1000.0f;
|
||||
|
||||
_value_min = 1000.0f / _max_frame_time;
|
||||
_value_max = 1000.0f / _min_frame_time;
|
||||
|
||||
_frame_count = 0;
|
||||
_start_time = _prev_time;
|
||||
|
||||
_min_frame_time = 10000.0f;
|
||||
_max_frame_time = 0.0f;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
_value = float(_frame_count) / (float(g_system->getMillis()) - _start_time) * 1000.0f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void fpsCounter::reset() {
|
||||
_prev_time = _start_time = float(g_system->getMillis());
|
||||
_frame_count = 0;
|
||||
_value = -1.0f;
|
||||
_value_min = _value_max = 0.0f;
|
||||
|
||||
_min_frame_time = 10000.0f;
|
||||
_max_frame_time = 0.0f;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
73
engines/qdengine/qdcore/util/fps_counter.h
Normal file
73
engines/qdengine/qdcore/util/fps_counter.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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_UTIL_FPS_COUNTER_H
|
||||
#define QDENGINE_QDCORE_UTIL_FPS_COUNTER_H
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class fpsCounter {
|
||||
public:
|
||||
fpsCounter(int period = 3000);
|
||||
~fpsCounter() { }
|
||||
|
||||
bool quant();
|
||||
|
||||
float fps_value() const {
|
||||
return _value;
|
||||
}
|
||||
float fps_value_min() const {
|
||||
return _value_min;
|
||||
}
|
||||
float fps_value_max() const {
|
||||
return _value_max;
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
int period() const {
|
||||
return _period;
|
||||
}
|
||||
void set_period(int p) {
|
||||
_period = p;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
float _start_time;
|
||||
float _prev_time;
|
||||
|
||||
int _frame_count;
|
||||
|
||||
int _period;
|
||||
|
||||
float _value;
|
||||
float _value_min;
|
||||
float _value_max;
|
||||
|
||||
float _min_frame_time;
|
||||
float _max_frame_time;
|
||||
};
|
||||
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_FPS_COUNTER_H
|
||||
180
engines/qdengine/qdcore/util/plaympp_api.cpp
Normal file
180
engines/qdengine/qdcore/util/plaympp_api.cpp
Normal file
@@ -0,0 +1,180 @@
|
||||
/* 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/config-manager.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/vorbis.h"
|
||||
#include "audio/decoders/mpc.h"
|
||||
|
||||
#include "qdengine/qdengine.h"
|
||||
#include "qdengine/qd_fwd.h"
|
||||
#include "qdengine/qdcore/qd_file_manager.h"
|
||||
#include "qdengine/qdcore/util/plaympp_api.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
mpegPlayer::mpegPlayer() : _is_enabled(true),
|
||||
_volume(255),
|
||||
_cur_track_volume(255),
|
||||
_paused(false) {
|
||||
}
|
||||
|
||||
mpegPlayer::~mpegPlayer() {
|
||||
}
|
||||
|
||||
bool mpegPlayer::play(const Common::Path &file, bool loop, int vol) {
|
||||
bool isOGG = file.baseName().hasSuffixIgnoreCase(".ogg");
|
||||
|
||||
debugC(1, kDebugSound, "mpegPlayer::play(%s, %d, %d)", file.toString().c_str(), loop, vol);
|
||||
|
||||
_file = file;
|
||||
|
||||
stop();
|
||||
|
||||
Common::SeekableReadStream *stream;
|
||||
|
||||
if (!qdFileManager::instance().open_file(&stream, file, false)) {
|
||||
if (!qdFileManager::instance().open_file(&stream, file.punycodeEncode(), false)) {
|
||||
warning(" mpegPlayer::play(): Failed to open file %s", file.toString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Audio::SeekableAudioStream *audiostream;
|
||||
|
||||
if (isOGG) {
|
||||
#ifdef USE_VORBIS
|
||||
audiostream = Audio::makeVorbisStream(stream, DisposeAfterUse::YES);
|
||||
#else
|
||||
warning("mpegPlayer::play(%s, %d, %d): Vorbis support not compiled", file.toString().c_str(), loop, vol);
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef USE_MPCDEC
|
||||
audiostream = Audio::makeMPCStream(stream, DisposeAfterUse::YES);
|
||||
#else
|
||||
warning("mpegPlayer::play(%s, %d, %d): MPC support not compiled", file.toString().c_str(), loop, vol);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!loop) {
|
||||
g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, audiostream);
|
||||
} else {
|
||||
Audio::LoopingAudioStream *looped = new Audio::LoopingAudioStream(audiostream, 0, DisposeAfterUse::YES);
|
||||
|
||||
g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, looped);
|
||||
}
|
||||
|
||||
set_volume(vol);
|
||||
|
||||
_paused = false;
|
||||
|
||||
debugC(1, kDebugSound, "mpegPlayer::play(%s)", _file.toString().c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mpegPlayer::stop() {
|
||||
debugC(1, kDebugSound, "mpegPlayer::stop(%s)", _file.toString().c_str());
|
||||
|
||||
g_system->getMixer()->stopHandle(_soundHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mpegPlayer::pause() {
|
||||
if (_paused)
|
||||
return true;
|
||||
|
||||
debugC(1, kDebugSound, "mpegPlayer::pause(%s)", _file.toString().c_str());
|
||||
|
||||
g_system->getMixer()->pauseHandle(_soundHandle, true);
|
||||
_paused = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mpegPlayer::resume() {
|
||||
if (!_paused)
|
||||
return true;
|
||||
|
||||
debugC(1, kDebugSound, "mpegPlayer::resume(%s)", _file.toString().c_str());
|
||||
|
||||
g_system->getMixer()->pauseHandle(_soundHandle, false);
|
||||
_paused = false;
|
||||
|
||||
g_system->getMixer()->setChannelVolume(_soundHandle, _volume * _cur_track_volume / 256);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
mpegPlayer::mpeg_status_t mpegPlayer::status() const {
|
||||
mpeg_status_t res;
|
||||
|
||||
if (!g_system->getMixer()->isReady())
|
||||
res = MPEG_STOPPED;
|
||||
else if (_paused)
|
||||
res = MPEG_PAUSED;
|
||||
else if (g_system->getMixer()->isSoundHandleActive(_soundHandle))
|
||||
res = MPEG_PLAYING;
|
||||
else
|
||||
res = MPEG_STOPPED;
|
||||
|
||||
debugC(7, kDebugSound, "mpegPlayer::status(%s), status: %d", _file.toString().c_str(), res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void mpegPlayer::set_volume(uint32 vol) {
|
||||
debugC(1, kDebugSound, "mpegPlayer::set_volume(%s), vol: %d", _file.toString().c_str(), vol);
|
||||
|
||||
_volume = vol;
|
||||
|
||||
g_system->getMixer()->setChannelVolume(_soundHandle, _volume * _cur_track_volume / 256);
|
||||
}
|
||||
|
||||
bool mpegPlayer::init_library(void *dsound_device) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void mpegPlayer::deinit_library() {
|
||||
}
|
||||
|
||||
mpegPlayer *g_mpegPlayer = nullptr;
|
||||
|
||||
mpegPlayer &mpegPlayer::instance() {
|
||||
if (!g_mpegPlayer)
|
||||
g_mpegPlayer = new mpegPlayer;
|
||||
|
||||
return *g_mpegPlayer;
|
||||
}
|
||||
|
||||
void mpegPlayer::syncMusicSettings() {
|
||||
set_volume(ConfMan.getInt("music_volume"));
|
||||
|
||||
if (ConfMan.getBool("enable_music"))
|
||||
enable();
|
||||
else
|
||||
disable();
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
102
engines/qdengine/qdcore/util/plaympp_api.h
Normal file
102
engines/qdengine/qdcore/util/plaympp_api.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/* 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 QDENGINE_QDCORE_UTIL_PLAYMPP_API_H
|
||||
#define QDENGINE_QDCORE_UTIL_PLAYMPP_API_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class MpegSound;
|
||||
|
||||
class mpegPlayer {
|
||||
public:
|
||||
//! Состояние.
|
||||
enum mpeg_status_t {
|
||||
MPEG_STOPPED,
|
||||
MPEG_PAUSED,
|
||||
MPEG_PLAYING
|
||||
};
|
||||
|
||||
~mpegPlayer();
|
||||
|
||||
bool play(const Common::Path &file, bool loop = false, int vol = 256);
|
||||
bool stop();
|
||||
bool pause();
|
||||
bool resume();
|
||||
|
||||
bool is_enabled() const {
|
||||
return _is_enabled;
|
||||
}
|
||||
//! Разрешает проигрывание музыки.
|
||||
void enable(bool need_resume = true) {
|
||||
_is_enabled = true;
|
||||
if (need_resume) resume();
|
||||
}
|
||||
//! Запрещает проигрывание музыки.
|
||||
void disable() {
|
||||
_is_enabled = false;
|
||||
pause();
|
||||
}
|
||||
|
||||
mpeg_status_t status() const;
|
||||
bool is_playing() const {
|
||||
return (status() == MPEG_PLAYING);
|
||||
}
|
||||
|
||||
uint32 volume() const {
|
||||
return _volume;
|
||||
}
|
||||
void set_volume(uint32 vol);
|
||||
|
||||
void syncMusicSettings();
|
||||
|
||||
static bool init_library(void *dsound_device);
|
||||
static void deinit_library();
|
||||
|
||||
static mpegPlayer &instance();
|
||||
|
||||
private:
|
||||
|
||||
mpegPlayer();
|
||||
|
||||
//! Music is off when false
|
||||
bool _is_enabled;
|
||||
bool _paused;
|
||||
|
||||
//! Music volume, [0, 255].
|
||||
uint32 _volume;
|
||||
uint32 _cur_track_volume;
|
||||
|
||||
Audio::SoundHandle _soundHandle;
|
||||
|
||||
Common::Path _file;
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_PLAYMPP_API_H
|
||||
110
engines/qdengine/qdcore/util/splash_screen.cpp
Normal file
110
engines/qdengine/qdcore/util/splash_screen.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/* 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/events.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/formats/winexe.h"
|
||||
#include "common/formats/winexe_pe.h"
|
||||
#include "common/system.h"
|
||||
|
||||
#include "graphics/paletteman.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "image/bmp.h"
|
||||
|
||||
#include "qdengine/qdcore/util/splash_screen.h"
|
||||
#include "qdengine/qdengine.h"
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
bool SplashScreen::create(int bitmapResID) {
|
||||
if (!create_window()) return false;
|
||||
|
||||
Common::ScopedPtr<Common::PEResources> r(new Common::PEResources());
|
||||
Common::WinResourceID resid(bitmapResID);
|
||||
Image::BitmapDecoder decoder;
|
||||
|
||||
if (r->loadFromEXE(g_engine->getExeName())) {
|
||||
Common::SeekableReadStream *stream = r->getResource(Common::kWinBitmap, resid);
|
||||
if (stream && decoder.loadStream(*stream)) {
|
||||
_splash = new Graphics::Surface();
|
||||
_splash->copyFrom(*decoder.getSurface());
|
||||
_paletteCount = decoder.getPalette().size();
|
||||
_palette = new byte[_paletteCount * 3];
|
||||
|
||||
memcpy(_palette, decoder.getPalette().data(), _paletteCount * 3);
|
||||
}
|
||||
} else {
|
||||
warning("SplashScreen::create(): Cannot load splash screen from file %s", g_engine->getExeName());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SplashScreen::create(const char *bitmap_file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SplashScreen::set_mask(int mask_resid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SplashScreen::set_mask(const char *mask_file) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SplashScreen::destroy() {
|
||||
delete _splash;
|
||||
_splash = nullptr;
|
||||
delete[] _palette;
|
||||
_palette = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SplashScreen::show() {
|
||||
g_system->fillScreen(0);
|
||||
g_system->getPaletteManager()->setPalette(_palette, 0, _paletteCount);
|
||||
|
||||
_start_time = g_system->getMillis();
|
||||
|
||||
if (!_splash)
|
||||
return;
|
||||
|
||||
int x = (640 - _splash->w) / 2;
|
||||
int y = (480 - _splash->h) / 2;
|
||||
g_system->copyRectToScreen(_splash->getPixels(), _splash->pitch, x, y, _splash->w, _splash->h);
|
||||
g_system->updateScreen();
|
||||
|
||||
}
|
||||
|
||||
void SplashScreen::wait(uint time) {
|
||||
if (g_system->getMillis() - _start_time < time)
|
||||
g_system->delayMillis(time - (g_system->getMillis() - _start_time));
|
||||
}
|
||||
|
||||
void SplashScreen::hide() {
|
||||
}
|
||||
|
||||
bool SplashScreen::create_window() {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace QDEngine
|
||||
64
engines/qdengine/qdcore/util/splash_screen.h
Normal file
64
engines/qdengine/qdcore/util/splash_screen.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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef QDENGINE_QDCORE_UTIL_SPLASH_SCREEN_H
|
||||
#define QDENGINE_QDCORE_UTIL_SPLASH_SCREEN_H
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace QDEngine {
|
||||
|
||||
class SplashScreen {
|
||||
public:
|
||||
SplashScreen() : _start_time(0) { }
|
||||
~SplashScreen() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
bool create(int bitmap_resid);
|
||||
bool create(const char *bitmap_file);
|
||||
|
||||
bool set_mask(int mask_resid);
|
||||
bool set_mask(const char *mask_file);
|
||||
|
||||
bool destroy();
|
||||
|
||||
void show();
|
||||
void hide();
|
||||
|
||||
void wait(uint time);
|
||||
|
||||
private:
|
||||
|
||||
uint _start_time = 0;
|
||||
|
||||
Graphics::Surface *_splash = nullptr;
|
||||
byte *_palette = nullptr;
|
||||
int _paletteCount = 0;
|
||||
|
||||
bool create_window();
|
||||
};
|
||||
|
||||
} // namespace QDEngine
|
||||
|
||||
#endif // QDENGINE_QDCORE_UTIL_SPLASH_SCREEN_H
|
||||
Reference in New Issue
Block a user