#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 #include MTextureView::MTextureView(QWidget *parent, const char *name) : MGLView(parent, name) { int i, j; _numTiles = MPreferences::get()->getTexSize(); _minU = -1.0; _minV = -1.0; _maxU = 1.0; _maxV = 1.0; _position = "0.0 0.0 10.0"; _selectedVertex = NULL; setMouseTracking(true); /// Create the background tile pattern... _background = new unsigned int[4*64*64]; for(j = 0; j < 64; j++) { for(i = 0; i < 64; i++) { if((i + j) % 2 == 0) _background[j*64 + i] = 0xffcccccc; else _background[j*64 + i] = 0xff666666; } } } MTextureView::~MTextureView() { delete _background; } void MTextureView::renderView(void) { int i, j; MLine viewRay; float emission[] = {0.5, 0.5, 0.5, 1.0}; MTexture *texturePtr; MShape *shape; MFacet *f; MVector *v; int i1, i2, i3; if(!isVisible()) return; if(!MDocument::get()->getSelectedShape()) { MMainWindow::get()->onQuadView(); return; } shape = MDocument::get()->getSelectedShape(); texturePtr = MMaterialManager::get()->getTexture((shape->getMaterial()).getTexture()); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, (GLint)width(), (GLint)height()); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); _camera.createOrthoView(_minU, _minV, _maxU, _maxV, 0.1, 20.0, width(), height()); _camera.setPosition(_position); _camera.render(); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glEnable(GL_LIGHTING); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)_background); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex3f(_minU + _position[0], _minV + _position[1], -0.3); glTexCoord2f(1.0, 0.0); glVertex3f(_maxU + _position[0], _minV + _position[1], -0.3); glTexCoord2f(1.0, 1.0); glVertex3f(_maxU + _position[0], _maxV + _position[1], -0.3); glTexCoord2f(0.0, 1.0); glVertex3f(_minU + _position[0], _maxV + _position[1], -0.3); glEnd(); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturePtr->width(), texturePtr->height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char *)texturePtr->bytes()); glMaterialfv(GL_FRONT, GL_EMISSION, &emission[0]); glBegin(GL_QUADS); for(j = -_numTiles; j < _numTiles; j++) { for(i = -_numTiles; i < _numTiles; i++) { glTexCoord2f(0.0, 0.0); glVertex3f((float)i, (float)j, -0.2); glTexCoord2f(1.0, 0.0); glVertex3f((float)i + 1.0, (float)j, -0.2); glTexCoord2f(1.0, 1.0); glVertex3f((float)i + 1.0, (float)j + 1.0, -0.2); glTexCoord2f(0.0, 1.0); glVertex3f((float)i, (float)j + 1.0, -0.2); } } glEnd(); glDisable(GL_LIGHTING); glDisable(GL_BLEND); glDisable(GL_TEXTURE_2D); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glColor3f(0.0, 0.5, 1.0); glBegin(GL_QUADS); for(j = -_numTiles; j < _numTiles; j++) { for(i = -_numTiles; i < _numTiles; i++) { glTexCoord2f(0.0, 0.0); glVertex3f((float)i, (float)j, -0.1); glTexCoord2f(1.0, 0.0); glVertex3f((float)i + 1.0, (float)j, -0.1); glTexCoord2f(1.0, 1.0); glVertex3f((float)i + 1.0, (float)j + 1.0, -0.1); glTexCoord2f(0.0, 1.0); glVertex3f((float)i, (float)j + 1.0, -0.1); } } glEnd(); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); /// Render the UV-coordinate grid. QPtrList &facets = shape->getFacetList(); QPtrList &textureVertices = shape->getTextureVertexList(); glColor3f(1.0, 1.0, 1.0); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glBegin(GL_TRIANGLES); for(f = facets.first(); f; f = facets.next()) { i1 = f->getTextureVertexRef(0); i2 = f->getTextureVertexRef(1); i3 = f->getTextureVertexRef(2); if(i1 >= 0 && i2 >= 0 && i3 >= 0) { glVertex3fv(textureVertices.at(i1)->values()); glVertex3fv(textureVertices.at(i2)->values()); glVertex3fv(textureVertices.at(i3)->values()); } } glEnd(); glColor3f(1.0, 0.0, 0.0); glPointSize(5.0); glBegin(GL_POINTS); for(v = textureVertices.first(); v; v = textureVertices.next()) { glVertex3fv(v->values()); } glEnd(); glPointSize(1.0); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } int MTextureView::getNumTiles(void) { return _numTiles; } void MTextureView::setNumTiles(int num) { _numTiles = num; if(_numTiles < 1) _numTiles = 1; if(_numTiles > 100) _numTiles = 100; updateGL(); } float MTextureView::getMaxLength(void) { return fabs(_maxU - _minU); } bool MTextureView::displaysSingleTexture(void) { if((_position[0] == 0.5) && (_position[1] == 0.5) && (_minU == -0.5) && (_maxU == 0.5) && (_minV == -0.5) && (_maxV == 0.5)) return true; return false; } MVector MTextureView::getPosition(void) { return _position; } /// High level event handlers. void MTextureView::onSelectShape(void) { // reserved. } void MTextureView::onMoveShapeInit(void) { } void MTextureView::onMoveShapePerform(void) { MShape *shape; MVector *v; float du, dv; if(!isVisible()) return; if(!MDocument::get()->getSelectedShape()) return; shape = MDocument::get()->getSelectedShape(); QPtrList &textureVertices = shape->getTextureVertexList(); du = ((float)_mouseDX)/((float)size().width())*(_maxU - _minU); dv = ((float)_mouseDY)/((float)size().height())*(_maxV - _minV); for(v = textureVertices.first(); v; v = textureVertices.next()) { (*v)[0] += du; (*v)[1] -= dv; } updateGL(); } void MTextureView::onMoveShapeFinish(void) { } void MTextureView::onRotateShapeInit(void) { } void MTextureView::onRotateShapePerform(void) { MShape *shape; MVector *v; MMatrix R; if(!isVisible()) return; if(!MDocument::get()->getSelectedShape()) return; if(_mouseDS > 0.0) { MDocument::get()->commit(); MDocument::get()->lock(); } shape = MDocument::get()->getSelectedShape(); QPtrList &textureVertices = shape->getTextureVertexList(); R.loadRotationZ(-0.5*_mouseDX); for(v = textureVertices.first(); v; v = textureVertices.next()) { (*v) = R*(*v); } updateGL(); } void MTextureView::onRotateShapeFinish(void) { } void MTextureView::onScaleShapeInit(void) { } void MTextureView::onScaleShapePerform(void) { MShape *shape; MVector *v; if(!isVisible()) return; if(!MDocument::get()->getSelectedShape()) return; if(_mouseDS > 0.0) { MDocument::get()->commit(); MDocument::get()->lock(); } shape = MDocument::get()->getSelectedShape(); QPtrList &textureVertices = shape->getTextureVertexList(); for(v = textureVertices.first(); v; v = textureVertices.next()) { if(fabs(_mouseDX) > fabs(_mouseDY)) { if(_mouseDX < 0.0) { (*v)[0] *= 0.98; } else { (*v)[0] *= 1.02; } } else { if(_mouseDY > 0.0) { (*v)[1] *= 0.98; } else { (*v)[1] *= 1.02; } } } updateGL(); } void MTextureView::onScaleShapeFinish(void) { } void MTextureView::onMoveVertexInit(void) { MVector p, p_tilde, dp, x0, v; float lambda, distance; MLine ray; MCamera camera; MVector *tv; if(!MDocument::get()->getSelectedShape()) return; camera.createOrthoView(_minU, _minV, _maxU, _maxV, 0.1, 20.0, size().width(), size().height()); camera.setPosition(_position); ray = camera.getViewRay(_oldMouseX, _oldMouseY); distance = 1000000.0; x0 = ray[0]; v = ray[1] - ray[0]; v.normalize(); QPtrList &textureVertices = MDocument::get()->getSelectedShape()->getTextureVertexList(); for(tv = textureVertices.first(); tv; tv = textureVertices.next()) { p = *tv; lambda = (p - x0)*v; p_tilde = x0 + lambda*v; dp = p_tilde - p; if(sqrt(dp*dp) < distance) { distance = sqrt(dp*dp); _selectedVertex = tv; } } updateGL(); } void MTextureView::onMoveVertexPerform(void) { float du, dv; if(!_selectedVertex) return; if(!isVisible()) return; if(!MDocument::get()->getSelectedShape()) return; du = ((float)_mouseDX)/((float)size().width())*(_maxU - _minU); dv = ((float)_mouseDY)/((float)size().height())*(_maxV - _minV); (*_selectedVertex)[0] += du; (*_selectedVertex)[1] -= dv; updateGL(); } void MTextureView::onMoveVertexFinish(void) { if(!_selectedVertex) return; MCoordinateSystem::get()->snap(*_selectedVertex); _selectedVertex = NULL; updateGL(); } void MTextureView::onZoomView(void) { if(_mouseDY < 0) { _minU *= 1.05; _minV *= 1.05; _maxU *= 1.05; _maxV *= 1.05; } if(_mouseDY > 0) { _minU *= 0.95; _minV *= 0.95; _maxU *= 0.95; _maxV *= 0.95; } updateGL(); } void MTextureView::onMoveView(void) { _position[0] -= ((float)_mouseDX)/((float)size().width())*(_maxU - _minU); _position[1] += ((float)_mouseDY)/((float)size().height())*(_maxV - _minV); _position[2] = 10.0; updateGL(); } void MTextureView::onResetView(void) { _minU = -1.0; _minV = -1.0; _maxU = 1.0; _maxV = 1.0; _position = "0.0 0.0 10.0"; updateGL(); } QString MTextureView::mousePosition3D(void) { return QString("add this feature"); }