00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #if defined(_MSC_VER)
00030 #include <winsock2.h>
00031 #else
00032 #include <stdio.h>
00033 #include <arpa/inet.h>
00034 #include <fcntl.h>
00035 #include <sys/types.h>
00036 #include <unistd.h>
00037 #include <sys/socket.h>
00038 #include <time.h>
00039 #include <netinet/in.h>
00040 #endif
00041
00042 #include "MobileInterface.h"
00043 #include "DisplayDevice.h"
00044 #include "TextEvent.h"
00045 #include "CommandQueue.h"
00046 #include "Inform.h"
00047 #include "PickList.h"
00048 #include "Animation.h"
00049 #include "VMDApp.h"
00050 #include "math.h"
00051 #include "stdlib.h"
00052
00053
00054
00055 #define CURRENTAPIVERSION 9
00056
00057
00058 #define PACKET_ORIENT 1 // device orientation (gyro, accel, etc)
00059 #define PACKET_TOUCH 2 // touchpad events (up, down, move, etc)
00060 #define PACKET_HEARTBEAT 3 // heartbeat.. likely every second
00061 #define PACKET_CONNECT 4 // information about new connection
00062 #define PACKET_DISCONNECT 5 // notice that a device has disconnected
00063 #define PACKET_BUTTON 6 // button state has changed.
00064
00065
00066 #define EVENT_NON_TOUCH -1
00067 #define EVENT_TOUCH_DOWN 0
00068 #define EVENT_TOUCH_UP 1
00069 #define EVENT_TOUCH_MOVE 2
00070 #define EVENT_TOUCH_SOMEUP 5
00071 #define EVENT_TOUCH_SOMEDOWN 6
00072 #define EVENT_COMMAND 7
00073
00074
00075 #define SEND_HEARTBEAT 0
00076 #define SEND_ADDCLIENT 1
00077 #define SEND_REMOVECLIENT 2
00078 #define SEND_SETACTIVECLIENT 3
00079 #define SEND_SETMODE 4
00080 #define SEND_MESSAGE 5
00081
00082
00083
00084
00085 static void swap4_aligned(void *v, long ndata) {
00086 int *data = (int *) v;
00087 long i;
00088 int *N;
00089 for (i=0; i<ndata; i++) {
00090 N = data + i;
00091 *N=(((*N>>24)&0xff) | ((*N&0xff)<<24) |
00092 ((*N>>8)&0xff00) | ((*N&0xff00)<<8));
00093 }
00094 }
00095
00096
00097 void Mobile::prepareSendBuffer(const int eventType) {
00098 memset(statusSendBuffer, 0, sizeof(statusSendBuffer));
00099 int caretLoc = 0;
00100 int itmp=0;
00101
00102
00103
00104 itmp=1;
00105 memcpy(statusSendBuffer + caretLoc, &itmp, sizeof(itmp));
00106 caretLoc += sizeof(int);
00107
00108
00109
00110 itmp=CURRENTAPIVERSION;
00111 memcpy(statusSendBuffer + caretLoc, &itmp, sizeof(itmp));
00112 caretLoc += sizeof(int);
00113
00114
00115
00116 itmp=moveMode;
00117 memcpy(statusSendBuffer + caretLoc, &itmp, sizeof(itmp));
00118 caretLoc += sizeof(int);
00119
00120
00121
00122 itmp=eventType;
00123 memcpy(statusSendBuffer + caretLoc, &itmp, sizeof(itmp));
00124 caretLoc += sizeof(int);
00125
00126
00127
00128 caretLoc += 4;
00129
00130
00131
00132 itmp=clientNick.num();
00133 memcpy(statusSendBuffer + caretLoc, &itmp, sizeof(itmp));
00134 caretLoc += sizeof(int);
00135
00136
00137
00138 for (int i=0; i<clientNick.num();i++) {
00139 int strLength = strlen((const char *)(*(clientNick)[i]));
00140
00141 itmp=strLength;
00142 memcpy(statusSendBuffer + caretLoc, &itmp, sizeof(itmp));
00143 caretLoc += sizeof(int);
00144
00145
00146 memcpy((statusSendBuffer + caretLoc), (const char *)(*(clientNick)[i]), strLength);
00147 caretLoc += strLength;
00148
00149
00150
00151 itmp=(clientActive[i] ? 1 : 0);
00152 memcpy(statusSendBuffer + caretLoc, &itmp, sizeof(itmp));
00153 caretLoc += sizeof(int);
00154 }
00155
00156
00157
00158
00159
00160
00161
00162 statusSendBufferLength = caretLoc;
00163 }
00164
00165
00166
00167 typedef struct {
00168
00169 char buffer[1024];
00170 struct sockaddr_in sockaddr;
00171 #if defined(_MSC_VER)
00172 SOCKET sockfd;
00173 #else
00174 int sockfd;
00175 #endif
00176 int fromlen;
00177
00178
00179 int seqnum;
00180 int buttons;
00181 float rx;
00182 float ry;
00183 float rz;
00184 float tx;
00185 float ty;
00186 float tz;
00187 int padaction;
00188 int touchcnt;
00189 int upid;
00190 int touchid[16];
00191 float padx[16];
00192 float pady[16];
00193 float rotmatrix[9];
00194 } mobilehandle;
00195
00196
00197
00198 static void * mobile_listener_create(int port) {
00199 mobilehandle *ph = (mobilehandle *) calloc(1, sizeof(mobilehandle));
00200 if (ph == NULL)
00201 return NULL;
00202
00203 #if defined(_MSC_VER)
00204
00205 WSADATA wsaData;
00206 if (WSAStartup(MAKEWORD(2,2), &wsaData) != NO_ERROR)
00207 return NULL;
00208 #endif
00209
00210 if ((ph->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00211 perror("socket: ");
00212 free(ph);
00213 return NULL;
00214 }
00215
00216
00217 #if defined(_MSC_VER)
00218 u_long nonblock = 1;
00219 ioctlsocket(ph->sockfd, FIONBIO, &nonblock);
00220 #else
00221 int sockflags;
00222 sockflags = fcntl(ph->sockfd, F_GETFL, 0);
00223 fcntl(ph->sockfd, F_SETFL, sockflags | O_NONBLOCK);
00224 #endif
00225
00226 memset(&ph->sockaddr, 0, sizeof(ph->sockaddr));
00227 ph->sockaddr.sin_family = AF_INET;
00228 ph->sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
00229 ph->sockaddr.sin_port = htons(port);
00230
00231 if (bind(ph->sockfd, (struct sockaddr *)&ph->sockaddr, sizeof(sockaddr)) < 0) {
00232 perror("bind: ");
00233 free(ph);
00234 return NULL;
00235 }
00236
00237 return ph;
00238 }
00239
00240
00241 int getint32(char *bufptr) {
00242 int tmp=0;
00243 memcpy(&tmp, bufptr, sizeof(int));
00244 return tmp;
00245 }
00246
00247 float getfloat32(char *bufptr) {
00248 float tmp=0;
00249 memcpy(&tmp, bufptr, sizeof(float));
00250 return tmp;
00251 }
00252
00253
00254
00255 static int mobile_listener_poll(void *voidhandle,
00256 float &tx, float &ty, float &tz,
00257 float &rx, float &ry, float &rz,
00258 int &padaction, int &upid,
00259 int &touchcnt, int *touchid,
00260 float *padx, float *pady,
00261 int &buttons, int &packtype, JString &incomingIP,
00262 JString ¤tNick, int &listenerPort,
00263 float &tranScal, float &rotScal, float &zoomScal,
00264 JString &commandToSend) {
00265 mobilehandle *ph = (mobilehandle *) voidhandle;
00266 int offset = 0;
00267
00268 memset(ph->buffer, 0, sizeof(ph->buffer));
00269 #if defined(_MSC_VER)
00270 int fromlen=sizeof(ph->sockaddr);
00271 #else
00272 socklen_t fromlen=sizeof(ph->sockaddr);
00273 #endif
00274 int packlen=0;
00275
00276 packlen=recvfrom(ph->sockfd, ph->buffer, sizeof(ph->buffer), 0, (struct sockaddr *)&ph->sockaddr, &fromlen);
00277
00278 if (packlen < 1) {
00279 return 0;
00280 }
00281
00282
00283
00284 if (getint32(ph->buffer) != 1) {
00285 swap4_aligned(ph->buffer, sizeof(ph->buffer) / 4);
00286 }
00287
00288 if (getint32(ph->buffer) != 1) {
00289 printf("Received unrecognized mobile packet...\n");
00290 return 0;
00291 }
00292
00293
00294
00295 int endianism = getint32(ph->buffer + offset*sizeof(int));
00296 offset++;
00297
00298 int apiversion = getint32(ph->buffer + offset*sizeof(int));
00299 offset++;
00300
00301
00302
00303 if (endianism != 1 || (apiversion < 7 || apiversion > CURRENTAPIVERSION)) {
00304 msgWarn << "Dropped incoming mobile input packet from "
00305 << inet_ntoa((ph->sockaddr).sin_addr)
00306 << ", version: " << apiversion << sendmsg;
00307 return 0;
00308 }
00309
00310
00311 char nickName[17];
00312 memcpy(nickName, ph->buffer+(offset*sizeof(int)), 16);
00313 nickName[16] = 0;
00314 currentNick = nickName;
00315
00316 offset += 4;
00317
00318 if (apiversion >= 9) {
00319
00320
00321
00322
00323 listenerPort = getint32(ph->buffer + offset*sizeof(float));
00324 offset++;
00325 rotScal = getfloat32(ph->buffer + offset*sizeof(float));
00326 offset++;
00327 zoomScal = getfloat32(ph->buffer + offset*sizeof(float));
00328 offset++;
00329 tranScal = getfloat32(ph->buffer + offset*sizeof(float));
00330 offset++;
00331 } else {
00332 listenerPort = 4141;
00333 }
00334
00335 packtype = ((int*)ph->buffer)[offset++];
00336
00337 ph->buttons = ((int*)ph->buffer)[offset++];
00338 ph->seqnum = ((int*)ph->buffer)[offset++];
00339
00340
00341 buttons = ph->buttons;
00342 incomingIP = inet_ntoa((ph->sockaddr).sin_addr);
00343
00344
00345
00346 if (packtype == EVENT_COMMAND) {
00347
00348
00349
00350
00351
00352 int msgSize = ((int*)ph->buffer)[offset++];
00353
00354
00355
00356 if (msgSize > 0) {
00357 char *tmpmsg = new char[msgSize+1];
00358 memcpy(tmpmsg, ph->buffer+(offset*sizeof(int)), msgSize);
00359 tmpmsg[msgSize] = 0;
00360
00361 commandToSend = tmpmsg;
00362 delete [] tmpmsg;
00363 } else {
00364 commandToSend = "";
00365 }
00366
00367 return 1;
00368 }
00369
00370
00371 padaction = EVENT_NON_TOUCH;
00372
00373
00374
00375
00376
00377
00378
00379 ph->rx = 0;
00380 ph->ry = 0;
00381 ph->rz = 0;
00382 ph->tx = 0;
00383 ph->ty = 0;
00384 ph->tz = 0;
00385 ph->padaction = EVENT_NON_TOUCH;
00386 ph->upid = 0;
00387 memset(ph->touchid, 0, sizeof(ph->touchid));
00388 memset(ph->padx, 0, sizeof(ph->padx));
00389 memset(ph->pady, 0, sizeof(ph->pady));
00390 memset(ph->rotmatrix, 0, sizeof(9*sizeof(float)));
00391
00392
00393 int i;
00394
00395 switch (packtype) {
00396 case PACKET_ORIENT:
00397
00398
00399
00400
00401
00402
00403
00404 ph->rz = ((float*)ph->buffer)[offset ];
00405 ph->rx = ((float*)ph->buffer)[offset+1];
00406 ph->ry = ((float*)ph->buffer)[offset+2];
00407 ph->tx = ((float*)ph->buffer)[offset+3];
00408 ph->ty = ((float*)ph->buffer)[offset+4];
00409 ph->tz = ((float*)ph->buffer)[offset+5];
00410
00411
00412 for (i=0; i<9; i++)
00413 ph->rotmatrix[i] = ((float*)ph->buffer)[offset+6+i];
00414 break;
00415
00416 case PACKET_TOUCH: case PACKET_HEARTBEAT:
00417 float xdpi = ((float*)ph->buffer)[offset];
00418 float ydpi = ((float*)ph->buffer)[offset+1];
00419
00420
00421 float xinvdpi = 1.0f / xdpi;
00422 float yinvdpi = 1.0f / ydpi;
00423
00424
00425
00426
00427 ph->padaction = ((int*) ph->buffer)[offset+4];
00428 ph->upid = ((int*) ph->buffer)[offset+5];
00429
00430 if (ph->padaction == 1) {
00431 ph->touchcnt = touchcnt = 0;
00432 } else {
00433 ph->touchcnt = ((int*) ph->buffer)[offset+6];
00434 touchcnt = ph->touchcnt;
00435
00436 for (int i=0; i<ph->touchcnt; i++) {
00437 float px, py;
00438 #if 0
00439
00440 int ptrid;
00441 ptrid = ((int*) ph->buffer)[offset+7+3*i];
00442 #endif
00443 px = ((float*) ph->buffer)[offset+8+3*i];
00444 py = ((float*) ph->buffer)[offset+9+3*i];
00445
00446
00447
00448
00449 ph->padx[i] = px * xinvdpi;
00450 ph->pady[i] = py * yinvdpi;
00451 }
00452 }
00453
00454
00455 break;
00456 }
00457
00458
00459 if (packtype == PACKET_ORIENT) {
00460 rx = -ph->rx;
00461 ry = -(ph->rz-180);
00462 rz = ph->ry;
00463 tx = 0.0;
00464 ty = 0.0;
00465 tz = 0.0;
00466 }
00467
00468 if (packtype == PACKET_TOUCH) {
00469 padaction = ph->padaction;
00470 upid = ph->upid;
00471
00472 for (int i=0; i<ph->touchcnt; i++) {
00473 padx[i] = ph->padx[i];
00474 pady[i] = ph->pady[i];
00475 }
00476 }
00477
00478 #if 1
00479
00480
00481 float t_null_region = 0.01f;
00482 float r_null_region = 10.0f;
00483 float atx = fabsf(tx);
00484 float aty = fabsf(ty);
00485 float atz = fabsf(tz);
00486 float arx = fabsf(rx);
00487 float ary = fabsf(ry);
00488 float arz = fabsf(rz);
00489
00490
00491 if (atx > t_null_region) {
00492 tx = ((tx > 0) ? (tx - t_null_region) : (tx + t_null_region));
00493 } else {
00494 tx = 0;
00495 }
00496 if (aty > t_null_region) {
00497 ty = ((ty > 0) ? (ty - t_null_region) : (ty + t_null_region));
00498 } else {
00499 ty = 0;
00500 }
00501 if (atz > t_null_region) {
00502 tz = ((tz > 0) ? (tz - t_null_region) : (tz + t_null_region));
00503 } else {
00504 tz = 0;
00505 }
00506 if (arx > r_null_region) {
00507 rx = ((rx > 0) ? (rx - r_null_region) : (rx + r_null_region));
00508 } else {
00509 rx = 0;
00510 }
00511 if (ary > r_null_region) {
00512 ry = ((ry > 0) ? (ry - r_null_region) : (ry + r_null_region));
00513 } else {
00514 ry = 0;
00515 }
00516 if (arz > r_null_region) {
00517 rz = ((rz > 0) ? (rz - r_null_region) : (rz + r_null_region));
00518 } else {
00519 rz = 0;
00520 }
00521 #endif
00522
00523 return 1;
00524 }
00525
00526
00527
00528
00529 static int mobile_listener_destroy(void *voidhandle) {
00530 mobilehandle *ph = (mobilehandle *) voidhandle;
00531
00532 #if defined(_MSC_VER)
00533 closesocket(ph->sockfd);
00534 #else
00535 close(ph->sockfd);
00536 #endif
00537 free(ph);
00538
00539
00540 return 0;
00541 }
00542
00543
00544
00545
00546 Mobile::Mobile(VMDApp *vmdapp) : UIObject(vmdapp) {
00547 mobile = NULL;
00548 port = 3141;
00549
00550 packtimer = wkf_timer_create();
00551 wkf_timer_start(packtimer);
00552
00553 statustimer = wkf_timer_create();
00554 wkf_timer_start(statustimer);
00555
00556
00557 statusSendSeconds = 5.0f;
00558
00559 touchinprogress = 0;
00560 touchcount = 0;
00561 touchmode = ROTATE;
00562 touchscale = 1.0;
00563 touchscalestartdist = 0;
00564 touchrotstartangle = 0;
00565 touchdeltaX = 0;
00566 touchdeltaY = 0;
00567 buttonDown = 0;
00568
00569 tranScaling = 1.0;
00570 rotScaling = 1.0;
00571 zoomScaling = 1.0;
00572
00573 reset();
00574 }
00575
00576
00577
00578 Mobile::~Mobile(void) {
00579 wkf_timer_destroy(packtimer);
00580 wkf_timer_destroy(statustimer);
00581
00582 for (int i=0; i<clientNick.num();i++)
00583 {
00584 delete clientNick[i];
00585 delete clientIP[i];
00586 }
00587
00588
00589
00590
00591
00592
00593
00594 if (mobile != NULL)
00595 mobile_listener_destroy(mobile);
00596 }
00597
00598
00599
00600 int send_dgram(const char *host_addr, int port, const unsigned char *buf,
00601 int buflen) {
00602 struct sockaddr_in addr;
00603 int sockfd;
00604
00605
00606
00607 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00608 return -1;
00609 }
00610
00611 memset(&addr, 0, sizeof(addr));
00612 addr.sin_family = AF_INET;
00613 addr.sin_port = htons(port);
00614 addr.sin_addr.s_addr = inet_addr(host_addr);
00615
00616 #if defined(_MSC_VER)
00617 sendto(sockfd, (const char *) buf, buflen, 0, (struct sockaddr *)&addr, sizeof(addr));
00618 closesocket(sockfd);
00619 #else
00620 sendto(sockfd, buf, buflen, 0, (struct sockaddr *)&addr, sizeof(addr));
00621 close(sockfd);
00622 #endif
00623
00624 return 0;
00625 }
00626
00627
00628
00629 void Mobile::sendStatus(const int eventType) {
00630 prepareSendBuffer(eventType);
00631
00632
00633 for (int i=0; i< clientIP.num(); i++) {
00634
00635
00636 int active = (clientActive[i] ? 1 : 0);
00637 memcpy(statusSendBuffer + 16, &active, sizeof(int));
00638
00639
00640 send_dgram((const char *)*(clientIP[i]), clientListenerPort[i],
00641 statusSendBuffer, statusSendBufferLength);
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651 wkf_timer_start(statustimer);
00652 }
00653
00654
00655
00656 void Mobile::checkAndSendStatus() {
00657 if (wkf_timer_timenow(statustimer) > statusSendSeconds) {
00658 sendStatus(SEND_HEARTBEAT);
00659 }
00660 }
00661
00662
00663
00664
00665 bool Mobile::isInControl(JString* nick, JString* ip, const int port, const int packtype) {
00666
00667 int i;
00668 for (i=0; i < clientNick.num(); i++) {
00669 if (*nick == *(clientNick[i]) && *ip == *(clientIP[i])) {
00670
00671 break;
00672 }
00673 }
00674
00675 if (i < clientNick.num()) {
00676
00677 if (packtype == PACKET_DISCONNECT) {
00678 removeClient(i);
00679 return false;
00680 }
00681 return clientActive[i];
00682 } else {
00683 JString *tmpNick, *tmpIp;
00684 tmpNick = new JString(*nick);
00685 tmpIp = new JString(*ip);
00686
00687
00688 if (clientNick.num() == 0) {
00689 addNewClient(tmpNick, tmpIp, port, true);
00690 return true;
00691 } else {
00692 addNewClient(tmpNick, tmpIp, port, false);
00693 return false;
00694 }
00695 }
00696
00697 return false;
00698 }
00699
00700
00701
00703
00704
00705 void Mobile::reset(void) {
00706
00707 move_mode(OFF);
00708
00709
00710 set_max_stride(20);
00711
00712
00713
00714 transInc = 1.0f / 25000.0f;
00715 rotInc = 1.0f / 200.0f;
00716 scaleInc = 1.0f / 25000.0f;
00717 animInc = 1.0f / 1.0f;
00718 }
00719
00720
00721
00722
00723
00724
00725
00726 int Mobile::act_on_command(int type, Command *cmd) {
00727 return FALSE;
00728 }
00729
00730
00731
00732
00733
00734 int Mobile::check_event(void) {
00735 float tx, ty, tz, rx, ry, rz;
00736 int touchid[16];
00737 float padx[16], pady[16];
00738
00739 int padaction, upid, buttons, touchcnt;
00740 int buttonchanged;
00741 int win_event=FALSE;
00742 int packtype=0;
00743 JString incIP, nick, commandToSend;
00744
00745
00746 int clientPort=0;
00747
00748
00749
00750
00751
00752
00753 checkAndSendStatus();
00754
00755
00756 rx=ry=rz=tx=ty=tz=0.0f;
00757 buttons=padaction=upid=0;
00758 memset(touchid, 0, sizeof(touchid));
00759 memset(padx, 0, sizeof(padx));
00760 memset(pady, 0, sizeof(pady));
00761 touchcnt=0;
00762
00763
00764 while (moveMode != OFF &&
00765 mobile_listener_poll(mobile, rx, ry, rz, tx, ty, tz, padaction, upid,
00766 touchcnt, touchid, padx, pady, buttons, packtype,
00767 incIP, nick, clientPort, tranScaling, rotScaling,
00768 zoomScaling, commandToSend)) {
00769
00770 win_event = TRUE;
00771
00772
00773
00774 if (packtype == EVENT_COMMAND) {
00775
00776
00777 char strTmp[11];
00778 sprintf(strTmp, "%d",buttons);
00779 JString jstr = "{" + nick + "} {" + incIP + "} {" + strTmp +
00780 "} {" + commandToSend + "}";
00781
00782
00783 runcommand(new MobileDeviceCommandEvent(jstr));
00784 break;
00785 }
00786
00787
00788
00789 if (isInControl(&nick, &incIP, clientPort, packtype)) {
00790 DisplayDevice::EventCodes keydev=DisplayDevice::WIN_KBD;
00791
00792
00793
00794 buttonchanged = buttons ^ buttonDown;
00795
00796
00797 if (buttonchanged) {
00798
00799 if (buttonchanged == (1<<0) && (buttonchanged & buttons)) {
00800 runcommand(new UserKeyEvent(keydev, '0', (int) DisplayDevice::AUX));
00801 }
00802 if (buttonchanged == (1<<1) && (buttonchanged & buttons)) {
00803 runcommand(new UserKeyEvent(keydev, '1', (int) DisplayDevice::AUX));
00804 }
00805 if (buttonchanged == (1<<2) && (buttonchanged & buttons)) {
00806 runcommand(new UserKeyEvent(keydev, '2', (int) DisplayDevice::AUX));
00807 }
00808 if (buttonchanged == (1<<3) && (buttonchanged & buttons)) {
00809 runcommand(new UserKeyEvent(keydev, '3', (int) DisplayDevice::AUX));
00810 }
00811 }
00812
00813 #if 0
00814 printf("Touchpad action: %d upid %d", padaction, upid);
00815 for (int i=0; i<touchcnt; i++) {
00816 printf("ID[%d] x: %.2f y: %.2f ",
00817 i, padx[i], pady[i]);
00818 }
00819 printf("\n");
00820 #endif
00821
00822 if (padaction != EVENT_NON_TOUCH) {
00823
00824 if (touchcnt < touchcount ||
00825 padaction == EVENT_TOUCH_UP || padaction == EVENT_TOUCH_SOMEUP) {
00826
00827 touchinprogress = 0;
00828 touchmode = ROTATE;
00829 touchcount = 0;
00830 touchstartX = 0;
00831 touchstartY = 0;
00832 touchdeltaX = 0;
00833 touchdeltaY = 0;
00834 touchscale = 1.0;
00835 touchscalestartdist = 0;
00836 touchrotstartangle = 0;
00837 }
00838
00839
00840 if (touchcnt > touchcount ||
00841 padaction == EVENT_TOUCH_DOWN ||
00842 padaction == EVENT_TOUCH_SOMEDOWN) {
00843
00844 touchcount = touchcnt;
00845 touchstartX = 0;
00846 touchstartY = 0;
00847 touchdeltaX = 0;
00848 touchdeltaY = 0;
00849 touchscale = 1.0;
00850 touchscalestartdist = 0;
00851 touchrotstartangle = 0;
00852
00853
00854 if (touchcount == 1) {
00855
00856 touchinprogress=1;
00857 touchmode = ROTATE;
00858 touchstartX = padx[0];
00859 touchstartY = pady[0];
00860 } else if (touchcount == 2) {
00861 touchinprogress=1;
00862 touchstartX = (padx[0] + padx[1]) * 0.5f;
00863 touchstartY = (pady[0] + pady[1]) * 0.5f;
00864
00865 float dx = padx[1] - padx[0];
00866 float dy = pady[1] - pady[0];
00867 touchscalestartdist = sqrtf(dx*dx + dy*dy) + 0.00001f;
00868 if (touchscalestartdist > 0.65f) {
00869 touchrotstartangle = float(atan2(dx, -dy) + VMD_PI);
00870
00871 touchmode = SCALEROTZ;
00872 } else {
00873
00874 touchmode = TRANSLATE;
00875 }
00876 }
00877 }
00878
00879 if (touchinprogress && padaction == EVENT_TOUCH_MOVE) {
00880 if (touchmode == ROTATE) {
00881 touchdeltaX = padx[0] - touchstartX;
00882 touchdeltaY = pady[0] - touchstartY;
00883 } else if (touchmode == SCALEROTZ) {
00884
00885
00886 if (moveMode == MOVE) {
00887 float dx = padx[1] - padx[0];
00888 float dy = pady[1] - pady[0];
00889 float dist = sqrtf(dx*dx + dy*dy);
00890
00891
00892 float newscale = (dist / touchscalestartdist) / touchscale;
00893 if (fabsf(newscale - 1.0f) > 0.01f) {
00894 touchscale *= newscale;
00895 app->scene_scale_by((newscale - 1.0f) * zoomScaling + 1.0f);
00896 }
00897
00898
00899
00900
00901
00902 float newrotangle = float(atan2(dx, -dy) + VMD_PI);
00903 float rotby = float((newrotangle-touchrotstartangle)*180.0f/VMD_PI);
00904 if (fabsf(rotby) > 0.25f) {
00905 app->scene_rotate_by(-rotScaling*rotby, 'z');
00906 touchrotstartangle=newrotangle;
00907 }
00908 }
00909 } else if (touchmode == TRANSLATE) {
00910 touchdeltaX = ((padx[0]+padx[1])*0.5f) - touchstartX;
00911 touchdeltaY = ((pady[0]+pady[1])*0.5f) - touchstartY;
00912 }
00913 }
00914 }
00915
00916
00917 buttonDown = buttons;
00918 }
00919
00920
00921 wkf_timer_start(packtimer);
00922 }
00923
00924
00925
00926
00927
00928
00929 if (!win_event && wkf_timer_timenow(packtimer) > 3.0) {
00930 touchinprogress = 0;
00931 touchmode = ROTATE;
00932 touchcount = 0;
00933 touchstartX = 0;
00934 touchstartY = 0;
00935 touchdeltaX = 0;
00936 touchdeltaY = 0;
00937 touchscalestartdist = 0;
00938 touchrotstartangle = 0;
00939 }
00940
00941 if (touchinprogress) {
00942 if (moveMode == MOVE) {
00943 if (touchmode == ROTATE) {
00944
00945
00946 app->scene_rotate_by(touchdeltaY*rotScaling*0.5f, 'x');
00947 app->scene_rotate_by(touchdeltaX*rotScaling*0.5f, 'y');
00948 } else if (touchmode == TRANSLATE) {
00949 app->scene_translate_by(touchdeltaX*tranScaling*0.005f, -touchdeltaY*tranScaling*0.005f, 0.0f);
00950 }
00951 } else if (moveMode == ANIMATE) {
00952 if (fabsf(touchdeltaX) > 0.25f) {
00953 #if 0
00954
00955 float speed = fabsf(expf(fabsf((fabsf(touchdeltaX) * animInc) / 1.7f))) - 1.0f;
00956 #else
00957
00958 float speed = fabsf(touchdeltaX) * animInc;
00959 #endif
00960
00961 if (speed > 0) {
00962 if (speed < 1.0)
00963 app->animation_set_speed(speed);
00964 else
00965 app->animation_set_speed(1.0f);
00966
00967 int stride = 1;
00968 if (fabs(speed - 1.0) > (double) maxstride)
00969 stride = maxstride;
00970 else
00971 stride = 1 + (int) fabs(speed-1.0);
00972 if (stride < 1)
00973 stride = 1;
00974 app->animation_set_stride(stride);
00975
00976 if (touchdeltaX > 0) {
00977 app->animation_set_dir(Animation::ANIM_FORWARD1);
00978 } else {
00979 app->animation_set_dir(Animation::ANIM_REVERSE1);
00980 }
00981 } else {
00982 app->animation_set_dir(Animation::ANIM_PAUSE);
00983 app->animation_set_speed(1.0f);
00984 }
00985 } else {
00986 app->animation_set_dir(Animation::ANIM_PAUSE);
00987 app->animation_set_speed(1.0f);
00988 }
00989 }
00990 }
00991
00992
00993
00994
00995
00996 if (win_event) {
00997 return TRUE;
00998 } else {
00999 return FALSE;
01000 }
01001 }
01002
01003
01004
01005
01007
01008 const char* Mobile::get_mode_str(MoveMode mm) {
01009 const char* modestr;
01010
01011 switch (mm) {
01012 default:
01013 case OFF: modestr = "off"; break;
01014 case MOVE: modestr = "move"; break;
01015 case ANIMATE: modestr = "animate"; break;
01016 case TRACKER: modestr = "tracker"; break;
01017 case USER: modestr = "user"; break;
01018 }
01019
01020 return modestr;
01021 }
01022
01023
01024 int Mobile::get_port () {
01025 return port;
01026 }
01027
01028
01029 int Mobile::get_APIsupported () {
01030 return CURRENTAPIVERSION;
01031 }
01032
01033
01034 int Mobile::get_move_mode () {
01035 return moveMode;
01036 }
01037
01038
01039 void Mobile::get_client_list (ResizeArray <JString*>* &nick,
01040 ResizeArray <JString*>* &ip, ResizeArray <bool>* &active)
01041 {
01042 nick = &clientNick;
01043 ip = &clientIP;
01044 active = &clientActive;
01045 }
01046
01047
01048 int Mobile::sendMsgToClient(const char *nick, const char *ip,
01049 const char *msgType, const char *msg)
01050 {
01051
01052
01053 bool found = false;
01054 int i;
01055 for (i=0; i<clientNick.num();i++)
01056 {
01057 if (*(clientNick[i]) == nick) {
01058
01059 if (*(clientIP[i]) == ip) {
01060 found = true;
01061 break;
01062 }
01063 }
01064 }
01065
01066 if (found) {
01067 int msgTypeAsInt;
01068 if (EOF == sscanf(msgType, "%d", &msgTypeAsInt)) {
01069 return false;
01070 }
01071
01072 sendMsgToIp(clientActive[i],
01073 msgTypeAsInt,
01074 msg,
01075 (const char *)*(clientIP[i]),
01076 clientListenerPort[i]);
01077 return true;
01078 } else {
01079 return false;
01080 }
01081 }
01082
01083
01084
01085 void Mobile::sendMsgToIp(const bool isActive,
01086 const int msgTypeAsInt,
01087 const char *msg,
01088 const char *ip,
01089 const int port)
01090 {
01091
01092 prepareSendBuffer(SEND_MESSAGE);
01093
01094
01095 int active = (isActive ? 1 : 0);
01096 memcpy(statusSendBuffer + 16, &active, sizeof(int));
01097
01098
01099 int length = statusSendBufferLength;
01100
01101
01102 memcpy(statusSendBuffer + length, &msgTypeAsInt, sizeof(int));
01103 length += sizeof(int);
01104
01105 int msgLength = strlen(msg);
01106
01107
01108 memcpy((statusSendBuffer + length), &msgLength, sizeof(int));
01109 length += sizeof(int);
01110
01111 memcpy((statusSendBuffer + length), msg, msgLength);
01112 length += msgLength;
01113
01114 send_dgram(ip, port, statusSendBuffer, length);
01115
01116 }
01117
01118
01119
01120 int Mobile::set_activeClient(const char *nick, const char *ip) {
01121
01122
01123 bool found = false;
01124 int i;
01125 for (i=0; i<clientNick.num();i++) {
01126 if (*(clientNick[i]) == nick) {
01127
01128 if (*(clientIP[i]) == ip) {
01129 found = true;
01130 break;
01131 }
01132 }
01133 }
01134
01135 if (found) {
01136
01137 for (int j=0; j<clientActive.num();j++) {
01138 clientActive[j] = false;
01139 }
01140
01141
01142 touchinprogress = 0;
01143 touchmode = ROTATE;
01144 touchcount = 0;
01145 touchstartX = 0;
01146 touchstartY = 0;
01147 touchdeltaX = 0;
01148 touchdeltaY = 0;
01149 touchscalestartdist = 0;
01150 touchrotstartangle = 0;
01151
01152
01153 clientActive[i] = true;
01154
01155 sendStatus(SEND_SETACTIVECLIENT);
01156 return true;
01157 } else {
01158 return false;
01159 }
01160 }
01161
01162
01163
01164 void Mobile::get_tracker_status(float &tx, float &ty, float &tz,
01165 float &rx, float &ry, float &rz,
01166 int &buttons) {
01167 tx = trtx * transInc;
01168 ty = trty * transInc;
01169 tz = -trtz * transInc;
01170 rx = trrx * rotInc;
01171 ry = trry * rotInc;
01172 rz = -trrz * rotInc;
01173 buttons = trbuttons;
01174 }
01175
01176
01177
01178
01179 int Mobile::move_mode(MoveMode mm) {
01180
01181 moveMode = mm;
01182
01183 if (moveMode != OFF && !mobile) {
01184 mobile = mobile_listener_create(port);
01185 if (mobile == NULL) {
01186 msgErr << "Failed to open mobile port " << port
01187 << ", move mode disabled" << sendmsg;
01188 moveMode = OFF;
01189 } else {
01190 msgInfo << "Opened mobile port " << port << sendmsg;
01191 }
01192 }
01193
01194
01195 if (moveMode == OFF && mobile) {
01196 mobile_listener_destroy(mobile);
01197 mobile = 0;
01198 removeAllClients();
01199 }
01200
01201
01202 if (moveMode != TRACKER) {
01203 trtx=trty=trtz=trrx=trry=trrz=0.0f;
01204 trbuttons=0;
01205 }
01206
01207 runcommand(new MobileStateChangedEvent());
01208 sendStatus(SEND_SETMODE);
01209
01210 return TRUE;
01211 }
01212
01213
01214
01215
01216 int Mobile::network_port(int newport) {
01217 if (mobile != NULL) {
01218 mobile_listener_destroy(mobile);
01219 removeAllClients();
01220 }
01221
01222 if (moveMode != OFF) {
01223 mobile = mobile_listener_create(newport);
01224 if (mobile == NULL) {
01225 msgErr << "Failed to open mobile port " << newport
01226 << ", move mode disabled" << sendmsg;
01227 moveMode = OFF;
01228 } else {
01229 port = newport;
01230
01231 msgInfo << "Opened mobile port " << port << sendmsg;
01232 }
01233 runcommand(new MobileStateChangedEvent());
01234 } else {
01235 port = newport;
01236 }
01237
01238 return TRUE;
01239 }
01240
01241
01242
01243 int Mobile::addNewClient(JString* nick, JString* ip, const int port, const bool active) {
01244
01245 clientNick.append(nick);
01246 clientIP.append(ip);
01247 clientListenerPort.append(port);
01248 clientActive.append(active);
01249
01250
01251 runcommand(new MobileStateChangedEvent());
01252 sendStatus(SEND_ADDCLIENT);
01253 return 0;
01254 }
01255
01256
01257
01258 void Mobile::removeAllClients() {
01259 while (clientNick.num() > 0) {
01260 removeClient(0);
01261 }
01262 }
01263
01264
01265
01266 int Mobile::removeClient(const int num) {
01267 delete clientNick[num];
01268 clientNick.remove(num);
01269 delete clientIP[num];
01270 clientIP.remove(num);
01271 clientActive.remove(num);
01272 clientListenerPort.remove(num);
01273
01274
01275 int iCount;
01276 for (iCount=0; iCount<clientActive.num(); iCount++) {
01277 if (clientActive[iCount]) {
01278 break;
01279 }
01280 }
01281
01282
01283
01284
01285 if (iCount == clientActive.num() && clientActive.num() > 0) {
01286 clientActive[0] = true;
01287 }
01288
01289
01290 runcommand(new MobileStateChangedEvent());
01291 sendStatus(SEND_REMOVECLIENT);
01292
01293 return 0;
01294 }
01295
01296
01297