/* * Copyright (c) 2015 Tricoire Sebastien 3dsman@free.fr * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * */ #include "OE_interfaceDisplay.h" #include "OE_utils.h" #include "OE_controller.h" #include #include #include #include #include #include #include #include "actions/OE_actionsCurves.h" #include "actions/OE_actionsStitchs.h" #include "actions/OE_actionsLineStitchs.h" #include "actions/OE_actionsBirailStitchs.h" #include "actions/OE_actionsFillStitchs.h" #include "actions/OE_actionsLinkStitchs.h" #include "actions/OE_actionsSelection.h" #include "actions/OE_actionsThreads.h" static const GLuint TOOLSSELID = 0; static const GLuint STITCHSSELID = 1; static const GLuint CURVESSELID = 2; static const GLuint ZEROID = 0; static const GLuint TRANSTOOLID = 1; static const GLuint MOVETOOLID = 0; static const GLuint SCALETOOLID = 1; OE_interfaceDisplay::OE_interfaceDisplay(OE_document* document) { editStyle = new OE_display::OE_displayStyle(); commandStyle = new OE_display::OE_displayStyle(); commandStyle->drawGrid = false; commandStyle->drawCurves = false; commandStyle->drawStitches = false; commandStyle->drawCommands = true; setDisplayStyle(editStyle); setDocument(document); } OE_interfaceDisplay::~OE_interfaceDisplay() { //delete curDisplay; } bool OE_interfaceDisplay::setDocument(OE_document* document) { this->document = document; return true; } bool OE_interfaceDisplay::setController(OE_controller* controller) { this->controller = controller; return true; } void OE_interfaceDisplay::showAll() { OE_display::showAll(); } void OE_interfaceDisplay::mouse_Pos(double x, double y) { OE_display::mouse_Pos(x, y); vector_2dt oldClosestPoint = editClosestPoint; vector_2d absMove = vector_2d((mouse.x - clicOldMouse.x)*zoom*2, (mouse.y - clicOldMouse.y)*zoom*2); if (editionState == MoveSelection) //if the move action is enabled { controller->editActionMoveSelection(vector_2d((mouse.x - clicOldMouse.x)*zoom*2, (mouse.y - clicOldMouse.y)*zoom*2)); return; } if (editionState == ScaleSelection) //if the scale action is enabled { vector_2d bbCenter = controller->getSelectionBoundingBox().getCenter(); float scale = (absMouse-bbCenter).len()/(screenToDocument(clicOldMouse)-bbCenter).len(); controller->editActionScaleSelection(vector_2d(scale,scale)); return; } if (editSubcurve) //if we are working on a defined subcurve get the closest point on it { editClosestPoint = controller->getClosestPoint(editSubcurve->getCurve(), absMouse); } if (editionState == NewSubcurve) //if we must find the closest subcurve (get the closest point on it too) { closestCurve = controller->getClosestCurve(absMouse, editClosestPoint); } if (selControlCurve && selControlType==0) //if we're moving a curve control point { controller->editActionMovePointCurve(vector_2d((mouse.x - clicOldMouse.x)*zoom*2, (mouse.y - clicOldMouse.y)*zoom*2)); return; } if (editionState == MovePointstitch) //if we're moving a linkstitch control point { controller->editActionMovePointLinkStitch(absMove); return; } if (selControlStitch) //if we're working on a stitch { OE_linestitch* tmpLineStitch = dynamic_cast(selControlStitch); OE_birailstitch* tmpBirailStitch = dynamic_cast(selControlStitch); OE_fillstitch* tmpFillStitch = dynamic_cast(selControlStitch); if (tmpLineStitch && editionState == OffsetWidthLinestitch) //if this is a linestitch and we're picking the scaleWidth controler { controller->editActionSetLinestitchWidth((mouse.x - clicOldMouse.x)/100.0f, true); return; } //if we're define control curves for linestitch or birailstitch if ((tmpLineStitch && selControlType == 0)|| (tmpFillStitch && selControlType == 0)|| (tmpBirailStitch && (selControlType == 0 || selControlType == 1))) { if (editionState == NewSubcurve) { editionState = TraceSubcurve; if (oldClosestPoint.t>editClosestPoint.t) controller->editActionAddSubcurvePosSwitchDir(); } if (editionState == TraceSubcurve) { controller->editActionAddSubcurvePosEnd(editClosestPoint.t); } else { controller->editActionSetSubcurvePos(editClosestPoint.t); } } } } void OE_interfaceDisplay::mouse_Button(int button, int action, int mods) { modState = mods; OE_display::mouse_Button(button, action, mods); if (curScreen == edit && button == GLFW_MOUSE_BUTTON_LEFT && action==GLFW_PRESS) { if (editionState == NewSubcurve) { if (!closestCurve) { editionState = None; return; } else { controller->addAction(new OE_actionJoincurveAddSubCurve(curJoincurve, -1, closestCurve, editClosestPoint.t, editClosestPoint.t, false)); selControlStitch = controller->getStitch(-1); selControlType = 0; editSubcurve = curJoincurve->getCurve(-1); return; } } else { clicOldMouse = mouse; if (editionState == None) { picking(); } if (editionState == None) { editionState = Selection; } return; } } if (curScreen == edit && button == GLFW_MOUSE_BUTTON_LEFT && action==GLFW_RELEASE) { //if (selControlCurve)selControlCurve = 0; //if (selControlStitch)selControlStitch = 0; selControlCurve = 0; selControlStitch = 0; if (editionState == Selection) { if ((mouse-clicOldMouse).len()>5) { selectBox(); } selectApply(selectedCurves, selectedStitches); editionState = None; } if (editionState == TraceSubcurve) { editionState = NewSubcurve; editSubcurve = 0; return; } if (editionState == MoveSubcurve || editionState == MovePointcurve || editionState == MovePointstitch || editionState == DelPointstitch || editionState == MoveSelection || editionState == ScaleSelection) { editionState = None; } } } void OE_interfaceDisplay::scroll(double xoffset, double yoffset) { OE_display::scroll(xoffset, yoffset); } void OE_interfaceDisplay::resize(int width, int height) { OE_display::resize(width, height); } void OE_interfaceDisplay::key(int key, int scancode, int action, int mods) { const char* key_name = glfwGetKeyName(key, 0); if (!key_name) { key_name = " "; } modState = mods; if (action == GLFW_PRESS && curScreen == edit) { if (!strcmp(key_name, "z") && mods == GLFW_MOD_CONTROL) { if (controller) { controller->undoAction(); } } else if (!strcmp(key_name, "s") && mods == GLFW_MOD_CONTROL) { if (document) { document->saveToFile("../roger.oe"); } } else if (!strcmp(key_name, "o") && mods == GLFW_MOD_CONTROL) { if (document) { document->loadFromFile("../roger.oe"); } } else if (!strcmp(key_name, "z") && mods == (GLFW_MOD_CONTROL|GLFW_MOD_SHIFT)) { if (controller) { controller->redoAction(); } } else if (mods == 0) { if (!strcmp(key_name, "c")) { if (controller) { controller->toggleCloseSelectedCurve(); } } else if (!strcmp(key_name, "r")) { if (editionState == TraceSubcurve) { controller->editActionAddSubcurvePosSwitchDir(); } else if (editionState == MoveSubcurve) { controller->editActionSetSubcurvePosSwitchDir(); } } else if (key == GLFW_KEY_DELETE) { //TODO create an action to delete all selected stitches std::list::iterator it=selectedStitches.begin(); controller->addAction(new OE_actionDelStitch(*it)); } else if (key == GLFW_KEY_RIGHT) { std::list::iterator it=selectedStitches.begin(); if (it != selectedStitches.end()) { it = find (document->stitchs.begin(), document->stitchs.end(), *it); it++; if (it != selectedStitches.end()) { selectedStitches.clear(); selectedStitches.push_back(*it); controller->clearSelection(); controller->selectStitches(selectedStitches,true); } } } } } if (action == GLFW_RELEASE) { if (curScreen == command && key == GLFW_KEY_SPACE) { run=true; } if (key == GLFW_KEY_F5) { if (curScreen == edit) { curScreen = command; setDisplayStyle(commandStyle); } else { curScreen = edit; setDisplayStyle(editStyle); } } else if (!strcmp(key_name, "l")) { if (controller) { controller->newLineStitch(2.5, 2.5, controller->getPattern(0)); document->selectedStitchs.push_back(controller->getLineStitch(-1)); curJoincurve = controller->getLineStitch(-1)->getJoincurve(); closestCurve = controller->getClosestCurve(absMouse, editClosestPoint); editionState = NewSubcurve; joincurve_id = 0; } } else if (!strcmp(key_name, "b")) { if (controller) { controller->newBirailStitch(false, false, 0,0,0.7); document->selectedStitchs.push_back(controller->getBirailStitch(-1)); curJoincurve = controller->getBirailStitch(-1)->getJoincurve1(); closestCurve = controller->getClosestCurve(absMouse, editClosestPoint); editionState = NewSubcurve; joincurve_id = 1; } } else if (!strcmp(key_name, "f")) { if (controller) { controller->newFillStitch(50,50,controller->getPattern(0)); document->selectedStitchs.push_back(controller->getFillStitch(-1)); curJoincurve = controller->getFillStitch(-1)->getJoincurve(); closestCurve = controller->getClosestCurve(absMouse, editClosestPoint); editionState = NewSubcurve; joincurve_id = 0; } } else if (key == GLFW_KEY_ENTER) { if (editionState == NewSubcurve) { if (joincurve_id == 0) { editionState = None; curJoincurve = 0; } else { curJoincurve = controller->getBirailStitch(-1)->getJoincurve2(); closestCurve = controller->getClosestCurve(absMouse, editClosestPoint); joincurve_id -= 1; } } } else if (!strcmp(key_name, "r")) { if (editionState == TraceSubcurve) { controller->editActionAddSubcurvePosSwitchDir(); } else if (editionState == MoveSubcurve) { controller->editActionSetSubcurvePosSwitchDir(); } } else if (key == GLFW_KEY_KP_ADD) { if (mods == GLFW_MOD_CONTROL) { controller->addAction(new OE_actionScaleSelectedLineStitchLen(1.1)); controller->addAction(new OE_actionScaleSelectedBirailStitchLen(1.1)); } else { controller->addAction(new OE_actionScaleSelectedLineStitchWidth(1.1)); } } else if (key == GLFW_KEY_KP_SUBTRACT) { if (mods == GLFW_MOD_CONTROL) { controller->addAction(new OE_actionScaleSelectedLineStitchLen(1/1.1)); controller->addAction(new OE_actionScaleSelectedBirailStitchLen(1/1.1)); } else { controller->addAction(new OE_actionScaleSelectedLineStitchWidth(1/1.1)); } } else if (key == GLFW_KEY_KP_1) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(0))); } else if (key == GLFW_KEY_KP_2) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(1))); } else if (key == GLFW_KEY_KP_3) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(2))); } else if (key == GLFW_KEY_KP_4) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(3))); } else if (key == GLFW_KEY_KP_5) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(4))); } else if (key == GLFW_KEY_KP_6) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(5))); } else if (key == GLFW_KEY_KP_7) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(6))); } else if (key == GLFW_KEY_KP_8) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(7))); } else if (key == GLFW_KEY_KP_9) { controller->addAction(new OE_actionSetSelectedLineStitchPattern(controller->getPattern(8))); } if (key == GLFW_KEY_HOME) { zoomSelection(); } } //OE_display::key( key, scancode, action, mods); } bool OE_interfaceDisplay::selectBox() { selectedCurves.clear(); selectedStitches.clear(); vector_2d clicAbsMouse = viewPos+(clicOldMouse-vector_2d(width,height)/2)*zoom*2; float tmpXMin, tmpYMin, tmpXMax, tmpYMax; std::list::iterator curve = document->curves.begin(); while (curve != document->curves.end()) { BoundingBox box = (*curve)->getBound(); if ((box.getMin().x>minf(clicAbsMouse.x,absMouse.x)) &&(box.getMax().xminf(clicAbsMouse.y,absMouse.y)) &&(box.getMax().y::iterator stitch = document->stitchs.begin(); while (stitch != document->stitchs.end()) { BoundingBox box = (*stitch)->getBound(); if ((box.getMin().x>minf(clicAbsMouse.x,absMouse.x)) &&(box.getMax().xminf(clicAbsMouse.y,absMouse.y)) &&(box.getMax().yaddAction(new OE_actionMoveSelection(vector_2d(0,0))); } if (toolAction == 2) { editionState = ScaleSelection; return controller->addAction(new OE_actionScaleSelection(vector_2d(1,1), controller->getSelectionBoundingBox().getCenter())); } } if (selControlStitch) { OE_linestitch* tmpLineStitch = dynamic_cast(selControlStitch); if (tmpLineStitch) { if (selControlType == 0) { // get the corresponding subcurve editSubcurve = tmpLineStitch->getJoincurve()->getCurve(selControlIndex/2); if (editSubcurve) { editionState = MoveSubcurve; // get the closest point t value vector_2dt pos = editSubcurve->getCurve()->closestPoint(absMouse); // and add an action to move the point controller->addAction(new OE_actionSetSubcurvePos(editSubcurve, selControlIndex%2, pos.t)); return true; } return false; } if (selControlType == 1 && selControlIndex==0) { editionState = OffsetWidthLinestitch; controller->addAction(new OE_actionSetLineStitchWidth(tmpLineStitch, tmpLineStitch->getWidth())); return true; } } OE_birailstitch* tmpBirailStitch = dynamic_cast(selControlStitch); if (tmpBirailStitch && (selControlType == 0 || selControlType == 1)) { // get the corresponding subcurve if (selControlType == 0) { editSubcurve = tmpBirailStitch->getJoincurve1()->getCurve(selControlIndex/2); } else if (selControlType == 1) { editSubcurve = tmpBirailStitch->getJoincurve2()->getCurve(selControlIndex/2); } if (editSubcurve) { editionState = MoveSubcurve; // get the closest point t value vector_2dt pos = editSubcurve->getCurve()->closestPoint(absMouse); // and add an action to move the point controller->addAction(new OE_actionSetSubcurvePos(editSubcurve, selControlIndex%2, pos.t)); return true; } return false; } OE_linkstitch* tmpLinkStitch = dynamic_cast(selControlStitch); if (tmpLinkStitch && (selControlType == 0 || selControlType == 1 || selControlType == 2)) { if (selControlType == 0) { editionState = MovePointstitch; controller->addAction(new OE_actionMovePointLinkStitch(tmpLinkStitch, selControlIndex, vector_2d())); } else if (selControlType == 1) { editionState = MovePointstitch; controller->addAction(new OE_actionAddPointLinkStitch(tmpLinkStitch, selControlIndex, absMouse)); } else if (selControlType == 2) { editionState = DelPointstitch; controller->addAction(new OE_actionDelPointLinkStitch(tmpLinkStitch, selControlIndex)); } return false; } selControlStitch = 0; } if (selControlCurve) { OE_pointcurve* tmpPointCurve = dynamic_cast(selControlCurve); if (tmpPointCurve && selControlType == 0) { editionState = MovePointcurve; return controller->addAction(new OE_actionMovePointCurve(tmpPointCurve, selControlIndex+1, vector_2d(0,0))); } selControlCurve = 0; return true; } } /** \brief set selection * * \return true if all is ok * */ bool OE_interfaceDisplay::picking() { GLuint selectBuf[64]; GLint hits; glSelectBuffer(64, selectBuf); draw(true); hits = glRenderMode(GL_RENDER); selectedCurves.clear(); selectedStitches.clear(); toolAction = 0; GLuint i, nb_names, name, *ptr; //std::cout<<"hits : "<<"\r\n"; ptr = (GLuint *) selectBuf; for (GLuint i=0; i= document->stitchs.size()) { return false; } std::list::iterator it = document->stitchs.begin(); std::advance(it, *ptr); selectedStitches.push_back(*it); return true; } else if (names==4) //if name count correspond to a stitch sub element (like control point) { if (*ptr >= document->selectedStitchs.size()) { return false; } std::list::iterator it = document->selectedStitchs.begin(); std::advance(it, *ptr++); selControlStitch = *it; selControlType = *ptr++; selControlIndex = *ptr++; checkPicking(); return true; } } else if (*ptr == CURVESSELID) //curves picking { ptr++; if (names==2) //if name count correspond to an object (we picked a curve, not one of his sub element) { if (*ptr >= document->curves.size()) { return false; } std::list::iterator it = document->curves.begin(); std::advance(it, *ptr); selectedCurves.push_back(*it); return true; } else if (names==4) //if name count correspond to a sub element of curve (like control point) { if (*ptr >= document->selectedCurves.size()) { return false; } //in *ptr we got "curve id" then "control type" and at last "control id" std::list::iterator it = document->selectedCurves.begin(); std::advance(it, *ptr++); selControlCurve = *it; selControlType = *ptr++; selControlIndex = *ptr++; checkPicking(); return true; } } } return true; } bool OE_interfaceDisplay::selectApply(std::list selectedCurves, std::list selectedStitches) { if (selectedCurves.size()) { if (modState&GLFW_MOD_CONTROL) { controller->unselectCurves(selectedCurves); } else { controller->selectCurves(selectedCurves, !(modState&GLFW_MOD_SHIFT)); } } if (selectedStitches.size()) { if (modState&GLFW_MOD_CONTROL) { controller->unselectStitches(selectedStitches); } else { controller->selectStitches(selectedStitches, !(modState&GLFW_MOD_SHIFT)); } } if (!selectedStitches.size() && !selectedCurves.size()) { controller->clearSelection(); } return true; } /** \brief draw the document on screen * * \return true if all is ok * */ bool OE_interfaceDisplay::draw() { draw(false); } /** \brief draw the document on screen * * \return true if all is ok * */ bool OE_interfaceDisplay::draw(bool select) { if (run) { controller->sendInstPoint(); } if (select) { glRenderMode(GL_SELECT); //Init of name stack glInitNames(); glPushName(0); } float wzoom, hzoom; glViewport(0, 0, width, height); glClearColor(220.0f/255.0f, 220.0f/255.0f, 220.0f/255.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glEnd(); wzoom = (float)width*zoom; hzoom = (float)height*zoom; if (select) { glOrtho(absMouse.x-7*zoom, absMouse.x+7*zoom, absMouse.y+7*zoom, absMouse.y-7*zoom, -1, 1); } else { glOrtho(viewPos.x-wzoom, viewPos.x+wzoom, viewPos.y+hzoom, viewPos.y-hzoom, -1, 1); } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); glColor4ub(255,255,255,255); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); if (document) { if (select && (curScreen == edit)) { OE_display::select(document->selectedCurves, document->selectedStitchs); } else { OE_display::draw(); } } if (!select) { if (editionState==NewSubcurve) { // Points glPointSize(5.0f); glBegin(GL_POINTS); if (joincurve_id == 0) { glColor4d(0.8f, 0.0f, 0.0f, 1.0f); } else { glColor4d(0.0f, 0.8f, 0.0f, 1.0f); } glVertex2f(editClosestPoint.v.x,editClosestPoint.v.y); glEnd(); } // cursor cross glLineWidth(1.5); glBegin(GL_LINES); if (editionState) { if (joincurve_id == 0) { glColor4d(0.8f, 0.0f, 0.0f, 0.5f); } else { glColor4d(0.0f, 0.8f, 0.0f, 0.5f); } } else { glColor4d(0.0f, 0.0f, 0.0f, 0.3f); } glVertex2f(absMouse.x,-10000); glVertex2f(absMouse.x,10000); glVertex2f(-10000,absMouse.y); glVertex2f(10000,absMouse.y); glEnd(); //cursor select zone glLineWidth(2); glBegin(GL_LINE_LOOP); glColor4d(0.0f, 0.0f, 0.0f, 0.3f); glVertex2f(absMouse.x-5*zoom,absMouse.y+5*zoom); glVertex2f(absMouse.x-5*zoom,absMouse.y-5*zoom); glVertex2f(absMouse.x+5*zoom,absMouse.y-5*zoom); glVertex2f(absMouse.x+5*zoom,absMouse.y+5*zoom); glEnd(); if (editionState == Selection) { vector_2d clicAbsMouse = viewPos+(clicOldMouse-vector_2d(width,height)/2)*zoom*2; glLineWidth(2); glBegin(GL_LINE_STRIP); glColor4d(0.0f, 0.0f, 0.0f, 0.3f); glVertex2f(absMouse.x,clicAbsMouse.y); glVertex2f(absMouse.x,absMouse.y); glVertex2f(clicAbsMouse.x,absMouse.y); glVertex2f(clicAbsMouse.x,clicAbsMouse.y); glVertex2f(absMouse.x,clicAbsMouse.y); glEnd(); } } return true; }