f@0: /* f@0: XYPad - a haptic xy-pad that uses the jHapticGUI library f@0: f@0: Copyright (C) 2015 Queen Mary University of London (http://depic.eecs.qmul.ac.uk/) f@0: f@0: This program is free software: you can redistribute it and/or modify f@0: it under the terms of the GNU General Public License as published by f@0: the Free Software Foundation, either version 3 of the License, or f@0: (at your option) any later version. f@0: f@0: This program is distributed in the hope that it will be useful, f@0: but WITHOUT ANY WARRANTY; without even the implied warranty of f@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the f@0: GNU General Public License for more details. f@0: f@0: You should have received a copy of the GNU General Public License f@0: along with this program. If not, see . f@0: */ f@0: #include "XYScene.h" f@0: f@0: #include f@0: #include f@0: f@0: #include f@0: #include f@0: #include f@0: f@0: #include f@0: f@0: jhapticgui::XYScene::XYScene(void(*messageCallback) (const Message & m)) : HapticScene(messageCallback) {} f@0: f@0: jhapticgui::XYScene::~XYScene() {} f@0: f@0: bool jhapticgui::XYScene::initHaptics(void){ f@0: /* init haptic device */ f@0: HHD hHD = hdInitDevice(HD_DEFAULT_DEVICE); f@0: if (HD_DEVICE_ERROR(hdGetError())) { f@0: /* if unsuccessful return false */ f@0: return false; f@0: } f@0: f@0: /* create haptic context */ f@0: HHLRC hHLRC = hlCreateContext(hHD); f@0: hlMakeCurrent(hHLRC); f@0: f@0: /* Reserve an id for the shape */ f@0: shapeID = hlGenShapes(1); f@0: f@0: f@0: /* initialize the haptic space */ f@0: hlMatrixMode(HL_TOUCHWORKSPACE); f@0: hlLoadIdentity(); f@0: hlOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); f@0: f@0: /* install event callbacks for touch and motion */ f@0: hlAddEventCallback(HL_EVENT_TOUCH, HL_OBJECT_ANY, HL_CLIENT_THREAD, checkContact, this); f@0: hlAddEventCallback(HL_EVENT_UNTOUCH, HL_OBJECT_ANY, HL_CLIENT_THREAD, checkContact, this); f@0: hlAddEventCallback(HL_EVENT_MOTION, HL_OBJECT_ANY, HL_CLIENT_THREAD, checkMotion, this); f@0: f@0: /* initialization successful */ f@0: return true; f@0: } f@0: f@0: void jhapticgui::XYScene::initGL(void){ f@0: glClearColor(0.0, 0.0, 0.0, 0.0); f@0: glMatrixMode(GL_PROJECTION); f@0: glLoadIdentity(); f@0: glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); f@0: f@0: glDepthFunc(GL_LEQUAL); f@0: glEnable(GL_DEPTH_TEST); f@0: } f@0: f@0: f@0: unsigned int jhapticgui::XYScene::processMessage(const Message & m){ f@0: /* there is only one type of message coming from the java * f@0: * but the check is performed nevertheless for clarity */ f@0: if (!strcmp(m.command, "change")) { f@0: f@0: /* the command selects the shape to display here all is done * f@0: * is just a variable update. The variable new value will be * f@0: * read in the next cycle of drawScene */ f@0: if (!strcmp(m.args, "circle")){ f@0: shape = Shape::CIRCLE; f@0: } f@0: else if(!strcmp(m.args, "square")){ f@0: shape = Shape::SQUARE; f@0: } f@0: } f@0: f@0: /* message updates not used, just return any value */ f@0: return 0; f@0: } f@0: f@0: void jhapticgui::XYScene::beginFrame(void){ f@0: hlBeginFrame(); f@0: } f@0: f@0: void jhapticgui::XYScene::endFrame(void){ f@0: hlEndFrame(); f@0: } f@0: f@0: void jhapticgui::XYScene::drawCursor(void){ f@0: /* no cursor drawn */ f@0: } f@0: f@0: void jhapticgui::XYScene::drawScene(unsigned int messageUpdate, unsigned int callbacksUpdate){ f@0: f@0: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); f@0: glColor3f(1.0, 200.0/255.0, 0.0); f@0: f@0: hlBeginShape(HL_SHAPE_DEPTH_BUFFER, shapeID); f@0: f@0: /* use shape variable to determine which shape to draw */ f@0: if (shape == Shape::SQUARE){ f@0: glBegin(GL_POLYGON); f@0: glVertex3f(-RADIUS, -RADIUS, 0.0); f@0: glVertex3f(RADIUS, -RADIUS, 0.0); f@0: glVertex3f(RADIUS, RADIUS, 0.0); f@0: glVertex3f(-RADIUS, RADIUS, 0.0); f@0: glEnd(); f@0: } f@0: else { // CIRCLE f@0: glutSolidSphere(RADIUS, 64, 64); f@0: } f@0: f@0: hlEndShape(); f@0: } f@0: f@0: unsigned int jhapticgui::XYScene::checkCallbacks(void){ f@0: /* openhaptics call to check all the events */ f@0: hlCheckEvents(); f@0: /* no callback update used, return any value */ f@0: return 0; f@0: } f@0: f@0: /* contact callback */ f@0: void jhapticgui::XYScene::checkContact(HLenum event, HLuint object, HLenum thread, HLcache *cache, void *userdata){ f@0: XYScene *pThis = static_cast(userdata); f@0: f@0: /* update a status variable and send a message to the java thread */ f@0: if (event == HL_EVENT_TOUCH){ f@0: pThis->isTouching = true; f@0: pThis->send(Message("touch", "yes", object)); f@0: } f@0: else{ f@0: pThis->isTouching = false; f@0: pThis->send(Message("touch", "no", object)); f@0: } f@0: } f@0: f@0: /* motion callback */ f@0: void jhapticgui::XYScene::checkMotion(HLenum event, HLuint object, HLenum thread, HLcache *cache, void *userdata){ f@0: /* pointer to this scene */ f@0: XYScene *pThis = static_cast(userdata); f@0: f@0: /* get the proxy position */ f@0: HLdouble proxyPosition[3]; f@0: hlGetDoublev(HL_DEVICE_POSITION, proxyPosition); f@0: f@0: /* only send position data if the haptic object is being touched */ f@0: if (pThis->isTouching){ f@0: /* the proxy position ranges from -RADIUS to +RADIUS * f@0: * so the formula to get a normalized position (0 to 1)* f@0: * is: ( proxyPos - (-RADIUS) / (RADIUS) - (-RADIUS) ),* f@0: * let RADIUS be 0.5, the above formula is reduced to * f@0: * proxyPos + RADIUS */ f@0: double x = proxyPosition[0] + RADIUS; f@0: double y = proxyPosition[1] + RADIUS; f@0: f@0: /* send position message */ f@0: char msgArgs[Message::MAX_ARGS_LEN]; f@0: sprintf_s(msgArgs, "%f %f", x, y); f@0: pThis->send(Message("position", msgArgs, object)); f@0: } f@0: } f@0: f@0: f@0: const double jhapticgui::XYScene::RADIUS = 0.5;