#include /* This file is part of moth. moth is a program for creating and editing textured 3D models. Copyright (C) 2004 Peter Uray. moth 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 2 of the License, or (at your option) any later version. moth 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 moth; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include MItemManipulator *MItemManipulator::_this = NULL; MItemManipulator::MItemManipulator(void) { _eraseVertex = false; } MItemManipulator *MItemManipulator::get(void) { if(!_this) { _this = new MItemManipulator(); } return _this; } void MItemManipulator::render(void) { MVector pai; // point at infinity.. MVector x; MVertex *v; MShape *master; unsigned int i; _item = MDocument::get()->getSelectedItem(); if(!_item) return; _x0 = _item->getPosition(); _x1 = _x0 + _item->getDirection(); _x3 = _x0 + _item->getUp(); _x2 = _x0 + (_item->getUp() ^ _item->getDirection()); pai = _x0 + 100000.0*_item->getDirection(); glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); glDisable(GL_LIGHTING); glLineWidth(3.0); glPointSize(10.0); // light axis if(_item->getType() == MEnum::LightSource) { glBegin(GL_LINES); glColor3f(1.0, 1.0, 0.0); glVertex3fv(_x0.values()); glVertex3fv(pai.values()); glEnd(); } glDepthFunc(GL_ALWAYS); // direction. glBegin(GL_LINES); glColor3f(1.0, 0.0, 0.0); glVertex3fv(_x0.values()); glVertex3fv(_x1.values()); glEnd(); // normal. glBegin(GL_LINES); glColor3f(0.0, 1.0, 0.0); glVertex3fv(_x0.values()); glVertex3fv(_x2.values()); glEnd(); // up. glBegin(GL_LINES); glColor3f(0.0, 0.0, 1.0); glVertex3fv(_x0.values()); glVertex3fv(_x3.values()); glEnd(); glBegin(GL_POINTS); glColor3f(1.0, 1.0, 1.0); glVertex3fv(_x0.values()); glColor3f(1.0, 0.0, 0.0); glVertex3fv(_x1.values()); glColor3f(0.0, 1.0, 0.0); glVertex3fv(_x2.values()); glColor3f(0.0, 0.0, 1.0); glVertex3fv(_x3.values()); glEnd(); // shape vertices if applicable if(_item->getType() == MEnum::Shape) { glLineWidth(1.0); glPointSize(5.0); glColor3f(1.0, 0.0, 0.0); QPtrList &vertices = MShapePtr(_item)->getVertexList(); glBegin(GL_POINTS); for(v = vertices.first(); v; v = vertices.next()) { x = v->getPosition(); glVertex3fv(x.values()); } glEnd(); } // selected vertices if applicable if(_item->getType() == MEnum::Shape) { glLineWidth(1.0); glPointSize(5.0); glColor3f(1.0, 0.7, 0.0); QPtrList &vertices = MShapePtr(_item)->getVertexList(); glBegin(GL_POINTS); for(i = 0; i < _vertexStack.size(); i++) { x = vertices.at(_vertexStack[i])->getPosition(); glVertex3fv(x.values()); } glEnd(); } // master vertices if applicable. master = MDocument::get()->getMaster(); if(master) { glLineWidth(1.0); glPointSize(5.0); glColor3f(0.0, 0.0, 1.0); QPtrList &vertices = master->getVertexList(); glBegin(GL_POINTS); for(v = vertices.first(); v; v = vertices.next()) { x = v->getPosition(); glVertex3fv(x.values()); } glEnd(); } glLineWidth(1.0); glPointSize(1.0); } void MItemManipulator::set(MSceneGraphItem *item) { _item = item; } MGLView::MAxis MItemManipulator::findAxis(MLine ray, float epsilon) { float distance; MVector p_tilde, dp, x0, v; float lambda; _item = MDocument::get()->getSelectedItem(); if(!_item) return MGLView::NoAxis; _x0 = _item->getPosition(); _x1 = _x0 + _item->getDirection(); _x2 = _x0 + _item->getUp(); _x3 = _x0 + (_item->getUp() ^ _item->getDirection()); x0 = ray[0]; v = ray[1] - ray[0]; v.normalize(); distance = 0; // check x-handle lambda = (_x1 - x0)*v; p_tilde = x0 + lambda*v; dp = p_tilde - _x1; distance = sqrt(dp*dp); if(distance < epsilon) return MGLView::XAxis; // check y-handle lambda = (_x2 - x0)*v; p_tilde = x0 + lambda*v; dp = p_tilde - _x2; distance = sqrt(dp*dp); if(distance < epsilon) return MGLView::ZAxis; // check z-handle lambda = (_x3 - x0)*v; p_tilde = x0 + lambda*v; dp = p_tilde - _x3; distance = sqrt(dp*dp); if(distance < epsilon) return MGLView::YAxis; return MGLView::NoAxis; } void MItemManipulator::addVertex(int index) { QValueVector::iterator pos; for(pos = _vertexStack.begin(); pos != _vertexStack.end(); pos++) { if(*pos == index) { return; } } _vertexStack.push_back(index); } void MItemManipulator::removeVertex(int index) { QValueVector::iterator pos; for(pos = _vertexStack.begin(); pos != _vertexStack.end(); pos++) { if(*pos == index) { _vertexStack.erase(pos); return; } } } void MItemManipulator::clearVertexStack(void) { _vertexStack.clear(); } unsigned int MItemManipulator::getVertexStackSize(void) { return _vertexStack.size(); } int MItemManipulator::getVertexStackEntry(int index) { return _vertexStack[index]; } bool MItemManipulator::hasVertexStackEntry(int index) { unsigned int i; for(i = 0; i < _vertexStack.size(); i++) { if(_vertexStack[i] == index) return true; } return false; } void MItemManipulator::selectVertices(MLine &ray) { int i; MVector p, p_tilde, dp, x0, v; float lambda; MVertex *vertex; float distance, minDistance, maxDistance; int selectedVertex; x0 = ray[0]; v = ray[1] - ray[0]; v.normalize(); QPtrList &vl = MDocument::get()->getSelectedShape()->getVertexList(); i = 0; selectedVertex = -1; minDistance = 10000000.0; maxDistance = 0.3*(MPreferences::get()->getGridDX() + MPreferences::get()->getGridDY() + MPreferences::get()->getGridDZ()); for(vertex = vl.first(); vertex; vertex = vl.next()) { p = vertex->getPosition(); lambda = (p - x0)*v; p_tilde = x0 + lambda*v; dp = p_tilde - p; distance = sqrt(dp*dp); if(distance < maxDistance && distance < minDistance) { //if(_eraseVertex) removeVertex(i); //else addVertex(i); minDistance = distance; selectedVertex = i; } i++; } if(selectedVertex >= 0) { if(_eraseVertex) removeVertex(selectedVertex); else addVertex(selectedVertex); } } int MItemManipulator::selectMasterVertex(MLine &ray) { int i; MVector p, p_tilde, dp, x0, v; float distance, minDistance, maxDistance; float lambda; MVertex *vertex; int selectedVertex; if(!MDocument::get()->getMaster()) return -1; x0 = ray[0]; v = ray[1] - ray[0]; v.normalize(); QPtrList &vl = MDocument::get()->getMaster()->getVertexList(); i = 0; selectedVertex = -1; minDistance = 1000000.0; maxDistance = 0.3*(MPreferences::get()->getGridDX() + MPreferences::get()->getGridDY() + MPreferences::get()->getGridDZ()); for(vertex = vl.first(); vertex; vertex = vl.next()) { p = vertex->getPosition(); lambda = (p - x0)*v; p_tilde = x0 + lambda*v; dp = p_tilde - p; distance = sqrt(dp*dp); if(distance < maxDistance && distance < minDistance) { minDistance = distance; selectedVertex = i; } i++; } return selectedVertex; } void MItemManipulator::setEraseVertexTo(bool value) { _eraseVertex = value; }