f@0
|
1 /*
|
f@0
|
2 XYPad - a haptic xy-pad that uses the jHapticGUI library
|
f@0
|
3
|
f@0
|
4 Copyright (C) 2015 Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
|
f@0
|
5
|
f@0
|
6 This program is free software: you can redistribute it and/or modify
|
f@0
|
7 it under the terms of the GNU General Public License as published by
|
f@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
f@0
|
9 (at your option) any later version.
|
f@0
|
10
|
f@0
|
11 This program is distributed in the hope that it will be useful,
|
f@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@0
|
14 GNU General Public License for more details.
|
f@0
|
15
|
f@0
|
16 You should have received a copy of the GNU General Public License
|
f@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@0
|
18 */
|
f@0
|
19 #include "XYScene.h"
|
f@0
|
20
|
f@0
|
21 #include <HL/hl.h>
|
f@0
|
22 #include <HDU/hduError.h>
|
f@0
|
23
|
f@0
|
24 #include <GL/gl.h>
|
f@0
|
25 #include <GL/glu.h>
|
f@0
|
26 #include <GL/glut.h>
|
f@0
|
27
|
f@0
|
28 #include <iostream>
|
f@0
|
29
|
f@0
|
30 jhapticgui::XYScene::XYScene(void(*messageCallback) (const Message & m)) : HapticScene(messageCallback) {}
|
f@0
|
31
|
f@0
|
32 jhapticgui::XYScene::~XYScene() {}
|
f@0
|
33
|
f@0
|
34 bool jhapticgui::XYScene::initHaptics(void){
|
f@0
|
35 /* init haptic device */
|
f@0
|
36 HHD hHD = hdInitDevice(HD_DEFAULT_DEVICE);
|
f@0
|
37 if (HD_DEVICE_ERROR(hdGetError())) {
|
f@0
|
38 /* if unsuccessful return false */
|
f@0
|
39 return false;
|
f@0
|
40 }
|
f@0
|
41
|
f@0
|
42 /* create haptic context */
|
f@0
|
43 HHLRC hHLRC = hlCreateContext(hHD);
|
f@0
|
44 hlMakeCurrent(hHLRC);
|
f@0
|
45
|
f@0
|
46 /* Reserve an id for the shape */
|
f@0
|
47 shapeID = hlGenShapes(1);
|
f@0
|
48
|
f@0
|
49
|
f@0
|
50 /* initialize the haptic space */
|
f@0
|
51 hlMatrixMode(HL_TOUCHWORKSPACE);
|
f@0
|
52 hlLoadIdentity();
|
f@0
|
53 hlOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
|
f@0
|
54
|
f@0
|
55 /* install event callbacks for touch and motion */
|
f@0
|
56 hlAddEventCallback(HL_EVENT_TOUCH, HL_OBJECT_ANY, HL_CLIENT_THREAD, checkContact, this);
|
f@0
|
57 hlAddEventCallback(HL_EVENT_UNTOUCH, HL_OBJECT_ANY, HL_CLIENT_THREAD, checkContact, this);
|
f@0
|
58 hlAddEventCallback(HL_EVENT_MOTION, HL_OBJECT_ANY, HL_CLIENT_THREAD, checkMotion, this);
|
f@0
|
59
|
f@0
|
60 /* initialization successful */
|
f@0
|
61 return true;
|
f@0
|
62 }
|
f@0
|
63
|
f@0
|
64 void jhapticgui::XYScene::initGL(void){
|
f@0
|
65 glClearColor(0.0, 0.0, 0.0, 0.0);
|
f@0
|
66 glMatrixMode(GL_PROJECTION);
|
f@0
|
67 glLoadIdentity();
|
f@0
|
68 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
|
f@0
|
69
|
f@0
|
70 glDepthFunc(GL_LEQUAL);
|
f@0
|
71 glEnable(GL_DEPTH_TEST);
|
f@0
|
72 }
|
f@0
|
73
|
f@0
|
74
|
f@0
|
75 unsigned int jhapticgui::XYScene::processMessage(const Message & m){
|
f@0
|
76 /* there is only one type of message coming from the java *
|
f@0
|
77 * but the check is performed nevertheless for clarity */
|
f@0
|
78 if (!strcmp(m.command, "change")) {
|
f@0
|
79
|
f@0
|
80 /* the command selects the shape to display here all is done *
|
f@0
|
81 * is just a variable update. The variable new value will be *
|
f@0
|
82 * read in the next cycle of drawScene */
|
f@0
|
83 if (!strcmp(m.args, "circle")){
|
f@0
|
84 shape = Shape::CIRCLE;
|
f@0
|
85 }
|
f@0
|
86 else if(!strcmp(m.args, "square")){
|
f@0
|
87 shape = Shape::SQUARE;
|
f@0
|
88 }
|
f@0
|
89 }
|
f@0
|
90
|
f@0
|
91 /* message updates not used, just return any value */
|
f@0
|
92 return 0;
|
f@0
|
93 }
|
f@0
|
94
|
f@0
|
95 void jhapticgui::XYScene::beginFrame(void){
|
f@0
|
96 hlBeginFrame();
|
f@0
|
97 }
|
f@0
|
98
|
f@0
|
99 void jhapticgui::XYScene::endFrame(void){
|
f@0
|
100 hlEndFrame();
|
f@0
|
101 }
|
f@0
|
102
|
f@0
|
103 void jhapticgui::XYScene::drawCursor(void){
|
f@0
|
104 /* no cursor drawn */
|
f@0
|
105 }
|
f@0
|
106
|
f@0
|
107 void jhapticgui::XYScene::drawScene(unsigned int messageUpdate, unsigned int callbacksUpdate){
|
f@0
|
108
|
f@0
|
109 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
f@0
|
110 glColor3f(1.0, 200.0/255.0, 0.0);
|
f@0
|
111
|
f@0
|
112 hlBeginShape(HL_SHAPE_DEPTH_BUFFER, shapeID);
|
f@0
|
113
|
f@0
|
114 /* use shape variable to determine which shape to draw */
|
f@0
|
115 if (shape == Shape::SQUARE){
|
f@0
|
116 glBegin(GL_POLYGON);
|
f@0
|
117 glVertex3f(-RADIUS, -RADIUS, 0.0);
|
f@0
|
118 glVertex3f(RADIUS, -RADIUS, 0.0);
|
f@0
|
119 glVertex3f(RADIUS, RADIUS, 0.0);
|
f@0
|
120 glVertex3f(-RADIUS, RADIUS, 0.0);
|
f@0
|
121 glEnd();
|
f@0
|
122 }
|
f@0
|
123 else { // CIRCLE
|
f@0
|
124 glutSolidSphere(RADIUS, 64, 64);
|
f@0
|
125 }
|
f@0
|
126
|
f@0
|
127 hlEndShape();
|
f@0
|
128 }
|
f@0
|
129
|
f@0
|
130 unsigned int jhapticgui::XYScene::checkCallbacks(void){
|
f@0
|
131 /* openhaptics call to check all the events */
|
f@0
|
132 hlCheckEvents();
|
f@0
|
133 /* no callback update used, return any value */
|
f@0
|
134 return 0;
|
f@0
|
135 }
|
f@0
|
136
|
f@0
|
137 /* contact callback */
|
f@0
|
138 void jhapticgui::XYScene::checkContact(HLenum event, HLuint object, HLenum thread, HLcache *cache, void *userdata){
|
f@0
|
139 XYScene *pThis = static_cast<XYScene*>(userdata);
|
f@0
|
140
|
f@0
|
141 /* update a status variable and send a message to the java thread */
|
f@0
|
142 if (event == HL_EVENT_TOUCH){
|
f@0
|
143 pThis->isTouching = true;
|
f@0
|
144 pThis->send(Message("touch", "yes", object));
|
f@0
|
145 }
|
f@0
|
146 else{
|
f@0
|
147 pThis->isTouching = false;
|
f@0
|
148 pThis->send(Message("touch", "no", object));
|
f@0
|
149 }
|
f@0
|
150 }
|
f@0
|
151
|
f@0
|
152 /* motion callback */
|
f@0
|
153 void jhapticgui::XYScene::checkMotion(HLenum event, HLuint object, HLenum thread, HLcache *cache, void *userdata){
|
f@0
|
154 /* pointer to this scene */
|
f@0
|
155 XYScene *pThis = static_cast<XYScene*>(userdata);
|
f@0
|
156
|
f@0
|
157 /* get the proxy position */
|
f@0
|
158 HLdouble proxyPosition[3];
|
f@0
|
159 hlGetDoublev(HL_DEVICE_POSITION, proxyPosition);
|
f@0
|
160
|
f@0
|
161 /* only send position data if the haptic object is being touched */
|
f@0
|
162 if (pThis->isTouching){
|
f@0
|
163 /* the proxy position ranges from -RADIUS to +RADIUS *
|
f@0
|
164 * so the formula to get a normalized position (0 to 1)*
|
f@0
|
165 * is: ( proxyPos - (-RADIUS) / (RADIUS) - (-RADIUS) ),*
|
f@0
|
166 * let RADIUS be 0.5, the above formula is reduced to *
|
f@0
|
167 * proxyPos + RADIUS */
|
f@0
|
168 double x = proxyPosition[0] + RADIUS;
|
f@0
|
169 double y = proxyPosition[1] + RADIUS;
|
f@0
|
170
|
f@0
|
171 /* send position message */
|
f@0
|
172 char msgArgs[Message::MAX_ARGS_LEN];
|
f@0
|
173 sprintf_s(msgArgs, "%f %f", x, y);
|
f@0
|
174 pThis->send(Message("position", msgArgs, object));
|
f@0
|
175 }
|
f@0
|
176 }
|
f@0
|
177
|
f@0
|
178
|
f@0
|
179 const double jhapticgui::XYScene::RADIUS = 0.5; |