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;