const lib::vector2ds32 negatedDirectionVector(const lib::u32 scale = 1) const { lib::vector2ds32 result{ directionVector(scale) }; result *= (lib::s32) - 1; return result; }
float scoreForWidget(GuiWidget const &widget, ui::Direction dir) const { if (!widget.canBeFocused() || &widget == thisPublic) { return -1; } Rectanglef const viewRect = self().root().viewRule().rect(); Rectanglef const selfRect = self().hitRule().rect(); Rectanglef const otherRect = widget.hitRule().rect(); Vector2f const otherMiddle = (dir == ui::Up? otherRect.midBottom() : dir == ui::Down? otherRect.midTop() : dir == ui::Left? otherRect.midRight() : otherRect.midLeft() ); //otherRect.middle(); if (!viewRect.contains(otherMiddle)) { return -1; } bool const axisOverlap = (isHorizontal(dir) && !selfRect.vertical() .intersection(otherRect.vertical()) .isEmpty()) || (isVertical(dir) && !selfRect.horizontal().intersection(otherRect.horizontal()).isEmpty()); // Check for contacting edges. float edgeDistance = 0; // valid only if axisOverlap if (axisOverlap) { switch (dir) { case ui::Left: edgeDistance = selfRect.left() - otherRect.right(); break; case ui::Up: edgeDistance = selfRect.top() - otherRect.bottom(); break; case ui::Right: edgeDistance = otherRect.left() - selfRect.right(); break; default: edgeDistance = otherRect.top() - selfRect.bottom(); break; } // Very close edges are considered contacting. if (edgeDistance >= 0 && edgeDistance < toDevicePixels(5)) { return edgeDistance; } } Vector2f const middle = (dir == ui::Up? selfRect.midTop() : dir == ui::Down? selfRect.midBottom() : dir == ui::Left? selfRect.midLeft() : selfRect.midRight() ); Vector2f const delta = otherMiddle - middle; Vector2f const dirVector = directionVector(dir); auto dotProd = delta.normalize().dot(dirVector); if (dotProd <= 0) { // On the wrong side. return -1; } float distance = delta.length(); if (axisOverlap) { dotProd = 1.0; if (edgeDistance > 0) { distance = de::min(distance, edgeDistance); } } float favorability = 1; if (widget.parentWidget() == self().parentWidget()) { favorability = .1f; // Siblings are much preferred. } else if (self().hasAncestor(widget) || widget.hasAncestor(self())) { favorability = .2f; // Ancestry is also good. } // Prefer widgets that are nearby, particularly in the specified direction. return distance * (.5f + acos(dotProd)) * favorability; }
lib::vector2du32 applyToVector(const lib::vector2du32 &v,const lib::u32 scale = 1) const { lib::vector2ds32 dv{ directionVector(scale) }; lib::vector2du32 result(v.x + dv.x, v.y + dv.y); return result; }
MStatus sweptEmitter::compute(const MPlug& plug, MDataBlock& block) // // Descriptions: // Call emit emit method to generate new particles. // { MStatus status; // Determine if we are requesting the output plug for this emitter node. // if( !(plug == mOutput) ) return( MS::kUnknownParameter ); // Get the logical index of the element this plug refers to, // because the node can be emitting particles into more // than one particle shape. // int multiIndex = plug.logicalIndex( &status ); McheckErr(status, "ERROR in plug.logicalIndex.\n"); // Get output data arrays (position, velocity, or parentId) // that the particle shape is holding from the previous frame. // MArrayDataHandle hOutArray = block.outputArrayValue(mOutput, &status); McheckErr(status, "ERROR in hOutArray = block.outputArrayValue.\n"); // Create a builder to aid in the array construction efficiently. // MArrayDataBuilder bOutArray = hOutArray.builder( &status ); McheckErr(status, "ERROR in bOutArray = hOutArray.builder.\n"); // Get the appropriate data array that is being currently evaluated. // MDataHandle hOut = bOutArray.addElement(multiIndex, &status); McheckErr(status, "ERROR in hOut = bOutArray.addElement.\n"); // Get the data and apply the function set. // MFnArrayAttrsData fnOutput; MObject dOutput = fnOutput.create ( &status ); McheckErr(status, "ERROR in fnOutput.create.\n"); // Check if the particle object has reached it's maximum, // hence is full. If it is full then just return with zero particles. // bool beenFull = isFullValue( multiIndex, block ); if( beenFull ) { return( MS::kSuccess ); } // Get deltaTime, currentTime and startTime. // If deltaTime <= 0.0, or currentTime <= startTime, // do not emit new pariticles and return. // MTime cT = currentTimeValue( block ); MTime sT = startTimeValue( multiIndex, block ); MTime dT = deltaTimeValue( multiIndex, block ); if( (cT <= sT) || (dT <= 0.0) ) { // We do not emit particles before the start time, // and do not emit particles when moving backwards in time. // // This code is necessary primarily the first time to // establish the new data arrays allocated, and since we have // already set the data array to length zero it does // not generate any new particles. // hOut.set( dOutput ); block.setClean( plug ); return( MS::kSuccess ); } // Get speed, direction vector, and inheritFactor attributes. // double speed = speedValue( block ); MVector dirV = directionVector( block ); double inheritFactor = inheritFactorValue( multiIndex, block ); // Get the position and velocity arrays to append new particle data. // MVectorArray fnOutPos = fnOutput.vectorArray("position", &status); MVectorArray fnOutVel = fnOutput.vectorArray("velocity", &status); // Convert deltaTime into seconds. // double dt = dT.as( MTime::kSeconds ); // Apply rotation to the direction vector MVector rotatedV = useRotation ( dirV ); // position, MVectorArray inPosAry; // velocity MVectorArray inVelAry; // emission rate MIntArray emitCountPP; // Get the swept geometry data // MObject thisObj = this->thisMObject(); MPlug sweptPlug( thisObj, mSweptGeometry ); if ( sweptPlug.isConnected() ) { MDataHandle sweptHandle = block.inputValue( mSweptGeometry ); // MObject sweptData = sweptHandle.asSweptGeometry(); MObject sweptData = sweptHandle.data(); MFnDynSweptGeometryData fnSweptData( sweptData ); // Curve emission // if (fnSweptData.lineCount() > 0) { int numLines = fnSweptData.lineCount(); for ( int i=0; i<numLines; i++ ) { inPosAry.clear(); inVelAry.clear(); emitCountPP.clear(); MDynSweptLine line = fnSweptData.sweptLine( i ); // ... process current line ... MVector p1 = line.vertex( 0 ); MVector p2 = line.vertex( 1 ); inPosAry.append( p1 ); inPosAry.append( p2 ); inVelAry.append( MVector( 0,0,0 ) ); inVelAry.append( MVector( 0,0,0 ) ); // emit Rate for two points on line emitCountPP.clear(); status = emitCountPerPoint( plug, block, 2, emitCountPP ); emit( inPosAry, inVelAry, emitCountPP, dt, speed, inheritFactor, rotatedV, fnOutPos, fnOutVel ); } } // Surface emission (nurb or polygon) // if (fnSweptData.triangleCount() > 0) { int numTriangles = fnSweptData.triangleCount(); for ( int i=0; i<numTriangles; i++ ) { inPosAry.clear(); inVelAry.clear(); emitCountPP.clear(); MDynSweptTriangle tri = fnSweptData.sweptTriangle( i ); // ... process current triangle ... MVector p1 = tri.vertex( 0 ); MVector p2 = tri.vertex( 1 ); MVector p3 = tri.vertex( 2 ); MVector center = p1 + p2 + p3; center /= 3.0; inPosAry.append( center ); inVelAry.append( MVector( 0,0,0 ) ); // emit Rate for two points on line emitCountPP.clear(); status = emitCountPerPoint( plug, block, 1, emitCountPP ); emit( inPosAry, inVelAry, emitCountPP, dt, speed, inheritFactor, rotatedV, fnOutPos, fnOutVel ); } } } // Update the data block with new dOutput and set plug clean. // hOut.set( dOutput ); block.setClean( plug ); return( MS::kSuccess ); }