ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

myst3/scene.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/math.h"
00024 #include "common/config-manager.h"
00025 
00026 #include "engines/myst3/scene.h"
00027 #include "engines/myst3/gfx.h"
00028 #include "engines/myst3/myst3.h"
00029 #include "engines/myst3/node.h"
00030 #include "engines/myst3/state.h"
00031 
00032 #include "graphics/colormasks.h"
00033 
00034 #include "math/vector2d.h"
00035 
00036 namespace Myst3 {
00037 
00038 Scene::Scene(Myst3Engine *vm) :
00039         Window(),
00040         _vm(vm),
00041         _mouseSpeed(50) {
00042     updateMouseSpeed();
00043 }
00044 
00045 void Scene::updateCamera(Common::Point &mouse) {
00046     float pitch = _vm->_state->getLookAtPitch();
00047     float heading = _vm->_state->getLookAtHeading();
00048 
00049     if (!_vm->_state->getCursorLocked()) {
00050         float speed = 25 / (float)(200 - _mouseSpeed);
00051 
00052         // Adjust the speed according to the resolution
00053         Common::Rect screen = _vm->_gfx->viewport();
00054         speed *= Renderer::kOriginalHeight / (float) screen.height();
00055 
00056         if (ConfMan.getBool("mouse_inverted")) {
00057             pitch += mouse.y * speed;
00058         } else {
00059             pitch -= mouse.y * speed;
00060         }
00061         heading += mouse.x * speed;
00062     }
00063 
00064     // Keep heading within allowed values
00065     if (_vm->_state->isCameraLimited()) {
00066         float minHeading = _vm->_state->getMinHeading();
00067         float maxHeading = _vm->_state->getMaxHeading();
00068 
00069         if (minHeading < maxHeading) {
00070             heading = CLIP(heading, minHeading, maxHeading);
00071         } else {
00072             if (heading < minHeading && heading > maxHeading) {
00073                 uint distToMin = (uint)ABS(heading - minHeading);
00074                 uint distToMax = (uint)ABS(heading - maxHeading);
00075                 if (distToMin > distToMax)
00076                     heading = maxHeading;
00077                 else
00078                     heading = minHeading;
00079             }
00080         }
00081     }
00082 
00083     // Keep heading in 0..360 range
00084     if (heading > 360.0f)
00085         heading -= 360.0f;
00086     else if (heading < 0.0f)
00087         heading += 360.0f;
00088 
00089     // Keep pitch within allowed values
00090     float minPitch = _vm->_state->getCameraMinPitch();
00091     float maxPitch = _vm->_state->getCameraMaxPitch();
00092 
00093     if (_vm->_state->isCameraLimited()) {
00094         minPitch = _vm->_state->getMinPitch();
00095         maxPitch = _vm->_state->getMaxPitch();
00096     }
00097 
00098     pitch = CLIP(pitch, minPitch, maxPitch);
00099 
00100     _vm->_state->lookAt(pitch, heading);
00101     _vm->_state->setCameraPitch((int32)pitch);
00102     _vm->_state->setCameraHeading((int32)heading);
00103 }
00104 
00105 void Scene::drawSunspotFlare(const SunSpot &s) {
00106     Common::Rect frame = Common::Rect(Renderer::kOriginalWidth, Renderer::kFrameHeight);
00107 
00108     uint8 a = (uint8)(s.intensity * s.radius);
00109     uint8 r, g, b;
00110     Graphics::colorToRGB< Graphics::ColorMasks<888> >(s.color, r, g, b);
00111     uint32 color = Graphics::ARGBToColor< Graphics::ColorMasks<8888> >(a, r, g, b);
00112 
00113     _vm->_gfx->selectTargetWindow(this, false, true);
00114     _vm->_gfx->drawRect2D(frame, color);
00115 }
00116 
00117 
00118 Math::Vector3d Scene::directionToVector(float pitch, float heading) {
00119     Math::Vector3d v;
00120 
00121     float radHeading = Common::deg2rad(heading);
00122     float radPitch = Common::deg2rad(pitch);
00123 
00124     v.setValue(0, cos(radPitch) * cos(radHeading));
00125     v.setValue(1, sin(radPitch));
00126     v.setValue(2, cos(radPitch) * sin(radHeading));
00127 
00128     return v;
00129 }
00130 
00131 float Scene::distanceToZone(float spotHeading, float spotPitch, float spotRadius, float heading, float pitch) {
00132     Math::Vector3d vLookAt = directionToVector(pitch, heading);
00133     Math::Vector3d vSun = directionToVector(spotPitch, spotHeading);
00134     float dotProduct = Math::Vector3d::dotProduct(vLookAt, -vSun);
00135 
00136     float distance = (0.05 * spotRadius - (dotProduct + 1.0) * 90) / (0.05 * spotRadius);
00137     return CLIP<float>(distance, 0.0, 1.0);
00138 }
00139 
00140 void Scene::updateMouseSpeed() {
00141     _mouseSpeed = ConfMan.getInt("mouse_speed");
00142 }
00143 
00144 Common::Rect Scene::getPosition() const {
00145     Common::Rect screen = _vm->_gfx->viewport();
00146 
00147     Common::Rect frame;
00148     if (_vm->isWideScreenModEnabled()) {
00149         int32 viewportWidth = Renderer::kOriginalWidth;
00150 
00151         int32 viewportHeight;
00152         if (_vm->_state->getViewType() == kMenu) {
00153             viewportHeight = Renderer::kOriginalHeight;
00154         } else {
00155             viewportHeight = Renderer::kFrameHeight;
00156         }
00157 
00158         // Aspect ratio correction
00159         frame = Common::Rect(MIN<int32>(screen.width(), screen.height() * viewportWidth / viewportHeight),
00160                              MIN<int32>(screen.height(), screen.width() * viewportHeight / viewportWidth));
00161 
00162         // Pillarboxing
00163         uint left = (screen.width() - frame.width()) / 2;
00164 
00165         uint top;
00166         if (_vm->_state->getViewType() == kMenu) {
00167             top = (screen.height() - frame.height()) / 2;
00168         } else {
00169             top = (screen.height() - frame.height()) * Renderer::kTopBorderHeight / (Renderer::kTopBorderHeight + Renderer::kBottomBorderHeight);
00170         }
00171 
00172         frame.translate(left, top);
00173     } else {
00174         if (_vm->_state->getViewType() != kMenu) {
00175             frame = Common::Rect(screen.width(), screen.height() * Renderer::kFrameHeight / Renderer::kOriginalHeight);
00176             frame.translate(screen.left, screen.top + screen.height() * Renderer::kTopBorderHeight / Renderer::kOriginalHeight);
00177         } else {
00178             frame = screen;
00179         }
00180     }
00181 
00182     return frame;
00183 }
00184 
00185 Common::Rect Scene::getOriginalPosition() const {
00186     Common::Rect originalPosition;
00187 
00188     if (_vm->_state->getViewType() != kMenu) {
00189         originalPosition = Common::Rect(Renderer::kOriginalWidth, Renderer::kFrameHeight);
00190         originalPosition.translate(0, Renderer::kTopBorderHeight);
00191     } else {
00192         originalPosition = Common::Rect(Renderer::kOriginalWidth, Renderer::kOriginalHeight);
00193     }
00194 
00195     return originalPosition;
00196 }
00197 
00198 void Scene::screenPosToDirection(const Common::Point &screen, float &pitch, float &heading) const {
00199     Common::Rect frame = getPosition();
00200 
00201     // Screen coords to window coords
00202     Common::Point pos = screenPosToWindowPos(screen);
00203 
00204     // Window coords to normalized coords
00205     Math::Vector4d in;
00206     in.x() = pos.x * 2 / (float) frame.width() - 1.0;
00207     in.y() = 1.0 - pos.y * 2 / (float) frame.height();
00208     in.z() = 1.0;
00209     in.w() = 1.0;
00210 
00211     // Normalized coords to direction
00212     Math::Matrix4 A = _vm->_gfx->getMvpMatrix();
00213     A.inverse();
00214     Math::Vector4d out = A.transform(in);
00215 
00216     Math::Vector3d direction(out.x(), out.y(), out.z());
00217     direction.normalize();
00218 
00219     // 3D coords to polar coords
00220     Math::Vector2d horizontalProjection = Math::Vector2d(direction.x(), direction.z());
00221     horizontalProjection.normalize();
00222 
00223     pitch = 90 - Math::Angle::arcCosine(direction.y()).getDegrees();
00224     heading = Math::Angle::arcCosine(horizontalProjection.getY()).getDegrees();
00225 
00226     if (horizontalProjection.getX() > 0.0)
00227         heading = 360 - heading;
00228 }
00229 
00230 } // end of namespace Myst3


Generated on Sat Mar 16 2019 05:01:52 for ResidualVM by doxygen 1.7.1
curved edge   curved edge