Every mouse controller should implement the interface MouseHandler to work with the cg3DMetaManipulator.
But for the Shape Manipulator (every controller which manipulates shape), it's probably easier to directly extend the class cg3DAbstractManipulator.
Indeed, cg3DAbstractManipulator already implements a lot of really useful functionality to manipulate shape.
The principal variables you will need to use from this class are:
Point2d _p1 : the position of the mouse cursor when you press the the left button.
Point2d _p2 : the current position of the mouse cursor (only if the left button is still pressed).
cgJOGLMovableShapeNode _shapeToMove : the actual selected shape you want to move.
Point3d _shapePosition : the position of shapeToMove.
cgJOGLCompositeNode<cgNode> _rootnode : the rootnode of the view.
cgJOGL3DView _view : the 3D view.
Before I get into the main topic, you will have to implement three necessary functions:
unSelect(): is use to remove all the control points of the selected shape in the rootnode.
AddPointController(cgJOGLMovableShapeNode shapeSelected): is use to add all the control points of the selected shape in the rootnode.
updatePointRender(): Update the render of the control points.
Sample Code
@Override
public void unSelect(){
//get all control points of the selected shape
cgJOGL3DSimpleControlPoints[] points=selectControlPoints();
if(points!=null){
for (int i = 0; i < points.length; i++) {
//remove them to the root node.
_rootnode.removeNode(points[i].getControlledNode());
}
}
}
Sample Code
@Override
public void AddPointController(cgJOGLMovableShapeNode shapeSelected){
cgJOGL3DSimpleControlPoints[] points;
//verify if the selected shape is an cgJOGLEditableShapeNode (replace this class by the class you wanna manipulate)
if( shapeSelected instanceof cgJOGLEditableShapeNode){
//get all the controls point of the selected shape;
points=((cgJOGLEditableShapeNode) shapeSelected).getAll3DControlPoints();
if(points!=null){
for (int i = 0; i < points.length; i++) {
//add control points
_rootnode.addNode(points[i].getControlledNode());
}
//define which control point need to be show or hide
((cgJOGLEditableShapeNode) shapeSelected).updateOfVisiblePoint(4);
}
}
}
Sample Code
@Override
public void updatePointRender(){
//get all control points of the selected shape
cgJOGL3DSimpleControlPoints[] points=selectControlPoints();
//get the model matrix
Matrix4d model=_view.getModelMatrix();
Point3d origin;
//get the translate transformation of the model without his scale.
origin=new Point3d(-model.getM03()/model.getM00(),
-model.getM13()/model.getM11(),
-model.getM23()/model.getM22());
if(points!=null) {
for (int i = 0; i < points.length; i++) {
//define the size of the control points (radius if sphere)
unScaleController(points[i],origin,model);
}
}
}
Here a general example: how to pick a global shape object and display its control points.
Sample Code
@Override
public boolean mouseClicked(MouseEvent e) {
if (e.getClickCount() == 1) {
//pick the shape under the cursor when we pressed a button of the mouse.
cgJOGLSelectionResult[] results = _view.pick((int)_p1.x,(int)_p1.y, 2);
//if we pick nothing
if (results == null || results.length < 1) {
if(_shapeToMove!=null){
//UnSelect the shape
unSelect();
}
//Reset _shapeToMove
_shapeToMove=null;
//finish.
return false;
}
cgJOGLMovableShapeNode shapeSelected;
// verify if the picked object is movable
if(results[0].getSelectionPath().getBottomNode() instanceof cgJOGLMovableShapeNode){
shapeSelected=(cgJOGLMovableShapeNode) results[0].getSelectionPath().getBottomNode();
// here you can replace cgJOGLGlobalShape by every other subclass of cgJOGLGlobalShape which represent the object you wanna manipulate.
if ((shapeSelected instanceof cgJOGLGlobalShape)){
//unselect the previous shape and hide his control points associate.
unSelect();
//display control points of the current selected shape
AddPointController(shapeSelected);
// set our picked shape as the selected shape.
_shapeToMove=shapeSelected;
// update the render of the control point.
updatePointRender();
}
//if the picked shape is a control point ( replace cgJOGL3DControlPoints by the class which is the control point of your object)
if((shapeSelected instanceof cgJOGL3DControlPoints)){
//set the owner of this control point as the shape selected
_shapeToMove=((cgJOGL3DControlPoints)shapeSelected).getParentShape();
// update the render of the control point. Here we don't unselect and add controll point because, if it was able to pick a control point, it's mean the shape selected is still the same object.
updatePointRender();
}
}
}
return false;
}
A general example to move a shape by dragging it with your mouse.
First, let's have a look at the mousePressed function.
Sample Code
@Override//
public boolean mousePressed(MouseEvent e) {
// A boolean to know if the controller will be used, or if it will let the lead to other controlleurs
_mouseOnShape=false;
// A boolean to know if the mouse is press with the left button
_leftMouse=(e.getButton()==MouseEvent.BUTTON1);
// save the position where the mouse was pressed
_p1.x = e.getX();
// Height-y because in JOGL origin is in the bottom left.
_p1.y = _view.getViewComponent().getHeight() - e.getY();
//pick the shape under the mouse cursor.
cgJOGLSelectionResult[] results = _view.pick((int)_p1.x,(int)_p1.y, 2);
//if we pick something and pressed the left button.
if (_leftMouse&&!(results == null || results.length < 1)) {
cgJOGLMovableShapeNode shapeSelected;
// verify if the picked object is movable
if(results[0].getSelectionPath().getBottomNode() instanceof cgJOGLMovableShapeNode){
shapeSelected=(cgJOGLMovableShapeNode) results[0].getSelectionPath().getBottomNode();
//if shapeSelected is not an other GlobalShape, shapeSelected become the _shapeToMove
_mouseOnShape=shapeSelected==_shapeToMove;
if (shapeSelected instanceof cgJOGL3DControlPoints){
_mouseOnShape=true;
_shapeToMove=shapeSelected;
}
//if _shapeToMove is a control point of shapeSelected, shapeSelected become the _shapeToMove
else if (_shapeToMove instanceof cgJOGL3DControlPoints){
if(((cgJOGL3DControlPoints)_shapeToMove).getParentShape().equals(shapeSelected)){
_mouseOnShape=true;
_shapeToMove=shapeSelected;
}
//else we keep the same _shapeToMove as before and let the lead to other controller.
}
}
}
if(_shapeToMove!=null){
_shapePosition=_shapeToMove.getPosition();
}
//if _mouseOnShape is true, only this controller will be used, else we let the lead to an other controller.
return _mouseOnShape;
}
Now, let see what happens in mouseDragged.
Sample Code
@Override
public boolean mouseDragged(MouseEvent e) {
//boolean to know if mouseDragged in our controller will be use.
boolean isUse=false;
//if we have already selected a shape and if the mouse was on our selected shape when we pressed the button.
if(_shapeToMove!=null&&_mouseOnShape){
//if the button we press was the left button
if (_leftMouse){
//pick the shape under the mouse cursor.
_p2.x = e.getX();
_p2.y = _view.getViewComponent().getHeight() - e.getY();
//and move our selected shape to this new position (cg3DAbstractManipulator functionality).
_shapeToMove.setPosition(definePosition(_shapePosition));
isUse=true;
}
// update the render of the control point.
updatePointRender();
}
return isUse;
}
A general example to resize control points when the user zooms in and out. Moreover, this function set is visible only to useful control points.
Sample Code
@Override
public boolean mouseWheelMoved(MouseWheelEvent e) {
//if we have a selected shape and we rotate the mouse wheel
if( e.getWheelRotation() != 0 && _shapeToMove!=null){
// update the render of the control point.
updatePointRender();
//select global shape selected
cgJOGLEditableShapeNode selectedEditShape=selectEditShape();
if(selectedEditShape!=null){
//set visible only useful control points
selectedEditShape.updateOfVisiblePoint(4);
}
}
//let other controller in the meta controller access to their mouseWheelMoved funtion
return false;
}
The _shapeToMove variable can be a global shape or a control points. That is why we need to be sure to select all the control points of the global function, or the global function itself.
Example of a function to select all the control points:
Sample Code
public cgJOGL3DControlPoints[] selectControlPoints(){
cgJOGL3DControlPoints[] points=null;
//if the _shapeToMove is a control points
if( _shapeToMove instanceof cgJOGL3DControlPoints){
//if the parent of _shapeToMove is an editable shape
if(((cgJOGL3DControlPoints) _shapeToMove).getParentShape() instanceof cgJOGLEditableShapeNode){
//select the parent of shapeToMove, and then select all the control points.
points=((cgJOGLEditableShapeNode)
((cgJOGL3DControlPoints) _shapeToMove).getParentShape()
).getAll3DControlPoints();
}
}
//if _shapeToMove is a global shape
if( _shapeToMove instanceof cgJOGLEditableShapeNode){
//select all the control points of shapeToMove
points=((cgJOGLEditableShapeNode) _shapeToMove).getAll3DControlPoints();
}
return points;
}
Example of a function to select the editable shape:
Sample Code
public cgJOGLEditableShapeNode selectEditShape(){
cgJOGLEditableShapeNode shape=null;
//if the _shapeToMove is a control points
if( _shapeToMove instanceof cgJOGL3DControlPoints){
//if the parent of _shapeToMove is an editable shape
if(((cgJOGL3DControlPoints) _shapeToMove).getParentShape() instanceof cgJOGLEditableShapeNode){
//select the parent of shapeToMove
shape=(cgJOGLEditableShapeNode) ((cgJOGL3DControlPoints) _shapeToMove).getParentShape();
}
}
//if _shapeToMove is a global shape
if( _shapeToMove instanceof cgJOGLEditableShapeNode){
//select _shapeToMove itself
shape=((cgJOGLEditableShapeNode) _shapeToMove);
}
return shape;
}