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

hotspot.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 "engines/myst3/hotspot.h"
00024 #include "engines/myst3/scene.h"
00025 #include "engines/myst3/state.h"
00026 
00027 #include "common/config-manager.h"
00028 #include "common/math.h"
00029 
00030 #include "math/ray.h"
00031 
00032 namespace Myst3 {
00033 
00034 static void polarRectTo3dRect(const PolarRect &polarRect,
00035                               Math::Vector3d &topLeft, Math::Vector3d &topRight,
00036                               Math::Vector3d &bottomLeft, Math::Vector3d &bottomRight) {
00037     static const float scale = 50.0;
00038 
00039     Math::Vector3d direction = Scene::directionToVector(polarRect.centerPitch, 90.0 - polarRect.centerHeading) * scale;
00040 
00041     Math::Vector3d u = Math::Vector3d(direction.z(), 0.0, -direction.x());
00042     u.normalize();
00043 
00044     Math::Vector3d v = Math::Vector3d::crossProduct(direction, u);
00045     v.normalize();
00046 
00047     Math::Vector3d sizeU = u * polarRect.width  / 90.0 * scale;
00048     Math::Vector3d sizeV = v * polarRect.height / 90.0 * scale;
00049 
00050     topRight = direction + sizeV + sizeU;
00051     bottomRight = direction - sizeV + sizeU;
00052     bottomLeft = direction - sizeV - sizeU;
00053     topLeft = direction + sizeV - sizeU;
00054 }
00055 
00056 bool static rayIntersectsRect(const Math::Ray &ray, const Math::Vector3d &topLeft, const Math::Vector3d &topRight,
00057                               const Math::Vector3d &bottomLeft, const Math::Vector3d &bottomRight) {
00058     // Orthogonal basis in rectangle coordinates
00059     Math::Vector3d topRectDir = topRight - topLeft;
00060     Math::Vector3d leftRectDir = bottomLeft - topLeft;
00061     Math::Vector3d n = Math::Vector3d::crossProduct(topRectDir, leftRectDir);
00062 
00063     float nDotDir = Math::Vector3d::dotProduct(n, ray.getDirection());
00064     if (ABS(nDotDir) < 1e-6) {
00065         // The ray is coplanar with the rectangle
00066         return false;
00067     }
00068 
00069     // Solution to the system (intersection of line with plane):
00070     // Line equation: V = ray.origin + t * ray.direction
00071     // Plane equation: dot(n, V) = 0
00072     float t = -Math::Vector3d::dotProduct(n, ray.getOrigin() - topLeft) / nDotDir;
00073 
00074     if (t < 0.0) {
00075         // The intersection is not in the ray direction
00076         return false;
00077     }
00078 
00079     // Intersection point in world coordinates
00080     Math::Vector3d intersection = ray.getOrigin() + ray.getDirection() * t;
00081 
00082     // Intersection point in 2D rect coordinates
00083     Math::Vector3d intersect2D = intersection - topLeft;
00084     float u = Math::Vector3d::dotProduct(intersect2D, topRectDir);
00085     float v = Math::Vector3d::dotProduct(intersect2D, leftRectDir);
00086 
00087     // Intersection inside the rectangle
00088     return (u >= 0.0 && u <= Math::Vector3d::dotProduct(topRectDir, topRectDir)
00089             && v >= 0.0 && v <= Math::Vector3d::dotProduct(leftRectDir, leftRectDir));
00090 }
00091 
00092 HotSpot::HotSpot() :
00093         condition(0),
00094         cursor(0) {
00095 }
00096 
00097 int32 HotSpot::isPointInRectsCube(float pitch, float heading) {
00098     for (uint j = 0; j < rects.size(); j++) {
00099         Math::Ray ray = Math::Ray(Math::Vector3d(), Scene::directionToVector(pitch, 90.0 - heading));
00100 
00101         Math::Vector3d topLeft, topRight, bottomLeft, bottomRight;
00102         polarRectTo3dRect(rects[j], topLeft, topRight, bottomLeft, bottomRight);
00103 
00104         if (rayIntersectsRect(ray, topLeft, topRight, bottomLeft, bottomRight)) {
00105             return j;
00106         }
00107     }
00108 
00109     return -1;
00110 }
00111 
00112 int32 HotSpot::isPointInRectsFrame(GameState *state, const Common::Point &p) {
00113     for (uint j = 0; j < rects.size(); j++) {
00114         int16 x = rects[j].centerPitch;
00115         int16 y = rects[j].centerHeading;
00116         int16 w = rects[j].width;
00117         int16 h = rects[j].height;
00118 
00119         if (y < 0) {
00120             x = state->getVar(x);
00121             y = state->getVar(-y);
00122             h = -h;
00123         }
00124 
00125         Common::Rect rect = Common::Rect(w, h);
00126         rect.translate(x, y);
00127         if (rect.contains(p))
00128             return j;
00129     }
00130 
00131     return -1;
00132 }
00133 
00134 bool HotSpot::isEnabled(GameState *state, uint16 var) {
00135     if (!state->evaluate(condition))
00136         return false;
00137 
00138     if (isZip()) {
00139         if (!ConfMan.getBool("zip_mode") || !isZipDestinationAvailable(state)) {
00140             return false;
00141         }
00142     }
00143 
00144     if (var == 0)
00145         return cursor <= 13;
00146     else
00147         return cursor == var;
00148 }
00149 
00150 int32 HotSpot::isZipDestinationAvailable(GameState *state) {
00151     assert(isZip() && script.size() != 0);
00152 
00153     uint16 node;
00154     uint16 room = state->getLocationRoom();
00155     uint32 age = state->getLocationAge();
00156 
00157     // Get the zip destination from the script
00158     Opcode op = script[0];
00159     switch (op.op) {
00160     case 140:
00161     case 142:
00162         node = op.args[0];
00163         break;
00164     case 141:
00165     case 143:
00166         node = op.args[1];
00167         room = op.args[0];
00168         break;
00169     default:
00170         error("Expected zip action");
00171     }
00172 
00173     return state->isZipDestinationAvailable(node, room, age);
00174 }
00175 
00176 } // End of namespace Myst3


Generated on Sat May 18 2019 05:01:04 for ResidualVM by doxygen 1.7.1
curved edge   curved edge