mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
252 lines
8.2 KiB
C++
252 lines
8.2 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "common/math.h"
|
|
#include "math/ray.h"
|
|
|
|
#include "tetraedge/tetraedge.h"
|
|
#include "tetraedge/te/te_camera.h"
|
|
#include "tetraedge/te/te_matrix4x4.h"
|
|
#include "tetraedge/te/te_renderer.h"
|
|
|
|
namespace Tetraedge {
|
|
|
|
TeCamera::TeCamera() : _projectionMatrixType(0), _orthogonalParamL(0.0f),
|
|
_orthogonalParamR(1.0f), _orthogonalParamT(1.0f), _orthogonalParamB(0.0f),
|
|
_orthNearVal(10.0f), _orthFarVal(4000.0f), _transformA(0), /*_transformB(0),*/
|
|
_fov(40.0f), _somePerspectiveVal(1.0f)
|
|
{
|
|
}
|
|
|
|
void TeCamera::apply() {
|
|
//debug("TeCamera::apply %13s mtype %d fov %.2f persp %.2f orth(%.2f %.2f) pos %s scale %s rot %s", name().c_str(),
|
|
// _projectionMatrixType, _fov, _somePerspectiveVal, _orthNearVal, _orthFarVal,
|
|
// position().dump().c_str(), scale().dump().c_str(), rotation().dump().c_str());
|
|
applyProjection();
|
|
applyTransformations();
|
|
}
|
|
|
|
void TeCamera::applyProjection() {
|
|
TeRenderer *renderer = g_engine->getRenderer();
|
|
renderer->setCurrentCamera(this);
|
|
renderer->setViewport(_viewportX, _viewportY,
|
|
(uint)(_viewportW * _scale.x()), (uint)(_viewportH * _scale.y()));
|
|
renderer->setMatrixMode(TeRenderer::MatrixMode::MM_GL_PROJECTION);
|
|
updateProjectionMatrix();
|
|
renderer->setMatrixMode(TeRenderer::MatrixMode::MM_GL_PROJECTION);
|
|
renderer->loadCurrentMatrixToGL();
|
|
renderer->setMatrixMode(TeRenderer::MatrixMode::MM_GL_MODELVIEW);
|
|
}
|
|
|
|
void TeCamera::applyTransformations() {
|
|
TeRenderer *renderer = g_engine->getRenderer();
|
|
renderer->setMatrixMode(TeRenderer::MatrixMode::MM_GL_MODELVIEW);
|
|
TeMatrix4x4 matrix = worldTransformationMatrix();
|
|
matrix.inverse();
|
|
renderer->loadMatrix(matrix);
|
|
renderer->loadCurrentMatrixToGL();
|
|
}
|
|
|
|
void TeCamera::buildOrthoMatrix() {
|
|
float widthNorm = FLT_MAX;
|
|
if ((_orthogonalParamR - _orthogonalParamL) != 0.0) {
|
|
widthNorm = 1.0 / (_orthogonalParamR - _orthogonalParamL);
|
|
}
|
|
float heightNorm = FLT_MAX;
|
|
if (_orthogonalParamB - _orthogonalParamT != 0.0) {
|
|
heightNorm = 1.0 / (_orthogonalParamB - _orthogonalParamT);
|
|
}
|
|
float depthNorm = FLT_MAX;
|
|
if ((_orthFarVal - _orthNearVal) != 0.0) {
|
|
depthNorm = 1.0 / (_orthFarVal - _orthNearVal);
|
|
}
|
|
|
|
_projectionMatrix.setValue(0, 0, widthNorm * 2.0f);
|
|
_projectionMatrix.setValue(1, 0, 0.0);
|
|
_projectionMatrix.setValue(2, 0, 0.0);
|
|
_projectionMatrix.setValue(3, 0, 0.0);
|
|
|
|
_projectionMatrix.setValue(0, 1, 0.0);
|
|
_projectionMatrix.setValue(1, 1, heightNorm * 2.0f);
|
|
_projectionMatrix.setValue(2, 1, 0.0);
|
|
_projectionMatrix.setValue(3, 1, 0.0);
|
|
|
|
_projectionMatrix.setValue(0, 2, 0.0);
|
|
_projectionMatrix.setValue(1, 2, 0.0);
|
|
_projectionMatrix.setValue(2, 2, depthNorm * -2.0f);
|
|
_projectionMatrix.setValue(3, 2, 0.0);
|
|
|
|
_projectionMatrix.setValue(0, 3, -((_orthogonalParamR + _orthogonalParamL) * widthNorm));
|
|
_projectionMatrix.setValue(1, 3, -((_orthogonalParamB + _orthogonalParamT) * heightNorm));
|
|
_projectionMatrix.setValue(2, 3, -((_orthFarVal + _orthNearVal) * depthNorm));
|
|
_projectionMatrix.setValue(3, 3, 1.0);
|
|
}
|
|
|
|
void TeCamera::buildPerspectiveMatrix() {
|
|
_projectionMatrix = TeMatrix4x4();
|
|
float f = tanf(_fov * 0.5);
|
|
_projectionMatrix.setValue(0, 0, (1.0 / f) / ((float)_viewportW / _viewportH));
|
|
_projectionMatrix.setValue(1, 1, 1.0 / f);
|
|
_projectionMatrix.setValue(2, 2, (_orthNearVal + _orthFarVal) / (_orthNearVal - _orthFarVal));
|
|
_projectionMatrix.setValue(3, 2, (_orthNearVal * _orthFarVal) / (_orthNearVal - _orthFarVal));
|
|
_projectionMatrix.setValue(2, 3, -1);
|
|
_projectionMatrix.setValue(3, 3, 0.0);
|
|
}
|
|
|
|
void TeCamera::buildPerspectiveMatrix2() {
|
|
_projectionMatrix = TeMatrix4x4();
|
|
float f = tanf(_fov * 0.5);
|
|
_projectionMatrix.setValue(0, 0, 1.0 / f);
|
|
_projectionMatrix.setValue(1, 1, _somePerspectiveVal / f);
|
|
_projectionMatrix.setValue(2, 2, -(_orthNearVal + _orthFarVal) / (_orthNearVal - _orthFarVal));
|
|
_projectionMatrix.setValue(3, 2, 1.0);
|
|
_projectionMatrix.setValue(2, 3, (_orthFarVal * 2) * _orthNearVal / (_orthNearVal - _orthFarVal));
|
|
_projectionMatrix.setValue(3, 3, 0.0);
|
|
}
|
|
|
|
void TeCamera::buildPerspectiveMatrix3() {
|
|
_projectionMatrix = TeMatrix4x4();
|
|
float f = tanf(_fov * 0.5);
|
|
_projectionMatrix.setValue(0, 0, (1.0 / f) / _somePerspectiveVal);
|
|
_projectionMatrix.setValue(1, 1, 1.0 / f);
|
|
_projectionMatrix.setValue(2, 2, -(_orthNearVal + _orthFarVal) / (_orthNearVal - _orthFarVal));
|
|
_projectionMatrix.setValue(3, 2, 1.0);
|
|
_projectionMatrix.setValue(2, 3, (_orthFarVal * 2) * _orthNearVal / (_orthNearVal - _orthFarVal));
|
|
_projectionMatrix.setValue(3, 3, 0.0);
|
|
}
|
|
|
|
void TeCamera::draw() {
|
|
error("TODO: Implement TeCamera::draw");
|
|
}
|
|
|
|
Math::Ray TeCamera::getRay(const TeVector2s32 &pxloc) {
|
|
const Math::Vector3d origin = position();
|
|
|
|
// point offset relative to viewport
|
|
const float xval = (pxloc._x - _viewportX) / fabs(_viewportW);
|
|
const float yval = (_viewportH - (pxloc._y - _viewportY)) / fabs(_viewportH);
|
|
|
|
// normalized to -1..1
|
|
const TeVector3f32 projectedPoint(xval * 2.0f - 1.0f, yval * 2.0f - 1.0f, 1.0f);
|
|
|
|
TeMatrix4x4 projInverse = _projectionMatrix;
|
|
bool inverted = projInverse.inverse();
|
|
if (!inverted)
|
|
error("failed to invert camera projection");
|
|
TeVector3f32 unprojectedPoint = projInverse * projectedPoint;
|
|
unprojectedPoint.normalize();
|
|
|
|
TeQuaternion rot = _rotation;
|
|
rot.normalize();
|
|
TeMatrix4x4 rotMatrix = rot.toTeMatrix();
|
|
TeVector3f32 rayDir = rotMatrix * unprojectedPoint;
|
|
Math::Ray ray(origin, rayDir);
|
|
return ray;
|
|
}
|
|
|
|
void TeCamera::loadBin(const Common::String &path) {
|
|
error("TODO: Implement TeCamera::loadBin");
|
|
}
|
|
|
|
void TeCamera::loadBin(const Common::ReadStream &stream) {
|
|
error("TODO: Implement TeCamera::loadBin");
|
|
}
|
|
|
|
void TeCamera::orthogonalParams(float left, float right, float top, float bottom) {
|
|
_orthogonalParamL = left;
|
|
_orthogonalParamR = right;
|
|
_orthogonalParamT = top;
|
|
_orthogonalParamB = bottom;
|
|
}
|
|
|
|
TeMatrix4x4 TeCamera::projectionMatrix() {
|
|
switch(_projectionMatrixType) {
|
|
case 1:
|
|
buildPerspectiveMatrix();
|
|
break;
|
|
case 2:
|
|
buildPerspectiveMatrix2();
|
|
break;
|
|
case 3:
|
|
buildPerspectiveMatrix3();
|
|
break;
|
|
case 4:
|
|
buildOrthoMatrix();
|
|
break;
|
|
}
|
|
return _projectionMatrix;
|
|
}
|
|
|
|
TeVector3f32 TeCamera::projectPoint(const TeVector3f32 &pt) {
|
|
error("TODO: Implement TeCamera::projectPoint");
|
|
}
|
|
|
|
TeVector3f32 TeCamera::projectPoint3f32(const TeVector3f32 &pt) {
|
|
error("TODO: Implement TeCamera::projectPoint3f32");
|
|
}
|
|
|
|
void TeCamera::restore() {
|
|
TeRenderer *renderer = g_engine->getRenderer();
|
|
renderer->setCurrentColor(TeColor(255, 255, 255, 255));
|
|
renderer->setCurrentCamera(nullptr);
|
|
}
|
|
|
|
TeMatrix4x4 TeCamera::transformationMatrix() {
|
|
if (!_transformA)
|
|
return Te3DObject2::transformationMatrix();
|
|
|
|
TeMatrix4x4 retval;
|
|
warning("TODO: Implement TeCamera::transformationMatrix");
|
|
|
|
retval.setToIdentity();
|
|
return retval;
|
|
}
|
|
|
|
TeVector3f32 TeCamera::transformCoord(const TeVector3f32 &pt) {
|
|
warning("TODO: Implement TeCamera::transformCoord");
|
|
return pt;
|
|
}
|
|
|
|
TeVector3f32 TeCamera::transformPoint2Dto3D(const TeVector3f32 &pt) {
|
|
TeVector3f32 retval;
|
|
TeVector3f32 vp_br(_viewportX + _viewportW, _viewportY + _viewportH, 0.0f);
|
|
float x = (pt.x() - _viewportX) / (vp_br.x() - _viewportX);
|
|
float y = (pt.y() - _viewportY) / (vp_br.y() - _viewportY);
|
|
return TeVector3f32(x * 2 - 1.0f, -(y * 2 - 1.0f), 0.0);
|
|
}
|
|
|
|
void TeCamera::updateProjectionMatrix() {
|
|
TeRenderer *renderer = g_engine->getRenderer();
|
|
renderer->setMatrixMode(TeRenderer::MatrixMode::MM_GL_PROJECTION);
|
|
renderer->loadProjectionMatrix(projectionMatrix());
|
|
}
|
|
|
|
void TeCamera::viewport(int x, int y, uint w, uint h) {
|
|
_viewportX = x;
|
|
_viewportY = y;
|
|
_viewportW = w;
|
|
_viewportH = h;
|
|
_onViewportChangedSignal.call();
|
|
}
|
|
|
|
|
|
} // end namespace Tetraedge
|