diff --git a/NOMADVRLib/ConfigFile.cpp b/NOMADVRLib/ConfigFile.cpp index 365a442dfd7fb7e3466eb6f1f6acca4029180ca8..c776ea4b83d1f578317aaf136dc9a078e1425409 100644 --- a/NOMADVRLib/ConfigFile.cpp +++ b/NOMADVRLib/ConfigFile.cpp @@ -86,6 +86,8 @@ int secret; const char * server; int port; +bool resetTimestepOnReload; + const char * loadConfigFileErrors[] = { "All Ok",//0 @@ -115,12 +117,34 @@ const char * loadConfigFileErrors[] = "Error loading analytics json file, add 400 to see the error",//<-400 }; +void cleanMarkers() +{ + for (int i=0;i<TIMESTEPS;i++) + delete markers[i]; + delete[] markers; + markers=nullptr; +} + +void cleanMarkerColours() { + for (int i=0;i<TIMESTEPS;i++) + delete markercolours[i]; + delete[] markercolours; + markercolours=nullptr; +} + void updateTIMESTEPS (int timesteps) { -if (TIMESTEPS==0) +if (TIMESTEPS==0) { TIMESTEPS=timesteps; -else - TIMESTEPS=std::min(TIMESTEPS, timesteps); +} else { + if (TIMESTEPS!=timesteps) { + if (markers) + cleanMarkers(); + if (markercolours) + cleanMarkerColours(); + TIMESTEPS=std::min(TIMESTEPS, timesteps); + } +} } int readString(FILE *f, char *s) @@ -155,6 +179,9 @@ int readString(FILE *f, char *s) void fixFile(char * file) { +if (!strncmp (file, "http://", 7) || !strncmp(file, "https://", 8)) + return; + #ifdef WIN32 const char c='\\'; #else @@ -190,13 +217,11 @@ void cleanConfig() SCREENSHOT=nullptr; if (markers) { + cleanMarkers(); for (int i=0;i<TIMESTEPS;i++) { - delete[] markers[i]; delete[] markercolours[i]; } - delete[] markers; delete[] markercolours; - markers=nullptr; markercolours=nullptr; } for (int i=0;i<info.size();i++) { @@ -301,8 +326,10 @@ void initState() secret=0; server=nullptr; port=-1; + resetTimestepOnReload=true; } + int loadConfigFile(const char * f) { //default values @@ -335,10 +362,7 @@ int loadConfigFile(const char * f) if (!strcmp(s, "timesteps")) { int timesteps; r = fscanf(F, "%d", ×teps); - if (TIMESTEPS==0) - TIMESTEPS=timesteps; - else - TIMESTEPS=std::min(TIMESTEPS, timesteps); + updateTIMESTEPS(timesteps); } else if (!strcmp(s, "isos")) { if (ISOS!=0) @@ -572,6 +596,8 @@ int loadConfigFile(const char * f) fclose(F); return -17; } + if (markers) + cleanMarkers(); markers=new float* [TIMESTEPS]; for (int i=0;i<TIMESTEPS;i++) { markers[i]=new float[3]; @@ -755,6 +781,8 @@ int loadConfigFile(const char * f) #endif } else if (!strcmp (s, "\x0d")) { //discard windows newline (problem in Sebastian Kokott's phone (?!) continue; + } else if (!strcmp (s, "disablereloadreset")) { + resetTimestepOnReload=false; } else if (!strcmp (s, "server")) { //multiuser support int r; if (server) diff --git a/NOMADVRLib/ConfigFile.h b/NOMADVRLib/ConfigFile.h index bf252fe11b9eda10e8d381b383da2aff9536d138..8c7fe0211cfe7e88a91a20a2647061b434c5da72 100644 --- a/NOMADVRLib/ConfigFile.h +++ b/NOMADVRLib/ConfigFile.h @@ -88,6 +88,8 @@ extern int secret; extern const char * server; extern int port; +extern bool resetTimestepOnReload; + struct information { float pos[3]; float size; diff --git a/NOMADVRLib/Grid.cpp b/NOMADVRLib/Grid.cpp index cc217c4723c4e080f0b9c41271ab5657733d605b..0437b2bfc5bdecfe7158658075e76d08cd8443fb 100644 --- a/NOMADVRLib/Grid.cpp +++ b/NOMADVRLib/Grid.cpp @@ -38,7 +38,7 @@ grid::~grid() void grid::coordinates(const float pos[3], int c[3]) { for (int i=0;i<3;i++) { - c[i]=floor((pos[i]-m[i])/dif[i]*dims); + c[i]=static_cast<int>(floor((pos[i]-m[i])/dif[i]*dims)); if (c[i]>=dims) c[i]=dims-1; else if (c[i]<0) @@ -52,7 +52,7 @@ void grid::add (float *p) //compatible with the atoms xyzr coordinates (p, pos); content[pos[0]*dims*dims + pos[1]*dims+pos[2]].push_back(p); - float ar=atomRadius(p[3]); + float ar=atomRadius(static_cast<int>(p[3])); if (ar>maxradius) maxradius=ar; } @@ -61,7 +61,7 @@ bool grid::compare (float *a, float *b) { if (a<=b) //already returned when searching a beforehand return false; - float sqd=atomRadius(a[3])+atomRadius(b[3]); + float sqd=atomRadius(static_cast<int>(a[3]))+atomRadius(static_cast<int>(b[3])); sqd*=sqd; float d=0; for (int i=0;i<3;i++) @@ -82,8 +82,8 @@ std::vector<float*> grid::find (float *p) float mp[3]; float Mp[3]; for (int i=0;i<3;i++) { - mp[i]=p[i]-(atomRadius(p[3])+maxradius)/scale; - Mp[i]=p[i]+(atomRadius(p[3])+maxradius)/scale; + mp[i]=p[i]-(atomRadius(static_cast<int>(p[3]))+maxradius)/scale; + Mp[i]=p[i]+(atomRadius(static_cast<int>(p[3]))+maxradius)/scale; } coordinates(mp, mc); coordinates(Mp, Mc); diff --git a/NOMADVRLib/atoms.cpp b/NOMADVRLib/atoms.cpp index 6876f4931d0ed45dd5f4ef35d3561cc490a1b3c4..679f588d476d7b49655886fcaf425188f7a0a8fc 100644 --- a/NOMADVRLib/atoms.cpp +++ b/NOMADVRLib/atoms.cpp @@ -227,7 +227,7 @@ int findAtom(const char *const s) strcpy (x, s); char *p=x+strlen(x); p--; - while (*p > '0' && *p <= '9') { + while (*p >= '0' && *p <= '9') { *p='\0'; *p--; if (p==x) @@ -260,7 +260,8 @@ const char * readAtomsXYZErrors[] = { "Could not open file", //-1 "Error loading atom type and position line", //-2 "Atom type unknown", //-3 - "Corrupt xyz file" //-4 + "Corrupt xyz file", //-4 + "Unable to download xyz file" //-5 }; void cleanAtoms (int **numatoms, int timesteps, float ***pos) @@ -276,10 +277,27 @@ void cleanAtoms (int **numatoms, int timesteps, float ***pos) int readAtomsXYZ(const char *const file, int **numatoms, int *timesteps, float ***pos) { + const char *myfile=nullptr; + const char *webdownload="material.xyz"; + //add http support + if (!strncmp(file, "http:", 5) || !strncmp(file, "https:", 6)) { + char cmd[2048]; + int ret; + sprintf (cmd, "wget %s -O %s", file, webdownload); + ret=system(cmd); + if (ret!=0) { + *numatoms=nullptr; + *pos=nullptr; + return (-5); + } + myfile=webdownload; + } else { + myfile = file; + } int mynumatoms; std::vector<float*> mypos; std::vector<int> mynum; - FILE *f=fopen (file, "r"); + FILE *f=fopen (myfile, "r"); int r; char s[100]; if (f==0) { @@ -294,6 +312,7 @@ int readAtomsXYZ(const char *const file, int **numatoms, int *timesteps, float * blanklines++; if (blanklines>3) { eprintf("Corrupt xyz file %s. Error at %d atoms\n", file, mynumatoms); + fclose(f); return -4; } continue; //there may be a blank line at the end of the file @@ -311,8 +330,10 @@ int readAtomsXYZ(const char *const file, int **numatoms, int *timesteps, float * char line[512]; fgets(line, 512, f); r=sscanf (line, "%s %f %f %f %f", s, mypos.back()+4*i+0, mypos.back()+4*i+1,mypos.back()+4*i+2, &unused); - if (r<4) + if (r<4) { + fclose (f); return -2; + } int a=findAtom(s); if (a==-1) { eprintf ("Read atoms xyz, atom type unknown: %s", s); @@ -331,7 +352,7 @@ int readAtomsXYZ(const char *const file, int **numatoms, int *timesteps, float * (*numatoms)[i]=mynum[i]; //eprintf ("Getting atoms, numatoms=%d",(*numatoms)[i]); } - + fclose (f); return 0; } @@ -367,9 +388,10 @@ int readAtomsCube(const char *const file, int **numatoms, int *timesteps, float discardline(f); //two comments discardline(f); r = fscanf(f, "%d %f %f %f", *numatoms, cubetrans + 0, cubetrans + 1, cubetrans + 2); - if (r < 4) + if (r < 4) { + fclose (f); return -2; - + } //rgh FIXME. Is this always bohr? for (int i=0;i<3;i++) cubetrans[i]*= 0.52918f; diff --git a/NOMADVRLib/atomsGL.cpp b/NOMADVRLib/atomsGL.cpp index 6c20dee2a10f701476430cd60adc40bec2c7bfe0..6efdd99a083e211d03de16c04eb1021c0b7c3c89 100644 --- a/NOMADVRLib/atomsGL.cpp +++ b/NOMADVRLib/atomsGL.cpp @@ -227,6 +227,9 @@ void CleanAtoms (GLuint **AtomVAO /*[4]*/, GLuint **AtomVertBuffer /*[3]*/, GLui if (!numAtoms) return; + if (*AtomVAO==nullptr) + return; + glDeleteVertexArrays(4, *AtomVAO); glDeleteBuffers(3, *AtomVertBuffer); glDeleteBuffers(1, BondIndices); @@ -764,6 +767,7 @@ GLenum SetupUnitCell(GLuint *UnitCellVAO, GLuint *UnitCellVertBuffer, GLuint *Un if ((e = glGetError()) != GL_NO_ERROR) eprintf( "opengl error %d, glBufferData index, l %d\n", e, __LINE__); glBindVertexArray(0); + delete[] tmp; return e; } diff --git a/OpenVR/TimestepData/hellovr_opengl_main.cpp b/OpenVR/TimestepData/hellovr_opengl_main.cpp index 2bc4e31e6e9184a8a8bb74637a55696f383561e6..c4b8831e13f2e508aad17cd845ddd907a422b7fc 100644 --- a/OpenVR/TimestepData/hellovr_opengl_main.cpp +++ b/OpenVR/TimestepData/hellovr_opengl_main.cpp @@ -351,6 +351,7 @@ private: // OpenGL bookkeeping char *pixels, *pixels2; //for saving screenshots to disk int framecounter; bool savetodisk; + bool showInfoBox; int selectedAtom; @@ -370,7 +371,7 @@ private: // OpenGL bookkeeping void UDP(); int UDPContr(SOCKET s, char c, int device); int UDPHead(SOCKET s); - int sock, s; + SOCKET sock, s; struct sockaddr_in serv_addr; void Send(char c, int32_t value); void Send(char c, bool value); @@ -417,6 +418,10 @@ void dprintf( const char *fmt, ... ) SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Warning", buffer, 0); } +void message (char *buffer) +{ +MessageBoxA (0, buffer, "Warning", 0); +} //pure windows, no sdl void eprintf( const char *fmt, ... ) @@ -439,7 +444,7 @@ void eprintf( const char *fmt, ... ) if ( g_bPrintf ) printf( "%s", buffer ); - MessageBoxA(0, buffer, "Warning", 0); + std::thread(message, buffer).detach(); } int CMainApplication::LoadConfigFile (const char *c) @@ -689,7 +694,10 @@ void CMainApplication::connectTCP() eprintf ("short read at socket\n"); return; } - currentset=ntohl(tmp)%TIMESTEPS; + if (TIMESTEPS!=0) + currentset=ntohl(tmp)%TIMESTEPS; + else + currentset=ntohl(tmp); break; case 'i': n=recv (sock, (char*)&tmp, sizeof(tmp), 0); @@ -726,13 +734,6 @@ void CMainApplication::connectTCP() std::unique_lock<std::mutex> lk(cleanupmutex); cleanupcond.wait(lk); - //OpenGL commands only in main thread - //CleanScene(); - //LoadConfigFile(myargv[currentConfig]); - //SetupScene(); - //cleanupmutex.lock(); - //cleanup=0; - //cleanupmutex.unlock(); } break; case 'X': @@ -850,6 +851,8 @@ CMainApplication::CMainApplication(int argc, char *argv[]) , identifier(0) , whenDrag (3) , cleanup (0) + , showInfoBox (true) + , m_unInfoVAO (0) { LoadConfigFile(argv[currentConfig]); for (int j=0;j<3;j++) @@ -1134,6 +1137,7 @@ void CMainApplication::Shutdown() if (tcpconn) { closesocket(sock); sock=INVALID_SOCKET; + cleanupcond.notify_one(); //in case we are waiting for update tcpconn->join(); delete tcpconn; tcpconn=nullptr; @@ -1357,7 +1361,11 @@ void CMainApplication::Send(char c, bool value) void CMainApplication::SendConfigFile() { - Send('n', currentConfig); + if (sock != INVALID_SOCKET) { + Send('n', currentConfig); + } else {//notify for local execution + cleanup=1; + } } void CMainApplication::SendTimestep() @@ -1501,19 +1509,12 @@ bool CMainApplication::HandleInput() if (currentConfig>=myargc) currentConfig=1; SendConfigFile(); - //we will soon receive an order to reload the scene, so avoid double-reloading + race here - //CleanScene(); - //LoadConfigFile(myargv[currentConfig]); - //SetupScene(); } else if (state.rAxis[0].y < -0.7 && state.rAxis[0].x > -0.4 && state.rAxis[0].x < 0.4) { //prev config file currentConfig--; if (currentConfig<=0) currentConfig=myargc-1; SendConfigFile(); - //CleanScene(); - //LoadConfigFile(myargv[currentConfig]); - //SetupScene(); } } } else { //Drag and Drop @@ -1552,8 +1553,12 @@ bool CMainApplication::HandleInput() else if(unDevice !=firstdevice && seconddevice==-1) seconddevice=unDevice; */ - if (firstdevice==unDevice) - savetodisk = !savetodisk; + if (firstdevice==unDevice) { + if (menubutton==Record) + savetodisk = !savetodisk; + else if (menubutton==Infobox) + showInfoBox= !showInfoBox; + } else { showAtoms= !showAtoms; SendShowAtoms(); @@ -1793,7 +1798,6 @@ void CMainApplication::RenderFrame() cleanup=0; cleanupmutex.unlock(); cleanupcond.notify_one(); - //return; } int e; @@ -2089,7 +2093,8 @@ void CMainApplication::CleanScene() CleanMarker(&m_unMarkerVAO, &m_glMarkerVertBuffer); } //infocube - ::CleanInfoCube(&m_unInfoVAO, &m_unInfoVertBuffer, &m_unInfoIndexBuffer); + if (m_unInfoVAO != 0) + ::CleanInfoCube(&m_unInfoVAO, &m_unInfoVertBuffer, &m_unInfoIndexBuffer); cleanConfig(); ISOS=0; } @@ -2108,6 +2113,14 @@ void CMainApplication::SetupScene() SetupInfoCube(); movementspeed/=scaling; SetupInfoBoxTexture(); + SetupCameras(); //near and far plane may have changed + if (resetTimestepOnReload) { + currentset=0; + currentiso=ISOS; + UserPosition=Vector3(-userpos[0], -userpos[1], -userpos[2]); + SendUserPos(); + selectedAtom=-1; + } } void CMainApplication::SetupInfoCube() @@ -2155,7 +2168,7 @@ Matrix4 i = matDeviceToTracking; Matrix4 trans; -Vector3 iPos = (*pos)+Vector3(0,0.02,0); //raise glyph +Vector3 iPos = (*pos)+Vector3(0.0f,0.02f,0.0f); //raise glyph int e; trans.scale(0.05).translate(iPos); //translate(0,0.1,0); @@ -2178,31 +2191,31 @@ return true; void FillVerticesGlyph (float * const vert, const int i, const float u) { for (int j=0;j<4;j++) { - vert[i*9*4+j*9+2]=0; //z - vert[i*9*4+j*9+3]=1; //w - vert[i*9*4+j*9+4]=0; //nx - vert[i*9*4+j*9+5]=0; //ny - vert[i*9*4+j*9+6]=-1; //nz - } - vert [i*9*4+0*9+0]=i+0; //x - vert [i*9*4+0*9+1]=0; //y + vert[i*9*4+j*9+2]=0.0f; //z + vert[i*9*4+j*9+3]=1.0f; //w + vert[i*9*4+j*9+4]=0.0f; //nx + vert[i*9*4+j*9+5]=0.0f; //ny + vert[i*9*4+j*9+6]=-1.0f; //nz + } + vert [i*9*4+0*9+0]=static_cast<float>(i+0); //x + vert [i*9*4+0*9+1]=0.0f; //y vert [i*9*4+0*9+7]=u; //u - vert [i*9*4+0*9+8]=1; //v + vert [i*9*4+0*9+8]=1.0f; //v - vert [i*9*4+1*9+0]=i+1; //x - vert [i*9*4+1*9+1]=0; //y + vert [i*9*4+1*9+0]=static_cast<float>(i+1); //x + vert [i*9*4+1*9+1]=0.0f; //y vert [i*9*4+1*9+7]=u+1.0f/16.0f; //u - vert [i*9*4+1*9+8]=1; //v + vert [i*9*4+1*9+8]=1.0f; //v - vert [i*9*4+2*9+0]=i+0; //x - vert [i*9*4+2*9+1]=1; //y + vert [i*9*4+2*9+0]=static_cast<float>(i+0); //x + vert [i*9*4+2*9+1]=1.0f; //y vert [i*9*4+2*9+7]=u; //u - vert [i*9*4+2*9+8]=0; //v + vert [i*9*4+2*9+8]=0.0f; //v - vert [i*9*4+3*9+0]=i+1; //x - vert [i*9*4+3*9+1]=1; //y + vert [i*9*4+3*9+0]=static_cast<float>(i+1); //x + vert [i*9*4+3*9+1]=1.0f; //y vert [i*9*4+3*9+7]=u+1.0f/16.0f; //u - vert [i*9*4+3*9+8]=0; //v + vert [i*9*4+3*9+8]=0.0f; //v } short int *FillIndicesGlyph (int l) @@ -2303,7 +2316,7 @@ void CMainApplication::RenderControllerGlyph (const vr::Hmd_Eye nEye, const int SendDragDrop(pos); } - if (selectedAtom==-1) { //isos + if (selectedAtom==-1 || numAtoms==nullptr || numAtoms[currentset]>=selectedAtom) { //isos sprintf (string, "%d", currentiso+1); } else { pos-=Vector3(atoms[currentset][selectedAtom*4+0], atoms[currentset][selectedAtom*4+1], atoms[currentset][selectedAtom*4+2]); @@ -3328,7 +3341,7 @@ void CMainApplication::RenderScene(vr::Hmd_Eye nEye) glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - if (menubutton==Infobox && savetodisk) + if (showInfoBox) RenderInfo(nEye); RenderAtoms(nEye); RenderUnitCell(nEye); @@ -3954,17 +3967,11 @@ char * MainErrors [] = { int main(int argc, char *argv[]) { //https://stackoverflow.com/questions/8544090/detected-memory-leaks - /*_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); - _CrtSetBreakAlloc(639); - _CrtSetBreakAlloc(783); - _CrtSetBreakAlloc(676); - _CrtSetBreakAlloc(675); - _CrtSetBreakAlloc(639); - _CrtSetBreakAlloc(125); - _CrtSetBreakAlloc(118); - _CrtSetBreakAlloc(117); - _CrtSetBreakAlloc(94); - _CrtSetBreakAlloc(93);*/ + _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );/* + _CrtSetBreakAlloc(1969); + _CrtSetBreakAlloc(1918); + _CrtSetBreakAlloc(1226); + */ TMPDIR=".\\"; //http://stackoverflow.com/questions/4991967/how-does-wsastartup-function-initiates-use-of-the-winsock-dll WSADATA wsaData; diff --git a/README.md b/README.md index ca2e4fae8c887a6ed544991c26faedb610226a04..adb848541b7b46d34720ab921b0c9df1b32c21c7 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,13 @@ Subdirectories: Transforms a json from encyclopedia or archive into an XYZ file Useful for the remote visualization infrastructure + proxy: Back-end support for multiuser support in OpenVR NOMAD VR. + NOMADVRproxy listens to connections and forwards user actions to rest of + users. + + MD-Driver/SimpleMove and MD-Driver/PeriodicTable: see MD-Driver/Readme + Support for atom drag-and-drop functionality in OpenVR NOMAD VR. + More platforms will be added in the future. The code is distributed under the Apache 2.0 License (See LICENSE file).