void SkeletonTool::magicLink(int index) { if (index < 0 || index >= (int)m_magicLinks.size()) return; HookData h0 = m_magicLinks[index].m_h0; HookData h1 = m_magicLinks[index].m_h1; TTool::Application *app = TTool::getApplication(); TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); int columnIndex = app->getCurrentColumn()->getColumnIndex(); TStageObjectId id = TStageObjectId::ColumnId(columnIndex); TStageObject *obj = xsh->getStageObject(id); int parentColumnIndex = h1.m_columnIndex; TStageObjectId parentId = TStageObjectId::ColumnId(parentColumnIndex); std::string parentHandle = h1.getHandle(); std::string handle = ""; if (h0.m_columnIndex < 0) { handle = obj->getHandle(); } else { handle = h0.getHandle(); } //TUndoManager *undoManager = TUndoManager::manager(); //undoManager->beginBlock(); TStageObjectCmd::setHandle(id, handle, app->getCurrentXsheet()); TStageObjectCmd::setParent(id, parentId, parentHandle, app->getCurrentXsheet()); //undoManager->endBlock(); }
bool SkeletonTool::doesApply() const { TTool::Application *app = TTool::getApplication(); TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); assert(xsh); TStageObjectId objId = app->getCurrentObject()->getObjectId(); if (objId.isColumn()) { TXshColumn *column = xsh->getColumn(objId.getIndex()); if (column && column->getSoundColumn()) return false; } return true; }
TAffine TTool::getCurrentObjectParentMatrix2() const { TTool::Application *app = m_application; TFrameHandle *fh = app->getCurrentFrame(); if (fh->isEditingLevel()) return TAffine(); int frame = fh->getFrame(); TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); TStageObjectId id = app->getCurrentObject()->getObjectId(); double objZ = xsh->getZ(id, frame); TStageObjectId parentId = xsh->getStageObjectParent(id); if (parentId == TStageObjectId::NoneId) return TAffine(); id = parentId; TAffine objPlacement = xsh->getPlacement(id, frame); TStageObjectId cameraId = xsh->getStageObjectTree()->getCurrentCameraId(); TStageObject *camera = xsh->getStageObject(cameraId); TAffine cameraPlacement = camera->getPlacement(frame); double cameraZ = camera->getZ(frame); TAffine placement; TStageObject::perspective(placement, cameraPlacement, cameraZ, objPlacement, objZ, 0); return placement; }
void SkeletonTool::drawHooks() { // camera stand reference system //glColor3d(0,0,1); //tglDrawRect(3,3,97,97); //glColor3d(0,1,1); //tglDrawRect(0,100,Stage::inch,110); QTime time; time.start(); m_magicLinks.clear(); computeMagicLinks(); TTool::Application *app = TTool::getApplication(); TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); int row = app->getCurrentFrame()->getFrame(); int col = app->getCurrentColumn()->getColumnIndex(); TPointD dpiScale = getViewer()->getDpiScale(); // glColor3d(1,0,1); // tglDrawRect(-100*dpiScale.x, -100*dpiScale.y, 0,0); // I should not show hooks of columns already connected with the current one // ("linking" to those hooks would create evil loops in the hierarchy) std::set<int> connectedColumns; getConnectedColumns(connectedColumns, xsh, col); std::vector<HookData> currentColumnHooks; std::vector<HookData> otherColumnsHooks; // fill currentColumnHooks // detect otherColumn (i.e. the active column during a click&drag operator int otherColumn = -1; if (m_parentProbeEnabled) { // qDebug(" parent probe enabled"); // currentColumnHooks <- current column & current handle int hookId = 0; std::string handle = xsh->getStageObject(TStageObjectId::ColumnId(col))->getHandle(); if (handle.find("H") == 0) { int j = 1; while (j < (int)handle.size() && '0' <= handle[j] && handle[j] <= '9') { hookId = hookId * 10 + (int)handle[j] - '0'; j++; } } currentColumnHooks.push_back(HookData(xsh, col, hookId, m_parentProbe)); // otherColumn = "picked" column not connected TPoint parentProbePos = getViewer()->worldToPos(m_parentProbe); std::vector<int> indexes; getViewer()->posToColumnIndexes(parentProbePos, indexes, getPixelSize() * 10, false); for (int i = (int)indexes.size() - 1; i >= 0; i--) { if (connectedColumns.count(indexes[i]) == 0) { otherColumn = indexes[i]; break; } } // if the mouse is not on a stroke, I'm using the "old" m_otherColumn, if any. // (this is needed because of the hooks put inside of unfilled regions) if (otherColumn < 0 && m_otherColumn >= 0) { if (m_otherColumnBBox.contains(m_otherColumnBBoxAff.inv() * m_parentProbe)) otherColumn = m_otherColumn; else m_otherColumn = -1; } } else { // parent probe not enabled: get all hooks of current column. other column = -1 getHooks(currentColumnHooks, xsh, row, col, TPointD(1, 1)); // dpiScale); } // other columns hooks <- all hooks of all unlinked columns for (int i = 0; i < xsh->getColumnCount(); i++) if (xsh->getColumn(i)->isCamstandVisible()) if (connectedColumns.count(i) == 0) getHooks(otherColumnsHooks, xsh, row, i, TPointD(1, 1)); // dpiScale); /* qDebug(" time=%dms", time.elapsed()); qDebug(" %d hooks (current column)", currentColumnHooks.size()); for(int i=0;i<(int)currentColumnHooks.size();i++) qDebug(" %d,%d",currentColumnHooks[i].m_columnIndex,currentColumnHooks[i].m_hookId); qDebug(" %d hooks (other columns)", otherColumnsHooks.size()); for(int i=0;i<(int)otherColumnsHooks.size();i++) qDebug(" %d,%d",otherColumnsHooks[i].m_columnIndex,otherColumnsHooks[i].m_hookId); */ std::vector<TRectD> balloons; // draw current column hooks for (int i = 0; i < (int)currentColumnHooks.size(); i++) { const HookData &hook = currentColumnHooks[i]; if (hook.m_name == "") continue; // should not happen int code = TD_Hook + hook.m_hookId; TPointD pos = hook.m_pos; ToolUtils::drawHook(pos, ToolUtils::OtherLevelHook); glPushName(code); TPixel32 color(200, 220, 205, 200); if (hook.m_isPivot) color = TPixel32(200, 200, 10, 200); else if (code == m_device) color = TPixel32(185, 255, 255); ToolUtils::drawBalloon(pos, hook.m_name, color, TPoint(20, 20), isPicking(), &balloons); glPopName(); } if (m_parentProbeEnabled) { for (int i = 0; i < (int)otherColumnsHooks.size(); i++) ToolUtils::drawHook(otherColumnsHooks[i].m_pos, ToolUtils::OtherLevelHook); } // search for magic links double minDist2 = 0; double snapRadius2 = 100 * getPixelSize() * getPixelSize(); double snapRadius2bis = 100; if (!m_parentProbeEnabled) { // "static" magic links: no parent probe for (int i = 0; i < (int)currentColumnHooks.size(); i++) { for (int j = 0; j < (int)otherColumnsHooks.size(); j++) { double dist2 = norm2(currentColumnHooks[i].m_pos - otherColumnsHooks[j].m_pos); if (currentColumnHooks[i].m_hookId == 0 || otherColumnsHooks[j].m_hookId == 0) continue; if (dist2 < snapRadius2bis) { m_magicLinks.push_back(MagicLink(currentColumnHooks[i], otherColumnsHooks[j], dist2)); qDebug(" magic link_a %d (%d,%d) %d (%d,%d); dist=%f", i, currentColumnHooks[i].m_columnIndex, currentColumnHooks[i].m_hookId, j, otherColumnsHooks[j].m_columnIndex, otherColumnsHooks[j].m_hookId, dist2); } } } } if (m_parentProbeEnabled) { // search for the closest hook of the picked column int i = -1, j = -1; double minDist2 = snapRadius2; for (i = 0; i < (int)otherColumnsHooks.size(); i++) { double dist2 = tdistance2(otherColumnsHooks[i].m_pos, m_parentProbe); if (dist2 < minDist2) { j = i; minDist2 = dist2; otherColumn = otherColumnsHooks[i].m_columnIndex; } } } if (m_parentProbeEnabled && otherColumn >= 0) // && m_magicLinks.empty() { // "dynamic" magic links: probing and picking a column // show image bounding box m_otherColumn = otherColumn; getImageBoundingBox(m_otherColumnBBox, m_otherColumnBBoxAff, row, otherColumn); if (!m_otherColumnBBox.isEmpty()) { glPushMatrix(); tglMultMatrix(m_otherColumnBBoxAff); ToolUtils::drawRect(m_otherColumnBBox, TPixel32(188, 202, 191), 0xF0F0); //tglDrawRect(img->getBBox()); glPopMatrix(); } /* TXshCell cell = xsh->getCell(row, otherColumn); //TAffine aff = xsh->getPlacement(TStageObjectId::ColumnId(otherColumn),row); //m_otherColumnAff = aff; TImageP img = cell.getImage(false); if(img) { getImageBoundingBox(m_otherColumnBBox, m_otherColumnBBoxAff, row, otherColumn); //glColor3d(188.0/255.0, 202.0/255.0, 191.0/255.0); glPushMatrix(); tglMultMatrix(aff * imageDpiAff); ToolUtils::drawRect(img->getBBox(), TPixel32(188,202,191), 0xF0F0); //tglDrawRect(img->getBBox()); glPopMatrix(); } */ // search for the closest hook of the picked column int i = -1, j = -1; double minDist2 = snapRadius2; for (i = 0; i < (int)otherColumnsHooks.size(); i++) if (otherColumnsHooks[i].m_columnIndex == otherColumn) { double dist2 = tdistance2(otherColumnsHooks[i].m_pos, m_parentProbe); if (j < 0) j = i; else if (dist2 < minDist2 || otherColumnsHooks[i].m_hookId == 0) { j = i; minDist2 = dist2; } } // visualize a balloon for the closest hook if (0 <= j && j < (int)otherColumnsHooks.size()) { // I want to get a specific color when overlaying the label on white int alfa = 100, ialfa = 255 - alfa; TPixel32 color(255 * (188 - ialfa) / alfa, 255 * (202 - ialfa) / alfa, 255 * (191 - ialfa) / alfa, alfa); ToolUtils::drawBalloon( otherColumnsHooks[j].m_pos, otherColumnsHooks[j].m_name, // getHandle(), color, TPoint(20, 20), false, &balloons); HookData baseHook = currentColumnHooks[0]; baseHook.m_pos = otherColumnsHooks[j].m_pos; // this is also a magic link m_magicLinks.push_back(MagicLink(baseHook, otherColumnsHooks[j], 10000)); } } // visualize all the magic links for (int i = 0; i < (int)m_magicLinks.size(); i++) { const MagicLink &magicLink = m_magicLinks[i]; const HookData &h1 = magicLink.m_h1; std::string name; name = (m_parentProbeEnabled ? "Linking " : "Link ") + removeTrailingH(magicLink.m_h0.getHandle()) + " to Col " + std::to_string(h1.m_columnIndex + 1) + "/" + removeTrailingH(h1.getHandle()); int code = TD_MagicLink + i; glPushName(code); TPixel32 color(100, 255, 100, 100); if (code == m_device) color = TPixel32(185, 255, 255); ToolUtils::drawBalloon(magicLink.m_h0.m_pos, name, color, TPoint(20, -20), isPicking(), &balloons); glPopName(); } }
void SkeletonTool::leftButtonDown(const TPointD &ppos, const TMouseEvent &e) { m_otherColumn = -1; m_otherColumnBBox = TRectD(); m_otherColumnBBoxAff = TAffine(); m_labelPos = TPointD(0, 0); m_label = ""; TUndoManager::manager()->beginBlock(); if (!doesApply()) return; assert(m_dragTool == 0); m_dragTool = 0; TTool::Application *app = TTool::getApplication(); int currentColumnIndex = app->getCurrentColumn()->getColumnIndex(); TXsheet *xsh = app->getCurrentScene()->getScene()->getXsheet(); TPointD pos = ppos; int selectedDevice = pick(e.m_pos); // cambio drawing if (selectedDevice == TD_ChangeDrawing || selectedDevice == TD_IncrementDrawing || selectedDevice == TD_DecrementDrawing) { int d = 0; if (selectedDevice == TD_IncrementDrawing) d = 1; else if (selectedDevice == TD_DecrementDrawing) d = -1; m_dragTool = new ChangeDrawingTool(this, d); m_dragTool->leftButtonDown(ppos, e); return; } // click su un hook: attacca la colonna corrente tramite quell'hook if (TD_Hook <= selectedDevice && selectedDevice < TD_Hook + 50) { TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); TStageObjectId objId = TStageObjectId::ColumnId(currentColumnIndex); TPointD p0 = getCurrentColumnMatrix() * TPointD(0, 0); HookData hook(xsh, currentColumnIndex, selectedDevice - TD_Hook, p0); TStageObjectCmd::setHandle(objId, hook.getHandle(), app->getCurrentXsheet()); app->getCurrentXsheet()->notifyXsheetChanged(); invalidate(); return; } // magic link if (TD_MagicLink <= selectedDevice && selectedDevice < TD_MagicLink + (int)m_magicLinks.size()) { magicLink(selectedDevice - TD_MagicLink); app->getCurrentXsheet()->notifyXsheetChanged(); return; } m_device = selectedDevice; bool justSelected = false; if (m_device < 0) { // nessun gadget cliccato. Eventualmente seleziono la colonna std::vector<int> columnIndexes; getViewer()->posToColumnIndexes(e.m_pos, columnIndexes, getPixelSize() * 5, false); if (!columnIndexes.empty()) { int columnIndex; columnIndex = columnIndexes.back(); if (columnIndex >= 0 && columnIndex != currentColumnIndex) { if (!isColumnLocked(columnIndex)) { pos = getMatrix() * pos; app->getCurrentColumn()->setColumnIndex(columnIndex); updateMatrix(); currentColumnIndex = columnIndex; justSelected = true; pos = getMatrix().inv() * pos; } else { m_label = "Column is locked"; m_labelPos = pos; } } } } if (m_device < 0) { if (m_mode.getValue() == INVERSE_KINEMATICS) m_device = TD_InverseKinematics; else if (m_mode.getValue() == ANIMATE) m_device = TD_Rotation; } // lock/unlock: modalita IK if (TD_LockStageObject <= m_device && m_device < TD_LockStageObject + 1000) { int columnIndex = m_device - TD_LockStageObject; int frame = app->getCurrentFrame()->getFrame(); togglePinnedStatus(columnIndex, frame, e.isShiftPressed()); invalidate(); m_dragTool = 0; return; } switch (m_device) { case TD_Center: m_dragTool = new DragCenterTool(this); break; case TD_Translation: m_dragTool = new DragPositionTool(this); break; case TD_Rotation: m_dragTool = new DragRotationTool(this, justSelected); break; case TD_ChangeParent: m_dragTool = new ParentChangeTool(this, getViewer()); break; case TD_InverseKinematics: { Skeleton *skeleton = new Skeleton(); buildSkeleton(*skeleton, currentColumnIndex); m_dragTool = new IKTool(this, getViewer(), skeleton, currentColumnIndex); break; } } if (m_dragTool) { m_dragTool->leftButtonDown(pos, e); invalidate(); } }