123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- /*************************************************************************************/
- /** **/
- /** Copyright (c) 1999-2009 Tatewake.com **/
- /** **/
- /** Permission is hereby granted, free of charge, to any person obtaining a copy **/
- /** of this software and associated documentation files (the "Software"), to deal **/
- /** in the Software without restriction, including without limitation the rights **/
- /** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell **/
- /** copies of the Software, and to permit persons to whom the Software is **/
- /** furnished to do so, subject to the following conditions: **/
- /** **/
- /** The above copyright notice and this permission notice shall be included in **/
- /** all copies or substantial portions of the Software. **/
- /** **/
- /** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR **/
- /** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, **/
- /** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE **/
- /** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER **/
- /** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, **/
- /** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN **/
- /** THE SOFTWARE. **/
- /** **/
- /*************************************************************************************/
- #include <glcomp/glcompdefs.h>
- #define ARCBALL_C
- #include "smyrnadefs.h"
- #include "arcball.h"
- static void setBounds(ArcBall_t *a, float NewWidth, float NewHeight) {
- assert((NewWidth > 1.0f) && (NewHeight > 1.0f));
- //Set adjustment factor for width/height
- a->AdjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f);
- a->AdjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);
- }
- static void mapToSphere(ArcBall_t * a, const Point2fT * NewPt,
- Vector3fT * NewVec)
- {
- Point2fT TempPt;
- //Copy paramter into temp point
- TempPt = *NewPt;
- //Adjust point coords and scale down to range of [-1 ... 1]
- TempPt.s.X = (TempPt.s.X * a->AdjustWidth) - 1.0f;
- TempPt.s.Y = 1.0f - (TempPt.s.Y * a->AdjustHeight);
- //Compute the square of the length of the vector to the point from the center
- float length = TempPt.s.X * TempPt.s.X + TempPt.s.Y * TempPt.s.Y;
- //If the point is mapped outside of the sphere... (length > radius squared)
- if (length > 1.0f) {
- //Compute a normalizing factor (radius / sqrt(length))
- float norm = 1.0f / FuncSqrt(length);
- //Return the "normalized" vector, a point on the sphere
- NewVec->s.X = TempPt.s.X * norm;
- NewVec->s.Y = TempPt.s.Y * norm;
- NewVec->s.Z = 0.0f;
- } else //Else it's on the inside
- {
- //Return a vector to a point mapped inside the sphere sqrt(radius squared - length)
- NewVec->s.X = TempPt.s.X;
- NewVec->s.Y = TempPt.s.Y;
- NewVec->s.Z = FuncSqrt(1.0f - length);
- }
- }
- static Matrix4fT Transform = { {1.0f, 0.0f, 0.0f, 0.0f, // NEW: Final Transform
- 0.0f, 1.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 1.0f}
- };
- static Matrix3fT LastRot = { {1.0f, 0.0f, 0.0f, // NEW: Last Rotation
- 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 1.0f}
- };
- static Matrix3fT ThisRot = { {1.0f, 0.0f, 0.0f, // NEW: This Rotation
- 0.0f, 1.0f, 0.0f,
- 0.0f, 0.0f, 1.0f}
- };
- //Create/Destroy
- void init_arcBall(ArcBall_t *a, float NewWidth, float NewHeight) {
- a->Transform = Transform;
- a->LastRot = LastRot;
- a->ThisRot = ThisRot;
- //Clear initial values
- a->StVec.s.X =
- a->StVec.s.Y =
- a->StVec.s.Z = a->EnVec.s.X = a->EnVec.s.Y = a->EnVec.s.Z = 0.0f;
- //Set initial bounds
- setBounds(a, NewWidth, NewHeight);
- a->isClicked = 0;
- a->isRClicked = 0;
- a->isDragging = 0;
- }
- //Mouse down
- static void click(ArcBall_t * a, const Point2fT * NewPt)
- {
- //Map the point to the sphere
- mapToSphere(a, NewPt, &a->StVec);
- }
- //Mouse drag, calculate rotation
- static void drag(ArcBall_t * a, const Point2fT * NewPt, Quat4fT * NewRot)
- {
- //Map the point to the sphere
- mapToSphere(a, NewPt, &a->EnVec);
- //Return the quaternion equivalent to the rotation
- if (NewRot) {
- Vector3fT Perp;
- //Compute the vector perpendicular to the begin and end vectors
- Vector3fCross(&Perp, &a->StVec, &a->EnVec);
- //Compute the length of the perpendicular vector
- if (Vector3fLength(&Perp) > Epsilon) //if its non-zero
- {
- //We're ok, so return the perpendicular vector as the transform after all
- NewRot->s.X = Perp.s.X;
- NewRot->s.Y = Perp.s.Y;
- NewRot->s.Z = Perp.s.Z;
- //In the quaternion values, w is cosine (theta / 2), where theta is rotation angle
- NewRot->s.W = Vector3fDot(&a->StVec, &a->EnVec);
- } else //if its zero
- {
- //The begin and end vectors coincide, so return an identity transform
- NewRot->s.X = NewRot->s.Y = NewRot->s.Z = NewRot->s.W = 0.0f;
- }
- }
- }
- void arcmouseClick(void)
- {
- view->arcball->isDragging = 1; // Prepare For Dragging
- view->arcball->LastRot = view->arcball->ThisRot; // Set Last Static Rotation To Last Dynamic One
- click(view->arcball, &view->arcball->MousePt);
- }
- void arcmouseDrag(void)
- {
- Quat4fT ThisQuat;
- drag(view->arcball, &view->arcball->MousePt, &ThisQuat);
- Matrix3fSetRotationFromQuat4f(&view->arcball->ThisRot, &ThisQuat); // Convert Quaternion Into Matrix3fT
- Matrix3fMulMatrix3f(&view->arcball->ThisRot, &view->arcball->LastRot); // Accumulate Last Rotation Into This One
- Matrix4fSetRotationFromMatrix3f(&view->arcball->Transform, &view->arcball->ThisRot); // Set Our Final Transform's Rotation From This One
- }
|