/* 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 .
*
*/
#include "common/debug.h"
#include "common/file.h"
#include "qdengine/qd_fwd.h"
#include "qdengine/parser/qdscr_parser.h"
#include "qdengine/parser/xml_tag_buffer.h"
#include "qdengine/system/graphics/gr_dispatcher.h"
#include "qdengine/qdcore/qd_setup.h"
#include "qdengine/qdcore/qd_camera.h"
#include "qdengine/qdcore/qd_game_object_animated.h"
#include "qdengine/qdcore/qd_game_dispatcher.h"
namespace QDEngine {
struct sPlane4f {
float A, B, C, D;
sPlane4f() { A = B = C = D = 0.0; }
sPlane4f(float a, float b, float c, float d) {
A = a, B = b, C = c, D = d;
}
sPlane4f(const Vect3f &a, const Vect3f &b, const Vect3f &c) {
// инициализация плоскости по трем точкам
A = (b.y - a.y) * (c.z - a.z) - (c.y - a.y) * (b.z - a.z);
B = (b.z - a.z) * (c.x - a.x) - (c.z - a.z) * (b.x - a.x);
C = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
GetNormal().normalize();
D = -A * a.x - B * a.y - C * a.z;
}
inline void Set(const Vect3f &a, const Vect3f &b, const Vect3f &c) {
// инициализация плоскости по трем точкам
A = (b.y - a.y) * (c.z - a.z) - (c.y - a.y) * (b.z - a.z);
B = (b.z - a.z) * (c.x - a.x) - (c.z - a.z) * (b.x - a.x);
C = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
GetNormal().normalize();
D = -A * a.x - B * a.y - C * a.z;
}
inline float GetDistance(const Vect3f &a) {
// расстояние от точки до плоскости
float t = A * a.x + B * a.y + C * a.z + D;
return t;
}
inline float GetCross(const Vect3f &a, const Vect3f &b) {
// поиск пересечения данной плоскости с прямой заданной двумя точками a и b
Vect3f v = a - b;
float t = A * v.x + B * v.y + C * v.z;
if (t == 0) return 0; // прямая и плоскость параллельны
t = (A * a.x + B * a.y + C * a.z + D) / t;
return t;
}
inline Vect3f &GetNormal() {
return *(Vect3f *)&A;
}
inline void GetReflectionVector(const Vect3f &in, Vect3f &out) {
// out - поиск отражение вектора от плоскости
out = in - 2 * dot(GetNormal(), in) * GetNormal();
}
};
const int32 IMPASSIBLE_CELL_CLR = 0x00FF0000;
const int32 SELECTED_CELL_CLR = 0x000000FF;
const int32 NORMAL_CELL_CLR = 0x00FFFFFF;
const int DASH_LEN = 2;
qdCamera *qdCamera::_current_camera = NULL;
#define CAMERA_WORLD_UP Vect3f(0, 1, 0)
#define CAMERA_AT_POINT Vect3f(0, 0, 0) // Point we're looking at
const float qdCamera::_NEAR_PLANE = 1;
const float qdCamera::_FAR_PLANE = 10000;
//qdCameraMode qdCamera::_default_mode;
qdCamera::qdCamera() : _m_fR(300.0f), _xAngle(45), _yAngle(0), _zAngle(0),
_GSX(0), _GSY(0), _grid(NULL),
_cellSX(32), _cellSY(32), _focus(1000.0f),
_gridCenter(0, 0, 0),
_redraw_mode(QDCAM_GRID_ZBUFFER),
_scrOffset(0, 0),
_current_mode_work_time(0.0f),
_current_mode_switch(false),
_current_object(NULL),
_default_object(NULL),
_scale_pow(1.0f),
_scale_z_offset(0.0f) {
set_grid_size(50, 50);
set_scr_size(640, 480);
set_scr_center(320, 240);
set_scr_center_initial(Vect2i(320, 240));
rotate_and_scale(_xAngle, _yAngle, _zAngle, 1, 1, 1);
_cycle_x = _cycle_y = false;
}
qdCamera::~qdCamera() {
if (_GSX) {
delete [] _grid;
}
}
void qdCamera::set_grid_size(int xs, int ys) {
if (_GSX == xs && _GSY == ys) return;
if (_GSX)
delete [] _grid;
_grid = new sGridCell[xs * ys];
_GSX = xs;
_GSY = ys;
}
void qdCamera::clear_grid() {
debugC(3, kDebugMovement, "qdCamera::clear_grid()");
int cnt = 0;
for (int i = 0; i < _GSY; i++) {
for (int j = 0; j < _GSX; j++) {
_grid[cnt++].clear();
}
}
}
float qdCamera::get_scale(const Vect3f &glCoord) const {
if ((_focus < 5000.0f) || (fabs(_scale_pow - 1) > 0.001)) {
Vect3f cameraCoord = global2camera_coord(glCoord);
float buf = cameraCoord.z + _scale_z_offset;
// Если координата отрицательна, то масштабирование происходит по линейному
// закону. Иначе по общему (степенному) закону.
if (buf > 0)
buf = exp(_scale_pow * log(buf));
float scale = (_focus / (buf + _focus));
if (scale < 0)
return 0;
return scale;
} else
return 1.0f;
}
const Vect2s qdCamera::scr2rscr(const Vect2s &v) const {
Vect2s res;
res.x = v.x - (_scrCenter.x - _scrOffset.x);
res.y = (_scrCenter.y - _scrOffset.y) - v.y;
return res;
}
const Vect2s qdCamera::rscr2scr(const Vect2s &v) const {
Vect2s res;
res.x = _scrCenter.x + v.x - _scrOffset.x;
res.y = _scrCenter.y - v.y - _scrOffset.y;
return res;
}
const Vect3f qdCamera::camera_coord2global(const Vect3f &v) const {
return TransformVector(v, MatrixInverse(_m_cam));
}
const Vect3f qdCamera::scr2global(const Vect2s &vScrPoint, float zInCameraCoord) const {
return rscr2global(scr2rscr(vScrPoint), zInCameraCoord);
}
const Vect3f qdCamera::rscr2global(const Vect2s rScrPoint, const float zInCameraCoord) const {
//Преобразование экран - координаты в системе камеры
Vect3f _t = rscr2camera_coord(rScrPoint, zInCameraCoord);
//Преобразование координаты в системе камеры - в координаты глобальные(в системе основной плоскости)
return camera_coord2global(_t);
}
const Vect3f qdCamera::global2camera_coord(const Vect3f &glCoord) const {
return TransformVector(glCoord, _m_cam);
}
const Vect3f qdCamera::rscr2camera_coord(const Vect2s &rScrPoint, float z) const {
float x = ((float)rScrPoint.x * (z + _focus)) / _focus;
float y = ((float)rScrPoint.y * (z + _focus)) / _focus;
return Vect3f(x, y, z);
}
const Vect2s qdCamera::camera_coord2rscr(const Vect3f &coord) const {
int16 sx = round(coord.x * _focus / (coord.z + _focus));
int16 sy = round(coord.y * _focus / (coord.z + _focus));
return Vect2s(sx, sy);
}
const Vect2s qdCamera::camera_coord2scr(const Vect3f &coord) const {
return rscr2scr(camera_coord2rscr(coord));
}
const Vect2s qdCamera::global2scr(const Vect3f &glCoord) const {
return camera_coord2scr(global2camera_coord(glCoord));
}
const Vect2s qdCamera::global2rscr(const Vect3f &glCoord) const {
return camera_coord2rscr(global2camera_coord(glCoord));
}
void qdCamera::set_R(const float r) {
_m_fR = r;
rotate_and_scale(_xAngle, _yAngle, _zAngle, 1, 1, 1);
}
bool qdCamera::line_cutting(Vect3f &b, Vect3f &e) const {
//положение по Z плоскости отсечения
const float D = -_focus * .9f;
if (b.z < D) { //первая лежит позади
if (e.z < D) //обе точки лежат позади
return false;
float k = (D - b.z) / (e.z - b.z);
b.z = D;
b.y = k * (e.y - b.y) + b.y;
b.x = k * (e.x - b.x) + b.x;
} else if (e.z < D) {
float k = (D - e.z) / (b.z - e.z);
e.z = D;
e.y = k * (b.y - e.y) + e.y;
e.x = k * (b.x - e.x) + e.x;
}
return true;
}
void qdCamera::rotate_and_scale(float XA, float YA, float ZA, float kX, float kY, float kZ) {
_xAngle = XA;
_yAngle = YA;
_zAngle = ZA;
MATRIX3D rot = RotateXMatrix(XA * (M_PI / 180.f));
rot = MatrixMult(RotateYMatrix(-YA * (M_PI / 180.f)), rot);
rot = MatrixMult(RotateZMatrix(-ZA * (M_PI / 180.f)), rot);
//точка, из которой мы сомотрим
const Vect3f camPos(0, 0, _m_fR);
//новая позиция камеры после поворота
Vect3f pos = TransformVector(camPos, rot);
//вычисляем, как измениться нормальный вектор камеры после поворота
Vect3f new_up = TransformVector(CAMERA_WORLD_UP, rot);
_m_cam = ViewMatrix(pos, CAMERA_AT_POINT, CAMERA_WORLD_UP, new_up);
}
const Vect3f qdCamera::rscr2plane_camera_coord(const Vect2s &scrPoint) const {
const int XSP = _cellSX * _GSX;
const int YSP = _cellSY * _GSY;
const float XSP05 = XSP * 0.5f;
const float YSP05 = YSP * 0.5f;
Vect3f p0 = global2camera_coord(Vect3f(-XSP05, -YSP05, 0) + _gridCenter);
Vect3f p1 = global2camera_coord(Vect3f(-XSP05, +YSP05, 0) + _gridCenter);
Vect3f p2 = global2camera_coord(Vect3f(+XSP05, +YSP05, 0) + _gridCenter);
sPlane4f plnT(p0, p1, p2);
Vect3f tlV((float)scrPoint.x, (float)scrPoint.y, _focus);
Vect3f tlP(0, 0, -_focus);
float t = -(plnT.A * tlP.x + plnT.B * tlP.y + plnT.C * tlP.z + plnT.D) /
(plnT.A * tlV.x + plnT.B * tlV.y + plnT.C * tlV.z);
float x = tlP.x + tlV.x * t;
float y = tlP.y + tlV.y * t;
float z = tlP.z + tlV.z * t;
return Vect3f(x, y, z);
}
const Vect3f qdCamera::scr2plane_camera_coord(const Vect2s &scrPoint) const {
return rscr2plane_camera_coord(scr2rscr(scrPoint));
}
const Vect3f qdCamera::scr2plane(const Vect2s &scrPoint) const {
return camera_coord2global(scr2plane_camera_coord(scrPoint));
}
const Vect3f qdCamera::rscr2plane(const Vect2s &rscrPoint) const {
return camera_coord2global(rscr2plane_camera_coord(rscrPoint));
}
const Vect2s qdCamera::plane2scr(const Vect3f &plnPoint) const {
return rscr2scr(plane2rscr(plnPoint));
}
const Vect2s qdCamera::plane2rscr(const Vect3f &plnPoint) const {
const float SMALL_VALUE = 0.0001f;
Vect3f res = global2camera_coord(plnPoint);
if (res.z < (SMALL_VALUE - _focus)) return Vect2s(0, 0);
int sx0 = round(res.x * _focus / (res.z + _focus));
int sy0 = round(res.y * _focus / (res.z + _focus));
return Vect2s(sx0, sy0);
}
const sGridCell *qdCamera::get_cell(float X, float Y) const {
int x = round(X - _gridCenter.x);
int y = round(Y - _gridCenter.y);
const int XSP = _cellSX * _GSX;
const int YSP = _cellSY * _GSY;
const int XSP05 = XSP / 2;
const int YSP05 = YSP / 2;
x += XSP05;
y += YSP05;
if (x < 0 || x >= XSP || y < 0 || y >= YSP) return 0;
x = x / _cellSX;
y = y / _cellSY;
return &_grid[y * _GSX + x];
}
const Vect2s qdCamera::get_cell_index(float X, float Y, bool grid_crop) const {
int x = round(X - _gridCenter.x);
int y = round(Y - _gridCenter.y);
const int XSP = _cellSX * _GSX;
const int YSP = _cellSY * _GSY;
const int XSP05 = XSP >> 1;
const int YSP05 = YSP >> 1;
x += XSP05;
y += YSP05;
if (grid_crop && (x < 0 || x >= XSP || y < 0 || y >= YSP))
return Vect2s(-1, -1);
return Vect2s(x / _cellSX, y / _cellSY);
}
const Vect2s qdCamera::get_cell_index(const Vect3f &v, bool grid_crop) const {
return get_cell_index(v.x, v.y, grid_crop);
}
const Vect3f qdCamera::get_cell_coords(int x_idx, int y_idx) const {
//float xx = (x_idx - (_GSX>>1)) * _cellSX + (_cellSX>>1) + _gridCenter.x;
//float yy = (y_idx - (_GSY>>1)) * _cellSY + (_cellSY>>1) + _gridCenter.y;
float xx = (x_idx - static_cast(_GSX) / 2 + 0.5) * _cellSX + _gridCenter.x;
float yy = (y_idx - static_cast(_GSY) / 2 + 0.5) * _cellSY + _gridCenter.y;
return Vect3f(xx, yy, _gridCenter.z);
}
const Vect3f qdCamera::get_cell_coords(const Vect2s &idxs) const {
return get_cell_coords(idxs.x, idxs.y);
}
void qdCamera::reset_all_select() {
int cnt = 0;
for (int i = 0; i < _GSY; i++) {
for (int j = 0; j < _GSX; j++) {
_grid[cnt++].deselect();
}
}
}
bool qdCamera::select_cell(int x, int y) {
const int XSP = _cellSX * _GSX;
const int YSP = _cellSY * _GSY;
const int XSP05 = XSP >> 1;
const int YSP05 = YSP >> 1;
x += XSP05 - _gridCenter.x;
y += YSP05 - _gridCenter.y;
if (x < 0 || x >= XSP || y < 0 || y >= YSP) return false;
x = x / _cellSX;
y = y / _cellSY;
_grid[y * _GSX + x].select();
return true;
}
bool qdCamera::deselect_cell(int x, int y) {
const int XSP = _cellSX * _GSX;
const int YSP = _cellSY * _GSY;
const int XSP05 = XSP >> 1;
const int YSP05 = YSP >> 1;
x += XSP05 - _gridCenter.x;
y += YSP05 - _gridCenter.y;
if (x < 0 || x >= XSP || y < 0 || y >= YSP) return false;
x = x / _cellSX;
y = y / _cellSY;
_grid[y * _GSX + x].deselect();
return true;
}
void qdCamera::load_script(const xml::tag *p) {
int x, y;
for (xml::tag::subtag_iterator it = p->subtags_begin(); it != p->subtags_end(); ++it) {
xml::tag_buffer buf(*it);
switch (it->ID()) {
case QDSCR_CAMERA_GRID_SIZE:
buf > x > y;
set_grid_size(x, y);
break;
case QDSCR_CAMERA_CELL_SIZE:
buf > _cellSX > _cellSY;
break;
case QDSCR_CAMERA_SCREEN_SIZE:
buf > x > y;
set_scr_size(x, y);
set_scr_center(x / 2, y / 2);
set_scr_center_initial(Vect2i(x / 2, y / 2));
break;
case QDSCR_CAMERA_SCREEN_OFFSET:
buf > x > y;
set_scr_offset(Vect2i(x, y));
break;
case QDSCR_CAMERA_SCREEN_CENTER:
buf > x > y;
set_scr_center_initial(Vect2i(x, y));
set_scr_center(x, y);
break;
case QDSCR_CAMERA_FOCUS:
buf > _focus;
break;
case QDSCR_CAMERA_ANGLES:
buf > _xAngle > _yAngle > _zAngle;
rotate_and_scale(_xAngle, _yAngle, _zAngle, 1, 1, 1);
break;
case QDSCR_CAMERA_GRID_CENTER: {
Vect3f v;
buf > v.x > v.y > v.z;
set_grid_center(v);
}
break;
case QDSCR_POS3D:
buf.get_float();
buf.get_float();
set_R(buf.get_float());
break;
case QDSCR_CAMERA_SCALE_POW:
buf > _scale_pow;
break;
case QDSCR_CAMERA_SCALE_Z_OFFSET:
buf > _scale_z_offset;
break;
}
}
rotate_and_scale(_xAngle, _yAngle, _zAngle, 1, 1, 1);
}
bool qdCamera::save_script(Common::WriteStream &fh, int indent) const {
for (int i = 0; i < indent; i++) {
fh.writeString("\t");
}
fh.writeString("\r\n");
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%d %d\r\n", _cellSX, _cellSY));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%ld %ld %f\r\n", 0L, 0L, get_R()));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%f\r\n", _focus));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%f %f %f\r\n", _xAngle, _yAngle, _zAngle));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%d %d\r\n", _scrSize.x, _scrSize.y));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%d %d\r\n", _scrOffset.x, _scrOffset.y));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%d %d\r\n", _scrCenterInitial.x, _scrCenterInitial.y));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%f %f %f\r\n", _gridCenter.x, _gridCenter.y, _gridCenter.z));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%f\r\n", scale_pow()));
for (int i = 0; i <= indent; i++) {
fh.writeString("\t");
}
fh.writeString(Common::String::format("%f\r\n", scale_z_offset()));
for (int i = 0; i < indent; i++) {
fh.writeString("\t");
}
fh.writeString("\r\n");
return true;
}
const Vect2i qdCamera::screen_center_limit_x() const {
int x0, x1;
if (_scrSize.x < g_engine->_screenW) {
x0 = x1 = g_engine->_screenW / 2;
} else {
x0 = -_scrSize.x / 2 + g_engine->_screenW;
x1 = _scrSize.x / 2;
}
if (_cycle_x) {
x0 -= _scrSize.x;
x1 += _scrSize.x;
}
return Vect2i(x0, x1);
}
const Vect2i qdCamera::screen_center_limit_y() const {
int y0, y1;
if (_scrSize.y < g_engine->_screenH) {
y0 = y1 = g_engine->_screenH / 2;
} else {
y0 = -_scrSize.y / 2 + g_engine->_screenH;
y1 = _scrSize.y / 2;
}
if (_cycle_y) {
y0 -= _scrSize.y;
y1 += _scrSize.y;
}
return Vect2i(y0, y1);
}
void qdCamera::move_scr_center(int dxc, int dyc) {
_scrCenter.x += dxc;
_scrCenter.y += dyc;
clip_center_coords(_scrCenter.x, _scrCenter.y);
}
float qdCamera::scrolling_phase_x() const {
if (_scrSize.x <= g_engine->_screenW)
return 0.0f;
else
return float(_scrCenter.x * 2 + _scrSize.x - g_engine->_screenW * 2) / float(_scrSize.x - g_engine->_screenW) - 1.0f;
}
float qdCamera::scrolling_phase_y() const {
if (_scrSize.y <= g_engine->_screenH)
return 0.0f;
else
return float(_scrCenter.y * 2 + _scrSize.y - g_engine->_screenH * 2) / float(_scrSize.x - g_engine->_screenH) - 1.0f;
}
bool qdCamera::draw_grid() const {
if (_redraw_mode == QDCAM_GRID_NONE) return true;
int cnt = 0;
const int XSP = _cellSX * _GSX;
const int YSP = _cellSY * _GSY;
const float XSP05 = XSP / 2.f;
const float YSP05 = YSP / 2.f;
for (int i = 0; i < _GSY;++i) {
for (int j = 0; j < _GSX;++j) {
if (!_grid[cnt].is_walkable())
draw_cell(j, i, 0, 1, IMPASSIBLE_CELL_CLR);
if (_grid[cnt].is_selected() || _grid[cnt].check_attribute(sGridCell::CELL_OCCUPIED | sGridCell::CELL_PERSONAGE_OCCUPIED))
draw_cell(j, i, 0, 1, SELECTED_CELL_CLR);
++cnt;
}
}
if (_redraw_mode == QDCAM_GRID_ZBUFFER) {
for (int i = 0; i <= _GSX; i++) {
for (int j = 0; j < _GSY; j++) {
Vect3f begPoint(-XSP05 + i * _cellSX, -YSP05 + j * _cellSY, 0);
Vect3f endPoint(-XSP05 + i * _cellSX, -YSP05 + (j + 1) *_cellSY, 0);
begPoint = global2camera_coord(begPoint + _gridCenter);
endPoint = global2camera_coord(endPoint + _gridCenter);
if (line_cutting(begPoint, endPoint)) {
Vect2s b = camera_coord2scr(begPoint);
Vect2s e = camera_coord2scr(endPoint);
#ifdef _GR_ENABLE_ZBUFFER
grDispatcher::instance()->Line_z(b.x, b.y, begPoint.z, e.x, e.y, endPoint.z, NORMAL_CELL_CLR, DASH_LEN);
#else
grDispatcher::instance()->line(b.x, b.y, e.x, e.y, NORMAL_CELL_CLR, DASH_LEN);
#endif
}
}
}
for (int i = 0; i <= _GSY; i++) {
for (int j = 0; j < _GSX; j++) {
Vect3f begPoint(-XSP05 + j * _cellSX, -YSP05 + i * _cellSY, 0);
Vect3f endPoint(-XSP05 + (j + 1)*_cellSX, -YSP05 + i * _cellSY, 0);
begPoint = global2camera_coord(begPoint + _gridCenter);
endPoint = global2camera_coord(endPoint + _gridCenter);
if (line_cutting(begPoint, endPoint)) {
Vect2s b = camera_coord2scr(begPoint);
Vect2s e = camera_coord2scr(endPoint);
#ifdef _GR_ENABLE_ZBUFFER
grDispatcher::instance()->line_z(b.x, b.y, begPoint.z, e.x, e.y, endPoint.z, NORMAL_CELL_CLR, DASH_LEN);
#else
grDispatcher::instance()->line(b.x, b.y, e.x, e.y, NORMAL_CELL_CLR, DASH_LEN);
#endif
}
}
}
} else {
for (int i = 0; i <= _GSX; i++) {
Vect3f begPoint(-XSP05 + i * _cellSX, -YSP05, 0);
Vect3f endPoint(-XSP05 + i * _cellSX, +YSP05, 0);
begPoint = global2camera_coord(begPoint + _gridCenter);
endPoint = global2camera_coord(endPoint + _gridCenter);
if (line_cutting(begPoint, endPoint)) {
Vect2s b = camera_coord2scr(begPoint);
Vect2s e = camera_coord2scr(endPoint);
grDispatcher::instance()->line(b.x, b.y, e.x, e.y, NORMAL_CELL_CLR, DASH_LEN);
}
}
for (int i = 0; i <= _GSY; i++) {
Vect3f begPoint(-XSP05, -YSP05 + i * _cellSY, 0);
Vect3f endPoint(+XSP05, -YSP05 + i * _cellSY, 0);
begPoint = global2camera_coord(begPoint + _gridCenter);
endPoint = global2camera_coord(endPoint + _gridCenter);
if (line_cutting(begPoint, endPoint)) {
Vect2s b = camera_coord2scr(begPoint);
Vect2s e = camera_coord2scr(endPoint);
grDispatcher::instance()->line(b.x, b.y, e.x, e.y, NORMAL_CELL_CLR, DASH_LEN);
}
}
}
cnt = 0;
uint32 color;
for (int i = 0; i < _GSY; i++) {
for (int j = 0; j < _GSX; j++, cnt++) {
if (_grid[cnt].height() || _grid[cnt].attributes()) {
color = 0;
if (_grid[cnt].attributes() & sGridCell::CELL_IMPASSABLE)
color = grDispatcher::instance()->make_rgb(0xff, 0x00, 0x00);
else if (_grid[cnt].attributes() & sGridCell::CELL_PERSONAGE_OCCUPIED)
color = grDispatcher::instance()->make_rgb(0xff, 0xff, 0x00);
else if (_grid[cnt].height())
color = grDispatcher::instance()->make_rgb(0xff, 0xff, 0xff);
if (_grid[cnt].attributes() & sGridCell::CELL_OCCUPIED)
color = grDispatcher::instance()->make_rgb(0x00, 0x00, 0xff);
if (_grid[cnt].attributes() & sGridCell::CELL_PERSONAGE_PATH)
warning("path");
if (color)
draw_cell(j, i, _grid[cnt].height(), 1, color);
}
}
}
return true;
}
bool qdCamera::draw_cell(int x, int y, int z, int penWidth, uint32 color) const {
const int XSP = get_cell_sx() * get_grid_sx();
const int YSP = get_cell_sy() * get_grid_sy();
const float XSP05 = XSP * 0.5f;
const float YSP05 = YSP * 0.5f;
const int offset = 2;
Vect3f point0((float)(x * get_cell_sx() - XSP05 + offset), (float)(y * get_cell_sy() - YSP05 + offset), (float)z);
Vect3f point1((float)((x + 1)*get_cell_sx() - XSP05 - offset), (float)(y * get_cell_sy() - YSP05 + offset), (float)z);
Vect3f point2((float)((x + 1)*get_cell_sx() - XSP05 - offset), (float)((y + 1)*get_cell_sy() - YSP05 - offset), (float)z);
Vect3f point3((float)(x * get_cell_sx() - XSP05 + offset), (float)((y + 1)*get_cell_sy() - YSP05 - offset), (float)z);
point0 = global2camera_coord(point0 + _gridCenter);
point1 = global2camera_coord(point1 + _gridCenter);
point2 = global2camera_coord(point2 + _gridCenter);
point3 = global2camera_coord(point3 + _gridCenter);
if (_redraw_mode == QDCAM_GRID_ZBUFFER) {
if (line_cutting(point0, point1)) {
Vect2s p0 = camera_coord2scr(point0);
Vect2s p1 = camera_coord2scr(point1);
#ifdef _GR_ENABLE_ZBUFFER
grDispatcher::instance()->Line_z(p0.x, p0.y, point0.z, p1.x, p1.y, point1.z, color/*, DASH_LEN*/);
#else
grDispatcher::instance()->line(p0.x, p0.y, p1.x, p1.y, color/*, DASH_LEN*/);
#endif
}
if (line_cutting(point1, point2)) {
Vect2s p0 = camera_coord2scr(point1);
Vect2s p1 = camera_coord2scr(point2);
#ifdef _GR_ENABLE_ZBUFFER
grDispatcher::instance()->Line_z(p0.x, p0.y, point1.z, p1.x, p1.y, point2.z, color/*, DASH_LEN*/);
#else
grDispatcher::instance()->line(p0.x, p0.y, p1.x, p1.y, color/*, DASH_LEN*/);
#endif
}
if (line_cutting(point2, point3)) {
Vect2s p0 = camera_coord2scr(point2);
Vect2s p1 = camera_coord2scr(point3);
#ifdef _GR_ENABLE_ZBUFFER
grDispatcher::instance()->Line_z(p0.x, p0.y, point2.z, p1.x, p1.y, point3.z, color/*, DASH_LEN*/);
#else
grDispatcher::instance()->line(p0.x, p0.y, p1.x, p1.y, color/*, DASH_LEN*/);
#endif
}
if (line_cutting(point3, point0)) {
Vect2s p0 = camera_coord2scr(point3);
Vect2s p1 = camera_coord2scr(point0);
#ifdef _GR_ENABLE_ZBUFFER
grDispatcher::instance()->Line_z(p0.x, p0.y, point3.z, p1.x, p1.y, point0.z, color/*, DASH_LEN*/);
#else
grDispatcher::instance()->line(p0.x, p0.y, p1.x, p1.y, color/*, DASH_LEN*/);
#endif
}
} else {
if (line_cutting(point0, point1)) {
Vect2s p0 = camera_coord2scr(point0);
Vect2s p1 = camera_coord2scr(point1);
grDispatcher::instance()->line(p0.x, p0.y, p1.x, p1.y, color/*, DASH_LEN*/);
}
if (line_cutting(point1, point2)) {
Vect2s p0 = camera_coord2scr(point1);
Vect2s p1 = camera_coord2scr(point2);
grDispatcher::instance()->line(p0.x, p0.y, p1.x, p1.y, color/*, DASH_LEN*/);
}
if (line_cutting(point2, point3)) {
Vect2s p0 = camera_coord2scr(point2);
Vect2s p1 = camera_coord2scr(point3);
grDispatcher::instance()->line(p0.x, p0.y, p1.x, p1.y, color/*, DASH_LEN*/);
}
if (line_cutting(point3, point0)) {
Vect2s p0 = camera_coord2scr(point3);
Vect2s p1 = camera_coord2scr(point0);
grDispatcher::instance()->line(p0.x, p0.y, p1.x, p1.y, color/*, DASH_LEN*/);
}
}
return true;
}
void qdCamera::scale_grid(int sx, int sy, int csx, int csy) {
if (_GSX == sx && _GSY == sy) return;
sGridCell *new_grid = new sGridCell[sx * sy];
if (_GSX) {
if (_GSX >= sx && _GSY >= sy) {
int dx = _GSX / sx;
int dy = _GSY / sy;
sGridCell *new_p = new_grid;
sGridCell *old_p = _grid;
for (int i = 0; i < sy; i++) {
for (int j = 0; j < sx; j++) {
int attr_count = 0;
int height_sum = 0;
for (int y = 0; y < dy; y++) {
for (int x = 0; x < dx; x++) {
if (!old_p[j * dx + x + y * _GSX].is_walkable())
attr_count++;
height_sum += old_p[j * dx + x + y * _GSX].height();
}
}
if (attr_count >= dx * dy / 2)
new_p->make_impassable();
new_p->set_height(height_sum / (dx * dy));
new_p++;
}
old_p += _GSX * dy;
}
}
if (_GSX <= sx && _GSY <= sy) {
int dx = sx / _GSX;
int dy = sy / _GSY;
sGridCell *new_p = new_grid;
sGridCell *old_p = _grid;
for (int i = 0; i < _GSY; i++) {
for (int j = 0; j < _GSX; j++) {
for (int y = 0; y < dy; y++) {
for (int x = 0; x < dx; x++)
new_p[j * dx + x + y * sx] = *old_p;
}
old_p++;
}
new_p += sx * dy;
}
}
delete [] _grid;
}
_grid = new_grid;
_GSX = sx;
_GSY = sy;
_cellSX = csx;
_cellSY = csy;
}
void qdCamera::resize_grid(int sx, int sy) {
if (_GSX == sx && _GSY == sy) return;
sGridCell *new_grid = new sGridCell[sx * sy];
if (_GSX) {
int x0 = (sx - _GSX) / 2;
int y0 = (sy - _GSY) / 2;
for (int y = 0; y < _GSY; y++) {
for (int x = 0; x < _GSX; x++) {
if (x + x0 >= 0 && x + x0 < sx && y + y0 >= 0 && y + y0 < sy)
new_grid[x + x0 + (y + y0) * sx] = _grid[x + y * _GSX];
}
}
delete [] _grid;
}
_grid = new_grid;
_GSX = sx;
_GSY = sy;
}
bool qdCamera::set_grid_cell(const Vect2s &cell_pos, const sGridCell &cell) {
if (cell_pos.x >= 0 && cell_pos.x < _GSX && cell_pos.y >= 0 && cell_pos.y < _GSY) {
_grid[cell_pos.x + cell_pos.y * _GSX] = cell;
return true;
}
return false;
}
bool qdCamera::set_grid_cell_attributes(const Vect2s &cell_pos, int attr) {
if (cell_pos.x >= 0 && cell_pos.x < _GSX && cell_pos.y >= 0 && cell_pos.y < _GSY) {
_grid[cell_pos.x + cell_pos.y * _GSX].set_attributes(attr);
return true;
}
return false;
}
bool qdCamera::restore_grid_cell(const Vect2s cell_pos) {
if (cell_pos.x >= 0 && cell_pos.x < _GSX && cell_pos.y >= 0 && cell_pos.y < _GSY) {
sGridCell cl;
cl.make_impassable();
_grid[cell_pos.x + cell_pos.y * _GSX] = cl;
return true;
}
return false;
}
sGridCell *qdCamera::get_cell(const Vect2s &cell_pos) {
if (cell_pos.x >= 0 && cell_pos.x < _GSX && cell_pos.y >= 0 && cell_pos.y < _GSY) {
return &_grid[cell_pos.x + cell_pos.y * _GSX];
}
return NULL;
}
const sGridCell *qdCamera::get_cell(const Vect2s &cell_pos) const {
if (cell_pos.x >= 0 && cell_pos.x < _GSX && cell_pos.y >= 0 && cell_pos.y < _GSY) {
return &_grid[cell_pos.x + cell_pos.y * _GSX];
}
return NULL;
}
bool qdCamera::load_data(Common::SeekableReadStream &fh, int save_version) {
debugC(3, kDebugSave, " qdCamera::load_data(): before: %d", (int)fh.pos());
int x, y;
char flag;
_scrCenter.x = fh.readSint32LE();
_scrCenter.y = fh.readSint32LE();
x = fh.readSint32LE();
y = fh.readSint32LE();
_current_mode_work_time = fh.readFloatLE();
flag = fh.readByte();
_current_mode_switch = bool(flag);
if (x != _GSX || y != _GSY) return false;
if (!_current_mode.load_data(fh, save_version))
return false;
if (!_default_mode.load_data(fh, save_version))
return false;
flag = fh.readByte();
if (flag) {
qdNamedObjectReference ref;
if (!ref.load_data(fh, save_version))
return false;
_current_object = dynamic_cast(qdGameDispatcher::get_dispatcher()->get_named_object(&ref));
}
flag = fh.readByte();
if (flag) {
qdNamedObjectReference ref;
if (!ref.load_data(fh, save_version))
return false;
_default_object = dynamic_cast(qdGameDispatcher::get_dispatcher()->get_named_object(&ref));
}
debugC(3, kDebugSave, " qdCamera::load_data(): after: %d", (int)fh.pos());
return true;
}
bool qdCamera::save_data(Common::WriteStream &fh) const {
debugC(3, kDebugSave, " qdCamera::save_data(): before: %d", (int)fh.pos());
fh.writeSint32LE(_scrCenter.x);
fh.writeSint32LE(_scrCenter.y);
fh.writeSint32LE(_GSX);
fh.writeSint32LE(_GSY);
fh.writeFloatLE(_current_mode_work_time);
fh.writeByte(char(_current_mode_switch));
_current_mode.save_data(fh);
_default_mode.save_data(fh);
if (_current_object) {
fh.writeByte(char(1));
qdNamedObjectReference ref(_current_object);
ref.save_data(fh);
} else {
fh.writeByte(char(0));
}
if (_default_object) {
fh.writeByte(char(1));
qdNamedObjectReference ref(_default_object);
ref.save_data(fh);
} else {
fh.writeByte(char(0));
}
debugC(3, kDebugSave, " qdCamera::save_data(): after: %d", (int)fh.pos());
return true;
}
bool qdCamera::set_mode(const qdCameraMode &mode, qdGameObjectAnimated *object) {
_current_mode = mode;
_current_object = object;
_current_mode_work_time = 0.0f;
_current_mode_switch = _current_mode.smooth_switch();
return true;
}
bool qdCamera::quant(float dt) {
Vect2i last_pos = _scrCenter;
qdGameObjectAnimated *p = _current_object;
if (!p) p = _default_object;
if (p)
p->qdGameObject::update_screen_pos();
switch (_current_mode.camera_mode()) {
case qdCameraMode::MODE_CENTER_OBJECT:
if (p) {
Vect2i r = p->screen_pos() + _current_mode.center_offset();
int cx = _scrCenter.x + g_engine->_screenW / 2 - r.x;
int cy = _scrCenter.y + g_engine->_screenH / 2 - r.y;
clip_center_coords(cx, cy);
int dx = cx - _scrCenter.x;
int dy = cy - _scrCenter.y;
if (_current_mode_switch) {
Vect2f dr(dx, dy);
float dr0 = _current_mode.scrolling_speed() * dt;
if (dr.norm2() > dr0 * dr0)
dr.normalize(dr0);
else
_current_mode_switch = false;
move_scr_center(dr.xi(), dr.yi());
} else
move_scr_center(dx, dy);
}
break;
case qdCameraMode::MODE_OBJECT_ON_SCREEN:
if (p) {
Vect2s r = p->screen_pos();
float sz = p->radius();
int dx = 0;
int dy = 0;
if (r.x + sz + _current_mode.scrolling_distance() >= g_engine->_screenW) {
dx = g_engine->_screenW - (r.x + sz + _current_mode.scrolling_distance());
} else {
if (r.x - sz - _current_mode.scrolling_distance() < 0)
dx = -r.x + sz + _current_mode.scrolling_distance();
}
if (r.y + sz + _current_mode.scrolling_distance() >= g_engine->_screenH) {
dy = g_engine->_screenH - (r.y + sz + _current_mode.scrolling_distance());
} else {
if (r.y - sz - _current_mode.scrolling_distance() < 0)
dy = -r.y + sz + _current_mode.scrolling_distance();
}
if (_current_mode_switch) {
int cx = _scrCenter.x + dx;
int cy = _scrCenter.y + dy;
clip_center_coords(cx, cy);
dx = cx - _scrCenter.x;
dy = cy - _scrCenter.y;
Vect2f dr(dx, dy);
float dr0 = _current_mode.scrolling_speed() * dt;
if (dr.norm2() > dr0 * dr0)
dr.normalize(dr0);
else
_current_mode_switch = false;
move_scr_center(dr.xi(), dr.yi());
} else
move_scr_center(dx, dy);
}
break;
case qdCameraMode::MODE_FOLLOW_OBJECT:
if (p) {
Vect2s r = p->screen_pos() + _current_mode.center_offset();
int dx = -r.x + g_engine->_screenW / 2;
int dy = -r.y + g_engine->_screenH / 2;
if (dx || dy) {
Vect2f dr(dx, dy);
float dr0 = _current_mode.scrolling_speed() * dt;
if (dr.norm2() > dr0 * dr0)
dr.normalize(dr0);
move_scr_center(dr.xi(), dr.yi());
}
_current_mode_switch = false;
}
break;
case qdCameraMode::MODE_CENTER_OBJECT_WHEN_LEAVING:
if (p) {
Vect2s r = p->screen_pos() + _current_mode.center_offset();
float sz = p->radius();
int dx = 0;
int dy = 0;
if (r.x + sz + _current_mode.scrolling_distance() >= g_engine->_screenW) {
dx = g_engine->_screenW - (r.x + sz + _current_mode.scrolling_distance());
} else {
if (r.x - sz - _current_mode.scrolling_distance() < 0)
dx = -r.x + sz + _current_mode.scrolling_distance();
}
if (r.y + sz + _current_mode.scrolling_distance() >= g_engine->_screenH) {
dy = g_engine->_screenH - (r.y + sz + _current_mode.scrolling_distance());
} else {
if (r.y - sz - _current_mode.scrolling_distance() < 0)
dy = -r.y + sz + _current_mode.scrolling_distance();
}
if (dx || dy) {
int dx1 = -r.x + g_engine->_screenW / 2;
int dy1 = -r.y + g_engine->_screenH / 2;
Vect2f dr(dx1, dy1);
float dr0 = _current_mode.scrolling_speed() * dt;
if (dr.norm2() > dr0 * dr0)
dr.normalize(dr0);
move_scr_center(dr.xi(), dr.yi());
}
_current_mode_switch = false;
}
break;
default:
break;
}
if (p)
p->update_screen_pos();
clip_center_coords(_scrCenter.x, _scrCenter.y);
if (!_current_mode_switch)
_current_mode_work_time += dt;
if (_current_mode.has_work_time() && _current_mode_work_time > _current_mode.work_time())
set_mode(_default_mode, _default_object);
if (last_pos.x != _scrCenter.x || last_pos.y != _scrCenter.y)
return true;
return false;
}
bool qdCamera::set_grid_attributes(const Vect2s ¢er_pos, const Vect2s &size, int attr) {
int x0 = center_pos.x - size.x / 2;
int y0 = center_pos.y - size.y / 2;
int x1 = x0 + size.x;
int y1 = y0 + size.y;
if (x0 < 0) x0 = 0;
if (x1 > _GSX - 1) x1 = _GSX - 1;
if (y0 < 0) y0 = 0;
if (y1 > _GSY - 1) y1 = _GSY - 1;
sGridCell *cells = _grid + x0 + y0 * _GSX;
debugC(4, kDebugMovement, "qdCamera::set_grid_attributes() attr: %d at [%d, %d]", attr, x0, y0);
for (int y = y0; y < y1; y++) {
sGridCell *p = cells;
for (int x = x0; x < x1; x++, p++)
p->set_attribute(attr);
cells += _GSX;
}
return true;
}
bool qdCamera::drop_grid_attributes(const Vect2s ¢er_pos, const Vect2s &size, int attr) {
int x0 = center_pos.x - size.x / 2;
int y0 = center_pos.y - size.y / 2;
int x1 = x0 + size.x;
int y1 = y0 + size.y;
if (x0 < 0) x0 = 0;
if (x1 > _GSX - 1) x1 = _GSX - 1;
if (y0 < 0) y0 = 0;
if (y1 > _GSY - 1) y1 = _GSY - 1;
sGridCell *cells = _grid + x0 + y0 * _GSX;
for (int y = y0; y < y1; y++) {
sGridCell *p = cells;
for (int x = x0; x < x1; x++, p++)
p->drop_attribute(attr);
cells += _GSX;
}
return true;
}
bool qdCamera::set_grid_attributes(int attr) {
sGridCell *p = _grid;
for (int i = 0; i < _GSX * _GSY; i++, p++)
p->set_attribute(attr);
return true;
}
bool qdCamera::drop_grid_attributes(int attr) {
sGridCell *p = _grid;
for (int i = 0; i < _GSX * _GSY; i++, p++)
p->drop_attribute(attr);
return true;
}
bool qdCamera::check_grid_attributes(const Vect2s ¢er_pos, const Vect2s &size, int attr) const {
int x0 = center_pos.x - size.x / 2;
int y0 = center_pos.y - size.y / 2;
int x1 = x0 + size.x;
int y1 = y0 + size.y;
if (x0 < 0) x0 = 0;
if (x1 > _GSX - 1) x1 = _GSX - 1;
if (y0 < 0) y0 = 0;
if (y1 > _GSY - 1) y1 = _GSY - 1;
const sGridCell *cells = _grid + x0 + y0 * _GSX;
for (int y = y0; y < y1; y++) {
const sGridCell *p = cells;
for (int x = x0; x < x1; x++, p++) {
if (p->check_attribute(attr))
return true;
}
cells += _GSX;
}
return false;
}
int qdCamera::cells_num_with_exact_attributes(const Vect2s ¢er_pos, const Vect2s &size, int attr) const {
int x0 = center_pos.x - size.x / 2;
int y0 = center_pos.y - size.y / 2;
int x1 = x0 + size.x;
int y1 = y0 + size.y;
if (x0 < 0) x0 = 0;
if (x1 > _GSX - 1) x1 = _GSX - 1;
if (y0 < 0) y0 = 0;
if (y1 > _GSY - 1) y1 = _GSY - 1;
const sGridCell *cells = _grid + x0 + y0 * _GSX;
int ret = 0;
for (int y = y0; y < y1; y++) {
const sGridCell *p = cells;
for (int x = x0; x < x1; x++, p++) {
if (p->attributes() == (uint)attr)
ret++;
}
cells += _GSX;
}
return ret;
}
bool qdCamera::is_walkable(const Vect2s ¢er_pos, const Vect2s &size, bool ignore_personages) const {
int x0 = center_pos.x - size.x / 2;
int y0 = center_pos.y - size.y / 2;
int x1 = x0 + size.x;
int y1 = y0 + size.y;
if (x0 < 0) x0 = 0;
if (x1 > _GSX - 1) x1 = _GSX - 1;
if (y0 < 0) y0 = 0;
if (y1 > _GSY - 1) y1 = _GSY - 1;
const sGridCell *cells = _grid + x0 + y0 * _GSX;
debugC(3, kDebugMovement, "qdCamera::is_walkable(): attr: %d [%d, %d] size: [%d, %d], ignore_personages: %d", cells->attributes(), x0, y0, size.x, size.y, ignore_personages);
int attr = sGridCell::CELL_IMPASSABLE | sGridCell::CELL_OCCUPIED;
if (g_engine->_gameVersion > 20031206 && !ignore_personages) {
attr |= sGridCell::CELL_PERSONAGE_OCCUPIED;
}
for (int y = y0; y < y1; y++) {
const sGridCell *p = cells;
for (int x = x0; x < x1; x++, p++) {
debugC(3, kDebugMovement, "qdCamera::is_walkable(): attr %d at [%d, %d]", p->attributes(), x, y);
if (p->check_attribute(attr) && !p->check_attribute(sGridCell::CELL_SELECTED)) {
return false;
}
}
cells += _GSX;
}
return true;
}
bool qdCamera::clip_grid_line(Vect2s &v0, Vect2s &v1) const {
int x = 0, y = 0;
bool accept = false, done = false;
int outcodeOut;
int outcode0 = clip_out_code(v0);
int outcode1 = clip_out_code(v1);
do {
if (outcode0 == 0 && outcode1 == 0) {
accept = true;
done = true;
} else {
if ((outcode0 & outcode1) != 0)
done = true;
else {
if (outcode0)
outcodeOut = outcode0;
else
outcodeOut = outcode1;
if (clTOP & outcodeOut) {
x = v0.x + (v1.x - v0.x) * (_GSY - v0.y - 1) / (v1.y - v0.y);
y = _GSY - 1;
} else if (clBOTTOM & outcodeOut) {
x = v0.x + (v1.x - v0.x) * (-v0.y) / (v1.y - v0.y);
y = 0;
}
if (clRIGHT & outcodeOut) {
y = v0.y + (v1.y - v0.y) * (_GSX - v0.x - 1) / (v1.x - v0.x);
x = _GSX - 1;
} else if (clLEFT & outcodeOut) {
y = v0.y + (v1.y - v0.y) * (-v0.x) / (v1.x - v0.x);
x = 0;
}
if (outcodeOut == outcode0) {
v0.x = x;
v0.y = y;
outcode0 = clip_out_code(Vect2s(x, y));
} else {
v1.x = x;
v1.y = y;
outcode1 = clip_out_code(Vect2s(x, y));
}
}
}
} while (!done);
return accept;
}
bool qdCamera::init() {
_default_object = NULL;
_current_object = NULL;
_scrCenter = _scrCenterInitial;
set_mode(_default_mode);
return true;
}
void qdCamera::clip_center_coords(int &x, int &y) const {
Vect2i lim = screen_center_limit_x();
if (x < lim.x)
x = lim.x;
else if (x > lim.y)
x = lim.y;
lim = screen_center_limit_y();
if (y < lim.x)
y = lim.x;
else if (y > lim.y)
y = lim.y;
}
bool qdCamera::is_visible(const Vect2i ¢er_offs) const {
int sx = g_engine->_screenW / 2;
int sy = g_engine->_screenH / 2;
Vect2s pos = scr2rscr(Vect2s(sx, sy));
pos.x -= center_offs.x;
pos.y += center_offs.y;
if (pos.x < -_scrSize.x / 2 - sx || pos.x > _scrSize.x / 2 + sx || pos.y < -_scrSize.y / 2 - sy || pos.y > _scrSize.y / 2 + sy)
return false;
return true;
}
void qdCamera::cycle_coords(int &x, int &y) const {
Vect2s pos = scr2rscr(Vect2s(x, y));
if (_cycle_x) {
if (pos.x < -_scrSize.x / 2 + _scrOffset.x)
pos.x += _scrSize.x;
else if (pos.x > _scrSize.x / 2 + _scrOffset.x)
pos.x -= _scrSize.x;
}
if (_cycle_y) {
if (pos.y < -_scrSize.y / 2 + _scrOffset.y)
pos.y += _scrSize.y;
else if (pos.y > _scrSize.y / 2 + _scrOffset.y)
pos.y -= _scrSize.y;
}
pos = rscr2scr(pos);
x = pos.x;
y = pos.y;
}
bool qdCamera::set_grid_line_attributes(const Vect2s &start_pos, const Vect2s &end_pos, const Vect2s &size, int attr) {
if (start_pos.x == end_pos.x && start_pos.y == end_pos.y) {
set_grid_attributes(start_pos, size, attr);
return true;
}
Vect2f r(start_pos.x, start_pos.y);
int dx = end_pos.x - start_pos.x;
int dy = end_pos.y - start_pos.y;
Vect2f dr(dx, dy);
float d = (float)_cellSX / 3.0;
if (d < 0.5f) d = 0.5f;
dr.normalize(d);
if (abs(dx) > abs(dy)) {
int i = round(float(dx) / dr.x);
do {
set_grid_attributes(Vect2s(r.xi(), r.yi()), size, attr);
r += dr;
} while (--i >= 0);
} else {
int i = round(float(dy) / dr.y);
do {
set_grid_attributes(Vect2s(r.xi(), r.yi()), size, attr);
r += dr;
} while (--i >= 0);
}
return true;
}
bool qdCamera::drop_grid_line_attributes(const Vect2s &start_pos, const Vect2s &end_pos, const Vect2s &size, int attr) {
if (start_pos.x == end_pos.x && start_pos.y == end_pos.y) {
drop_grid_attributes(start_pos, size, attr);
return true;
}
Vect2f r(start_pos.x, start_pos.y);
int dx = end_pos.x - start_pos.x;
int dy = end_pos.y - start_pos.y;
Vect2f dr(dx, dy);
float d = (float)_cellSX / 3.0;
if (d < 0.5f) d = 0.5f;
dr.normalize(d);
if (abs(dx) > abs(dy)) {
int i = round(float(dx) / dr.x);
do {
drop_grid_attributes(Vect2s(r.xi(), r.yi()), size, attr);
r += dr;
} while (--i >= 0);
} else {
int i = round(float(dy) / dr.y);
do {
drop_grid_attributes(Vect2s(r.xi(), r.yi()), size, attr);
r += dr;
} while (--i >= 0);
}
return true;
}
bool qdCamera::check_grid_line_attributes(const Vect2s &start_pos, const Vect2s &end_pos, const Vect2s &size, int attr) const {
if (start_pos.x == end_pos.x && start_pos.y == end_pos.y)
return check_grid_attributes(start_pos, size, attr);
Vect2f r(start_pos.x, start_pos.y);
int dx = end_pos.x - start_pos.x;
int dy = end_pos.y - start_pos.y;
Vect2f dr(dx, dy);
float d = (float)_cellSX / 3.0;
if (d < 0.5f) d = 0.5f;
dr.normalize(d);
if (abs(dx) > abs(dy)) {
int i = round(float(dx) / dr.x);
do {
if (check_grid_attributes(Vect2s(r.xi(), r.yi()), size, attr))
return true;
r += dr;
} while (--i >= 0);
} else {
int i = round(float(dy) / dr.y);
do {
if (check_grid_attributes(Vect2s(r.xi(), r.yi()), size, attr))
return true;
r += dr;
} while (--i >= 0);
}
return false;
}
void qdCamera::dump_grid(const char *file_name) const {
Common::DumpFile fh;
fh.open(Common::Path(file_name));
fh.writeString(Common::String::format("%d x %d\n", _GSX, _GSY));
for (int i = 0; i < _GSY; i++) {
for (int j = 0; j < _GSX; j++) {
if (_grid[j + i * _GSX].attributes() < 10)
fh.writeString(" ");
fh.writeString(Common::String::format("%u ", _grid[j + i * _GSX].attributes()));
}
fh.writeString("\n");
}
fh.close();
}
bool qdCamera::can_change_mode() const {
if (_current_mode.has_work_time()) return false;
return true;
}
} // namespace QDEngine