fiore@5
|
1 /*
|
fiore@5
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
fiore@5
|
3
|
fiore@5
|
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
fiore@5
|
5
|
fiore@5
|
6 This program is free software: you can redistribute it and/or modify
|
fiore@5
|
7 it under the terms of the GNU General Public License as published by
|
fiore@5
|
8 the Free Software Foundation, either version 3 of the License, or
|
fiore@5
|
9 (at your option) any later version.
|
fiore@5
|
10
|
fiore@5
|
11 This program is distributed in the hope that it will be useful,
|
fiore@5
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
fiore@5
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
fiore@5
|
14 GNU General Public License for more details.
|
fiore@5
|
15
|
fiore@5
|
16 You should have received a copy of the GNU General Public License
|
fiore@5
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
fiore@5
|
18 */
|
fiore@5
|
19
|
fiore@5
|
20 #include "uk_ac_qmul_eecs_ccmi_haptics_FalconHaptics.h"
|
fiore@5
|
21 #include "HapticManager.h"
|
fiore@5
|
22 #include <stdlib.h>
|
fiore@5
|
23 #include <math.h>
|
fiore@5
|
24 #include <assert.h>
|
fiore@5
|
25 #include <setjmp.h>
|
fiore@5
|
26 #include <GL/glut.h>
|
fiore@5
|
27 #ifdef FREEGLUT
|
fiore@5
|
28 #include <GL/freeglut.h>
|
fiore@5
|
29 #endif
|
fiore@5
|
30 #include "utils.h"
|
fiore@5
|
31
|
fiore@5
|
32 /* enum to match against when checking for the jump result */
|
fiore@5
|
33 enum {JMP_OK =0, JMP_EXIT };
|
fiore@5
|
34
|
fiore@5
|
35 /* Functions prototypes. */
|
fiore@5
|
36 /* callbacks */
|
fiore@5
|
37 void display(void);
|
fiore@5
|
38 void reshape(int width, int height);
|
fiore@5
|
39 void idle(void);
|
fiore@5
|
40 void exitProcedure(void);
|
fiore@5
|
41 void commandCallback(const jchar cmd, const jint ID, const jdouble x, const jdouble y,const jdouble startX, const jdouble startY);
|
fiore@5
|
42
|
fiore@5
|
43 void initJniVariables(void);
|
fiore@5
|
44
|
fiore@5
|
45 /* variables */
|
fiore@5
|
46 static HapticManager *hManager;
|
fiore@5
|
47 static CollectionsManager *cManager;
|
fiore@5
|
48 static JNIEnv *env;
|
fiore@5
|
49 static jobject *lock;
|
fiore@5
|
50 static jmp_buf jmpenv;
|
fiore@5
|
51 static int jmpval = 0;
|
fiore@5
|
52 static bool reshaped = false;
|
fiore@5
|
53 /* jni variables */
|
fiore@5
|
54 static jclass hapticClass;
|
fiore@5
|
55 static jclass hapticListenerClass;
|
fiore@5
|
56 static jfieldID shutdownFieldId;
|
fiore@5
|
57 static jfieldID hapticInitFailedfieldId;
|
fiore@5
|
58 static jfieldID collectionsChangedFieldId;
|
fiore@5
|
59 static jfieldID pickUpFieldId;
|
fiore@5
|
60 static jfieldID attractToFieldId;
|
fiore@5
|
61 /* hapticListener jni variables */
|
fiore@5
|
62 static jfieldID hapticListenerFieldId;
|
fiore@5
|
63 static jfieldID cmdFieldId; // belongs to the haptic listener
|
fiore@5
|
64 static jfieldID diagramElementFieldId; // belongs to the haptic listener
|
fiore@5
|
65 static jfieldID xFieldId; // belongs to the haptic listener
|
fiore@5
|
66 static jfieldID yFieldId; // belongs to the haptic listener
|
fiore@5
|
67 static jfieldID startXFieldId; // belongs to the haptic listener
|
fiore@5
|
68 static jfieldID startYFieldId; // belongs to the haptic listener
|
fiore@5
|
69 static jobject hapticListener;
|
fiore@5
|
70 /* synchronization methods ids */
|
fiore@5
|
71 static jmethodID notifyMethodId;
|
fiore@5
|
72 static jmethodID notifyListenerMethodId;
|
fiore@5
|
73 static jmethodID waitMethodId;
|
fiore@5
|
74
|
fiore@5
|
75 /* Native initialization method for the Falcon Haptic device. Upon successful initialization a loop *
|
fiore@5
|
76 * is started that communicates with the Java program in order to represent the diagram haptically */
|
fiore@5
|
77 JNIEXPORT jint JNICALL Java_uk_ac_qmul_eecs_ccmi_haptics_FalconHaptics_initFalcon
|
fiore@5
|
78 (JNIEnv *environment, jobject obj, jint w, jint h){
|
fiore@5
|
79
|
fiore@5
|
80 env = environment;
|
fiore@5
|
81 lock = &obj;
|
fiore@5
|
82 /* fake main argv and argc as this is a dll */
|
fiore@5
|
83 char *argv[1] = {"FalconHaptics"};
|
fiore@5
|
84 int argc = 1;
|
fiore@5
|
85 initJniVariables();
|
fiore@5
|
86
|
fiore@5
|
87 cManager = new CollectionsManager(env,lock);
|
fiore@5
|
88 cManager->init();
|
fiore@5
|
89 hManager = new HapticManager(cManager,commandCallback);
|
fiore@5
|
90
|
fiore@5
|
91 /* try to initialize the haptic, tell the java thread about the success/failure. The endeavour *
|
fiore@5
|
92 * takes the lock on the haptics java object in order to access the nodes and edges concurrently */
|
fiore@5
|
93 if(env->MonitorEnter(*lock) != JNI_OK){
|
fiore@5
|
94 stopExecution("Could not allocate memory for haptic thread monitor");
|
fiore@5
|
95 }
|
fiore@5
|
96 checkExceptions(env, "Could not enter monitor on Haptics");
|
fiore@5
|
97
|
fiore@5
|
98 bool mustSayGoodbye = false;
|
fiore@5
|
99
|
fiore@5
|
100 if(!hManager->init()){
|
fiore@5
|
101 /* set the field in the java class to comunicate the main thread (waiting *
|
fiore@5
|
102 * for the initialization to complete) that the initialization failed */
|
fiore@5
|
103 env->SetBooleanField(*lock,hapticInitFailedfieldId,JNI_TRUE);
|
fiore@5
|
104 mustSayGoodbye = true;
|
fiore@5
|
105 }
|
fiore@5
|
106
|
fiore@5
|
107 if(mustSayGoodbye)
|
fiore@5
|
108 std::cout << "Failed to initialize Falcon haptic device" << std::endl;
|
fiore@5
|
109 else
|
fiore@5
|
110 std::cout << "Falcon haptic device successfully initialized" << std::endl;
|
fiore@5
|
111
|
fiore@5
|
112 /* notify the java thread */
|
fiore@5
|
113 env->CallVoidMethod(*lock,notifyMethodId);
|
fiore@5
|
114 checkExceptions(env,"Could not call notify() on Haptics");
|
fiore@5
|
115
|
fiore@5
|
116 /* release the lock */
|
fiore@5
|
117 if(env->MonitorExit(*lock) != JNI_OK){
|
fiore@5
|
118 std::cerr << "Could not release memory for haptic thread monitor" << std::endl;
|
fiore@5
|
119 exit(-1);
|
fiore@5
|
120 }
|
fiore@5
|
121
|
fiore@5
|
122 if(mustSayGoodbye)
|
fiore@5
|
123 /* initialization failed: return */
|
fiore@5
|
124 return -1;
|
fiore@5
|
125
|
fiore@5
|
126 /* haptic device is initialized, now build the openGL window */
|
fiore@5
|
127
|
fiore@5
|
128 /* glut initialization */
|
fiore@5
|
129 glutInit(&argc, argv);
|
fiore@5
|
130
|
fiore@5
|
131 glutInitWindowSize( w, h );
|
fiore@5
|
132 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
|
fiore@5
|
133 glutCreateWindow( "Falcon Haptics Window" );
|
fiore@5
|
134
|
fiore@5
|
135 /* set up GLUT callback functions */
|
fiore@5
|
136 glutDisplayFunc ( display );
|
fiore@5
|
137 glutReshapeFunc ( reshape );
|
fiore@5
|
138 glutIdleFunc( idle );
|
fiore@5
|
139
|
fiore@5
|
140 /* use setjmp to be able to jump off the glutMainLoop when the user shuts the program down */
|
fiore@5
|
141 jmpval = setjmp(jmpenv);
|
fiore@5
|
142
|
fiore@5
|
143 /* start the loop*/
|
fiore@5
|
144 if(jmpval == JMP_OK){
|
fiore@5
|
145 glutMainLoop();
|
fiore@5
|
146 }
|
fiore@5
|
147
|
fiore@5
|
148 /* jmpval = JMP_EXIT, we're coming from the glut loop */
|
fiore@5
|
149 exitProcedure();
|
fiore@5
|
150
|
fiore@5
|
151 return 0;
|
fiore@5
|
152 }
|
fiore@5
|
153
|
fiore@5
|
154 /* GLUT display callback */
|
fiore@5
|
155 void display(){
|
fiore@5
|
156 /* takes the lock on the haptics java obejct in order to access the nodes and edges concurrently */
|
fiore@5
|
157 if(env->MonitorEnter(*lock) != JNI_OK){
|
fiore@5
|
158 stopExecution("Could not allocate memory for haptic thread monitor");
|
fiore@5
|
159 }
|
fiore@5
|
160 checkExceptions(env,"Could not enter monitor on Haptics");
|
fiore@5
|
161
|
fiore@5
|
162 /* check if there is a shutdown request */
|
fiore@5
|
163 if( env->GetBooleanField(*lock,shutdownFieldId) == JNI_TRUE ){
|
fiore@5
|
164 // notify the other thread that this thread is about to die
|
fiore@5
|
165 env->CallVoidMethod(*lock,notifyMethodId);
|
fiore@5
|
166 checkExceptions(env, "Could not call notify() on Haptics");
|
fiore@5
|
167 // release the lock
|
fiore@5
|
168 if(env->MonitorExit(*lock) != JNI_OK){
|
fiore@5
|
169 std::cerr << "Could not release memory for haptic thread monitor" << std::endl;
|
fiore@5
|
170 }
|
fiore@5
|
171 longjmp(jmpenv,JMP_EXIT);
|
fiore@5
|
172 }
|
fiore@5
|
173
|
fiore@5
|
174 /* check if the node and edges collections have changed since the last frame or if *
|
fiore@5
|
175 * the window has been reshaped. In either case the haptic scene must be rendered again */
|
fiore@5
|
176 bool collectionsChanged = false;
|
fiore@5
|
177 if(env->GetBooleanField(*lock,collectionsChangedFieldId) == JNI_TRUE || reshaped){
|
fiore@5
|
178 if(reshaped)
|
fiore@5
|
179 reshaped = false;
|
fiore@5
|
180 /* remember that collections have changed (will be used later in hManager->drawDiagram) */
|
fiore@5
|
181 collectionsChanged = true;
|
fiore@5
|
182 /* set the Java boolean variable back to false */
|
fiore@5
|
183 env->SetBooleanField(*lock,collectionsChangedFieldId,JNI_FALSE);
|
fiore@5
|
184 }
|
fiore@5
|
185
|
fiore@5
|
186 /* check if the user picked up an object */
|
fiore@5
|
187 jboolean picked_up = env->GetBooleanField(*lock,pickUpFieldId);
|
fiore@5
|
188 if(picked_up == JNI_TRUE){
|
fiore@5
|
189 env->SetBooleanField(*lock,pickUpFieldId,JNI_FALSE);
|
fiore@5
|
190 }
|
fiore@5
|
191
|
fiore@5
|
192 /* check if the user asked to be attracted to a node */
|
fiore@5
|
193 jint attract_to = env->GetIntField(*lock,attractToFieldId);
|
fiore@5
|
194 if(attract_to != HapticManager::NO_ID){
|
fiore@5
|
195 env->SetIntField(*lock,attractToFieldId,HapticManager::NO_ID);
|
fiore@5
|
196 }
|
fiore@5
|
197
|
fiore@5
|
198 /* --- start drawing --- */
|
fiore@5
|
199 /* Set up OpenGL state. */
|
fiore@5
|
200 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
fiore@5
|
201 glEnable(GL_DEPTH_TEST);
|
fiore@5
|
202 glDepthFunc(GL_LESS);
|
fiore@5
|
203 glDepthMask(GL_TRUE);
|
fiore@5
|
204 glEnable(GL_CULL_FACE);
|
fiore@5
|
205 glShadeModel(GL_SMOOTH);
|
fiore@5
|
206 glEnable( GL_LIGHTING );
|
fiore@5
|
207 glEnable(GL_LIGHT0);
|
fiore@5
|
208 glLoadIdentity();
|
fiore@5
|
209
|
fiore@5
|
210 gluLookAt(0, 0, 0.1, // eye position .05
|
fiore@5
|
211 0, 0, 0, // center position
|
fiore@5
|
212 0, 1, 0); // which direction is up
|
fiore@5
|
213 glEnable( GL_NORMALIZE );
|
fiore@5
|
214
|
fiore@5
|
215 /* draw the diagram graphicly and, if the collection has changed, haptically too */
|
fiore@5
|
216 hManager->drawCursor();
|
fiore@5
|
217 hManager->drawDiagram(collectionsChanged,(picked_up == JNI_TRUE),attract_to);
|
fiore@5
|
218
|
fiore@5
|
219
|
fiore@5
|
220 /* release lock. HapticManager methods from now on can execute commands without deadlock risk */
|
fiore@5
|
221 if(env->MonitorExit(*lock) != JNI_OK){
|
fiore@5
|
222 stopExecution("Could not release memory for haptic thread monitor");
|
fiore@5
|
223 }
|
fiore@5
|
224 /* check button status */
|
fiore@5
|
225 hManager->checkButtons();
|
fiore@5
|
226
|
fiore@5
|
227 /* check if un unselect command is to be issued, for an object being touched has been deleted */
|
fiore@5
|
228 hManager->checkUnselection();
|
fiore@5
|
229
|
fiore@5
|
230 /* check collisions. priority to nodes */
|
fiore@5
|
231 bool node_collision = hManager->checkNodeCollision();
|
fiore@5
|
232 if(!node_collision) // only one object at time can be touched
|
fiore@5
|
233 hManager->checkEdgeCollision();
|
fiore@5
|
234 /* check motion feedback */
|
fiore@5
|
235 hManager->checkMotion();
|
fiore@5
|
236
|
fiore@5
|
237 /* swap graphic buffers. */
|
fiore@5
|
238 glutSwapBuffers();
|
fiore@5
|
239 }
|
fiore@5
|
240
|
fiore@5
|
241 /* GLUT reshape callback */
|
fiore@5
|
242 void reshape (int w, int h){
|
fiore@5
|
243 cManager->setScreenHeight(h);
|
fiore@5
|
244 cManager->setScreenWidth(w);
|
fiore@5
|
245 reshaped = true;
|
fiore@5
|
246
|
fiore@5
|
247 static const double ANGLE = 100;
|
fiore@5
|
248 glViewport(0, 0, w, h);
|
fiore@5
|
249 glMatrixMode(GL_PROJECTION);
|
fiore@5
|
250 glLoadIdentity();
|
fiore@5
|
251 gluPerspective(ANGLE, // angle
|
fiore@5
|
252 (float)w / h, // aspect ratio
|
fiore@5
|
253 0.01, // near clipping plane .01
|
fiore@5
|
254 500);// far clipping plane 1000
|
fiore@5
|
255 glMatrixMode(GL_MODELVIEW);
|
fiore@5
|
256 }
|
fiore@5
|
257
|
fiore@5
|
258 /* GLUT idle callback */
|
fiore@5
|
259 void idle(){
|
fiore@5
|
260 glutPostRedisplay();
|
fiore@5
|
261 }
|
fiore@5
|
262
|
fiore@5
|
263 /* called before exit */
|
fiore@5
|
264 void exitProcedure(){
|
fiore@5
|
265 hManager->dispose();
|
fiore@5
|
266 delete hManager;
|
fiore@5
|
267 delete cManager;
|
fiore@5
|
268 }
|
fiore@5
|
269
|
fiore@5
|
270 /* initialize all the variables needed for the jni access to the Falcon Haptics class by the Haptic thread*/
|
fiore@5
|
271 void initJniVariables(void){
|
fiore@5
|
272 /* --- CLASSES --- */
|
fiore@5
|
273 //this class
|
fiore@5
|
274 hapticClass = env->GetObjectClass(*lock);
|
fiore@5
|
275 if(hapticClass == NULL){
|
fiore@5
|
276 stopExecution("Could not find the Haptics class");
|
fiore@5
|
277 }
|
fiore@5
|
278 // the haptic listener, member of this class
|
fiore@5
|
279 hapticListenerClass = env->FindClass("Luk/ac/qmul/eecs/ccmi/haptics/HapticListenerThread;");
|
fiore@5
|
280 if(hapticListenerClass == NULL){
|
fiore@5
|
281 stopExecution("Could not find the haptic listener class");
|
fiore@5
|
282 }
|
fiore@5
|
283
|
fiore@5
|
284 /* --- FIELD IDS --- */
|
fiore@5
|
285
|
fiore@5
|
286 // boolean set to this thread to notify the java thread the unsuccessful initialization of haptic device
|
fiore@5
|
287 hapticInitFailedfieldId = env->GetFieldID(hapticClass,"initFailed", "Z");
|
fiore@5
|
288 if(hapticInitFailedfieldId == NULL){
|
fiore@5
|
289 stopExecution("failed to find the initFailed field id");
|
fiore@5
|
290 }
|
fiore@5
|
291
|
fiore@5
|
292 // boolean set by the java thread to notify this thread the program has been shut down
|
fiore@5
|
293 shutdownFieldId = env->GetFieldID(hapticClass, "shutdown", "Z");
|
fiore@5
|
294 if(shutdownFieldId == NULL){
|
fiore@5
|
295 stopExecution("failed to find the shutdownfieldId field id");
|
fiore@5
|
296 }
|
fiore@5
|
297
|
fiore@5
|
298 collectionsChangedFieldId = env->GetFieldID(hapticClass, "collectionsChanged", "Z");
|
fiore@5
|
299 if(collectionsChangedFieldId == NULL){
|
fiore@5
|
300 stopExecution("failed to find the collectionsChangedFieldId field id");
|
fiore@5
|
301 }
|
fiore@5
|
302
|
fiore@5
|
303 attractToFieldId = env->GetFieldID(hapticClass, "attractTo" , "I");
|
fiore@5
|
304 if(attractToFieldId == NULL){
|
fiore@5
|
305 stopExecution("failed to find the attractTo field id");
|
fiore@5
|
306 }
|
fiore@5
|
307
|
fiore@5
|
308 pickUpFieldId = env->GetFieldID(hapticClass,"pickUp","Z");
|
fiore@5
|
309 if(pickUpFieldId == NULL){
|
fiore@5
|
310 stopExecution("failed to find the pickUp field id");
|
fiore@5
|
311 }
|
fiore@5
|
312
|
fiore@5
|
313 hapticListenerFieldId = env->GetFieldID(hapticClass, "hapticListener", "Luk/ac/qmul/eecs/ccmi/haptics/HapticListenerThread;");
|
fiore@5
|
314 if(hapticListenerFieldId == NULL){
|
fiore@5
|
315 stopExecution("failed to find the hapticListenerThread field id");
|
fiore@5
|
316 }
|
fiore@5
|
317
|
fiore@5
|
318 cmdFieldId = env->GetFieldID(hapticListenerClass,"cmd", "C");
|
fiore@5
|
319 if(cmdFieldId == NULL){
|
fiore@5
|
320 stopExecution("failed to find the cmd field id of the hapticListener class");
|
fiore@5
|
321 }
|
fiore@5
|
322
|
fiore@5
|
323 diagramElementFieldId = env->GetFieldID(hapticListenerClass, "diagramElementID", "I");
|
fiore@5
|
324 if(diagramElementFieldId == NULL){
|
fiore@5
|
325 stopExecution("failed to find the diagramElement field id of the hapticListener class");
|
fiore@5
|
326 }
|
fiore@5
|
327
|
fiore@5
|
328 xFieldId = env->GetFieldID(hapticListenerClass, "x", "D");
|
fiore@5
|
329 if(xFieldId == NULL){
|
fiore@5
|
330 stopExecution("failed to find the x field id of the hapticListener class");
|
fiore@5
|
331 }
|
fiore@5
|
332
|
fiore@5
|
333 yFieldId = env->GetFieldID(hapticListenerClass, "y", "D");
|
fiore@5
|
334 if(yFieldId == NULL){
|
fiore@5
|
335 stopExecution("failed to find the y field id of the hapticListener class");
|
fiore@5
|
336 }
|
fiore@5
|
337
|
fiore@5
|
338 startXFieldId = env->GetFieldID(hapticListenerClass, "startX", "D");
|
fiore@5
|
339 if(startXFieldId == NULL){
|
fiore@5
|
340 stopExecution("failed to find the x field id of the hapticListener class");
|
fiore@5
|
341 }
|
fiore@5
|
342
|
fiore@5
|
343 startYFieldId = env->GetFieldID(hapticListenerClass, "startY", "D");
|
fiore@5
|
344 if(startYFieldId == NULL){
|
fiore@5
|
345 stopExecution("failed to find the y field id of the hapticListener class");
|
fiore@5
|
346 }
|
fiore@5
|
347
|
fiore@5
|
348 hapticListener = env->GetObjectField(*lock,hapticListenerFieldId);
|
fiore@5
|
349 /* --- SYNCHRONIZATION METHODS ID --- */
|
fiore@5
|
350 // notify()
|
fiore@5
|
351 notifyMethodId = env->GetMethodID(hapticClass,"notify","()V");
|
fiore@5
|
352 if(notifyMethodId == NULL){
|
fiore@5
|
353 stopExecution("failed to find the notify method id");
|
fiore@5
|
354 }
|
fiore@5
|
355
|
fiore@5
|
356 notifyListenerMethodId = env->GetMethodID(hapticListenerClass,"notify","()V");
|
fiore@5
|
357 if(notifyListenerMethodId == NULL){
|
fiore@5
|
358 stopExecution("failed to find the notify method id");
|
fiore@5
|
359 }
|
fiore@5
|
360 // wait()
|
fiore@5
|
361 waitMethodId = env->GetMethodID(hapticListenerClass,"wait","()V");
|
fiore@5
|
362 if(waitMethodId == NULL){
|
fiore@5
|
363 stopExecution("failed to find the wait method id");
|
fiore@5
|
364 }
|
fiore@5
|
365 }
|
fiore@5
|
366
|
fiore@5
|
367 void commandCallback(const jchar cmd, const jint ID, const jdouble x, const jdouble y, const jdouble startX, const jdouble startY){
|
fiore@5
|
368 /* the haptic listener java thread is waiting for commands
|
fiore@5
|
369 first set the variable the Haptic Listener java thread will read after being notified,
|
fiore@5
|
370 then notify and get it awake. Thus wait for the java thread to notify that the command
|
fiore@5
|
371 has been accomplished. This is done as otherwise some commands might be neglected. as if the thread
|
fiore@5
|
372 scheduler decides to execute twice this routine without executing the java thread in the middle then
|
fiore@5
|
373 the former command gets overwritten by the latter.
|
fiore@5
|
374 Note the monitor is hapticListener and not haptics as for the draw function.
|
fiore@5
|
375 When in this routine, this thread does not hold the lock on haptics as if a command results in changing
|
fiore@5
|
376 the elements collections (e.g. moveNode) all those methods are synchronized and require to acquire the lock on haptics.
|
fiore@5
|
377 Since this thread would wait for the command to be executed by the java thread, which in turns would wait for this
|
fiore@5
|
378 thread to release the lock on haptics, that would result in a deadlock.
|
fiore@5
|
379 */
|
fiore@5
|
380 if(env->MonitorEnter(hapticListener) != JNI_OK){
|
fiore@5
|
381 stopExecution("Could not allocate memory for haptic listener thread monitor");
|
fiore@5
|
382 }
|
fiore@5
|
383 checkExceptions(env,"Could not enter monitor on the haptic listener");
|
fiore@5
|
384 /* Fill all the shared variables for informaton for the command to be executed */
|
fiore@5
|
385 env->SetCharField(hapticListener,cmdFieldId,cmd);
|
fiore@5
|
386 env->SetIntField(hapticListener,diagramElementFieldId,ID);
|
fiore@5
|
387 env->SetDoubleField(hapticListener,xFieldId,x);
|
fiore@5
|
388 env->SetDoubleField(hapticListener,yFieldId,y);
|
fiore@5
|
389 env->SetDoubleField(hapticListener,startXFieldId,startX);
|
fiore@5
|
390 env->SetDoubleField(hapticListener,startYFieldId,startY);
|
fiore@5
|
391 // wake the java thread up to execute the command
|
fiore@5
|
392 env->CallVoidMethod(hapticListener,notifyListenerMethodId);
|
fiore@5
|
393 checkExceptions(env, "Could not call notify() on HapticListener");
|
fiore@5
|
394 /* wait for the commands to be executed. Here is actually where the monitor is *
|
fiore@5
|
395 * freed and the java thread starts to execute the command, having been notified */
|
fiore@5
|
396 env->CallVoidMethod(hapticListener,waitMethodId);
|
fiore@5
|
397 checkExceptions(env, "Could not call wait() on HapticListener");
|
fiore@5
|
398 if(env->MonitorExit(hapticListener) != JNI_OK){
|
fiore@5
|
399 stopExecution("Could not release memory for haptic listener thread monitor");
|
fiore@5
|
400 }
|
fiore@5
|
401 }
|