diff --git a/NOMADVRLib/ConfigFile.cpp b/NOMADVRLib/ConfigFile.cpp index 7ba4e32e5ed358fd2dc42bbfa4a329362577aeda..a96909607a44bf6a110ecfbe66996ee0d8f2df87 100644 --- a/NOMADVRLib/ConfigFile.cpp +++ b/NOMADVRLib/ConfigFile.cpp @@ -82,6 +82,10 @@ menubutton_t menubutton; std::vector<information> info; +int secret; +const char * server; +int port; + const char * loadConfigFileErrors[] = { "All Ok",//0 @@ -290,6 +294,10 @@ void initState() bondscaling = 0.7f; bondThickness = 1.0f; + + secret=0; + server=nullptr; + port=-1; } int loadConfigFile(const char * f) @@ -530,7 +538,7 @@ int loadConfigFile(const char * f) return -11; } } else if (!strcmp(s, "atomglyph")) { - r=fscanf (F, "%s", s); + r=fscanf (F, "%99s", s); if (r==0) return -15; if (!strcmp(s, "icosahedron")) @@ -606,7 +614,7 @@ int loadConfigFile(const char * f) } else if (!strcmp (s, "atomcolour")) { char atom [100]; float rgb[3]; - r = fscanf(F, "%s %f %f %f", atom, rgb, rgb + 1, rgb + 2); + r = fscanf(F, "%99s %f %f %f", atom, rgb, rgb + 1, rgb + 2); if (r!=4) { eprintf ("Error loading atom colour"); return -19; @@ -622,7 +630,7 @@ int loadConfigFile(const char * f) char atom [100]; float rgb[3]; float size; - r = fscanf(F, "%s %f %f %f %f", atom, rgb, rgb + 1, rgb + 2, &size); + r = fscanf(F, "%99s %f %f %f %f", atom, rgb, rgb + 1, rgb + 2, &size); if (r!=5) { eprintf ("Error loading newatom"); return -20; @@ -711,7 +719,7 @@ int loadConfigFile(const char * f) eprintf("Error reading bondthickness"); } else if (!strcmp(s, "menubutton")) { - r = fscanf(F, "%s", s); + r = fscanf(F, "%99s", s); if (!strcmp(s, "Record")) menubutton = Record; else if (!strcmp(s, "Infobox")) @@ -743,6 +751,15 @@ 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, "server")) { //multiuser support + int r; + if (server) + delete(server); + server=new char[100]; + r=fscanf (F, "%99s %d %d", server, &port, &secret); + if (r<3) { + eprintf ("Error reading server paramters"); + } } else { eprintf( "Unrecognized parameter %s\n", s); for (int i=0;i<strlen(s);i++) diff --git a/NOMADVRLib/ConfigFile.h b/NOMADVRLib/ConfigFile.h index 8c9d967f9a92f930630cf4cfa0198112b707ea58..bf252fe11b9eda10e8d381b383da2aff9536d138 100644 --- a/NOMADVRLib/ConfigFile.h +++ b/NOMADVRLib/ConfigFile.h @@ -83,6 +83,11 @@ extern const char * loadConfigFileErrors[]; void cleanConfig(); int loadConfigFile(const char * f); +//for multiuser +extern int secret; +extern const char * server; +extern int port; + struct information { float pos[3]; float size; diff --git a/NOMADVRLib/atomsGL.cpp b/NOMADVRLib/atomsGL.cpp index 546257dbcc5269544e1b973a3700a85ff491098a..6c20dee2a10f701476430cd60adc40bec2c7bfe0 100644 --- a/NOMADVRLib/atomsGL.cpp +++ b/NOMADVRLib/atomsGL.cpp @@ -674,6 +674,8 @@ GLenum SetupMarker(GLuint *MarkerVAO, GLuint *MarkerVertBuffer) void CleanUnitCell (GLuint *UnitCellVAO, GLuint *UnitCellVertBuffer, GLuint *UnitCellIndexBuffer) { + if (!has_abc) + return; glDeleteVertexArrays(1, UnitCellVAO); glDeleteBuffers(1, UnitCellVertBuffer); glDeleteBuffers(1, UnitCellIndexBuffer); diff --git a/OpenVR/TimestepData/LoadPNG.cpp b/OpenVR/TimestepData/LoadPNG.cpp index 0e9d259050005add5dbd6546fa45c93a6b0625c1..db94f670be05ac907f539db996f9f8c8ab79c909 100644 --- a/OpenVR/TimestepData/LoadPNG.cpp +++ b/OpenVR/TimestepData/LoadPNG.cpp @@ -1,5 +1,5 @@ /* -# Copyright 2016-2018 Ruben Jesus Garcia Hernandez +# Copyright 2016-2018 Ruben Jesus Garcia-Hernandez # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -16,19 +16,24 @@ #include <vector> #include "LoadPNG.h" +#include "NOMADVRLib/eprintf.h" #include "shared/lodepng.h" -GLuint LoadPNG (const char *image) +GLuint LoadPNG(const char *image, int renderMode) { - GLuint m_iTexture; - glGenTextures(1, &m_iTexture); - glBindTexture(GL_TEXTURE_2D, m_iTexture); - std::vector<unsigned char> imageRGBA; unsigned nImageWidth, nImageHeight; unsigned nError = lodepng::decode(imageRGBA, nImageWidth, nImageHeight, image); - + if (nError!=0) { + eprintf ("Error loading texture %s, lodepng::decode error %d", image, nError); + return 0; + } + + GLuint m_iTexture; + glGenTextures(1, &m_iTexture); + glBindTexture(GL_TEXTURE_2D, m_iTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, nImageWidth, nImageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, &imageRGBA[0]); @@ -36,9 +41,19 @@ GLuint LoadPNG (const char *image) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - + switch (renderMode) { + case linear: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + break; + case nearest: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + break; + default: + eprintf("Error, unknown render mode in LoadPNG"); + return 0; + } //rgh fixme: revise this if texture sampling is too slow GLfloat fLargest; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest); diff --git a/OpenVR/TimestepData/LoadPNG.h b/OpenVR/TimestepData/LoadPNG.h index 5f39aeeae127102733145cb76d71ff957736e74b..5cbd76c48f78151b17ea1ff7eb5f16c86f49e0f9 100644 --- a/OpenVR/TimestepData/LoadPNG.h +++ b/OpenVR/TimestepData/LoadPNG.h @@ -1,5 +1,5 @@ /* -# Copyright 2016-2018 Ruben Jesus Garcia Hernandez +# Copyright 2016-2018 Ruben Jesus Garcia-Hernandez # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -18,6 +18,12 @@ #define LOADPNG_H #include "NOMADVRLib/MyGL.h" -GLuint LoadPNG (const char *image); +enum RenderMode { + linear = 0, + nearest = 1, + error = 2 +}; + +GLuint LoadPNG(const char *image, int renderMode=linear); #endif diff --git a/OpenVR/TimestepData/hellovr_opengl_main.cpp b/OpenVR/TimestepData/hellovr_opengl_main.cpp index 284461e02865bef4a3d0e4dcaf2c2e8f1fb726b6..ebbbaca103df9c50e6dada77cbd9b36df2d1634e 100644 --- a/OpenVR/TimestepData/hellovr_opengl_main.cpp +++ b/OpenVR/TimestepData/hellovr_opengl_main.cpp @@ -32,6 +32,7 @@ #define new DEBUG_NEW #include <vector> +#include <thread> #include <SDL.h> #include <GL/glew.h> @@ -348,6 +349,10 @@ private: // OpenGL bookkeeping int myargc; char **myargv; int currentConfig; + + std::thread *tcpconn; + void connectTCP(); + int sock; }; const float CMainApplication::videospeed = 0.01f; @@ -429,9 +434,85 @@ int CMainApplication::LoadConfigFile (const char *c) if (solid) MessageBoxA(0, "Only spheres implemented as atom glyphs in HTC Vive", "Atom Glyph", 0); + //change currentiso if needed + if (currentiso > ISOS || currentiso <0) + currentiso = (currentiso + ISOS + 1) % (ISOS+1); //beware of (-1) + //add multiuser support + if (port!=-1 && tcpconn==nullptr) { //do not change servers as we change config file for now + tcpconn=new std::thread(&CMainApplication::connectTCP, this); + } + + + return r; } +void CMainApplication::connectTCP() +{ + //https://stackoverflow.com/questions/5444197/converting-host-to-ip-by-sockaddr-in-gethostname-etc + struct sockaddr_in serv_addr; + struct hostent *he; + if ( (he = gethostbyname(server) ) == nullptr ) { + return; /* error */ + } + memset((char *) &serv_addr, 0, sizeof(serv_addr)); + memcpy(&serv_addr.sin_addr, he->h_addr_list[0], he->h_length); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(port); + sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); + if ( connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) { + return; /* error */ + } + //read state + int n; + int32_t tmp; + tmp=htonl (secret); + n = send(sock, (char*)&tmp , sizeof(tmp), 0); + if (n<sizeof(tmp)) + return; + char what; + while (true) { + n=recv(sock, &what, sizeof(what), 0); + if (n<1) + return; + switch (what) { + case 't': + n=recv (sock, (char*)&tmp, sizeof(tmp), 0); + if (n<sizeof(tmp)) + return; + currentset=ntohl(tmp)%TIMESTEPS; + break; + case 'i': + n=recv (sock, (char*)&tmp, sizeof(tmp), 0); + if (n<sizeof(tmp)) + return; + currentiso=ntohl(tmp)%(ISOS+1); + break; + case 's': + char s; + n=recv (sock, &s, sizeof(s), 0); + if (n<sizeof(s)) + return; + showAtoms=(bool)s; + break; + case 'n': + n=recv (sock, (char*)&tmp, sizeof(tmp), 0); + if (n<sizeof(tmp)) + return; + //load config file + if (currentConfig!=ntohl(tmp)%myargc) { + currentConfig=ntohl(tmp)%myargc; + CleanScene(); + LoadConfigFile(myargv[currentConfig]); + SetupScene(); + } + break; + default: + eprintf ("Unknown state sent from server: %c\n", what); + } + } +} + //----------------------------------------------------------------------------- // Purpose: Constructor //----------------------------------------------------------------------------- @@ -480,7 +561,7 @@ CMainApplication::CMainApplication(int argc, char *argv[]) , m_bShowCubes(true) , currentset(0) , elapsedtime(videospeed*float(SDL_GetTicks())) - , currentiso(ISOS) + , currentiso(-1) // (-> ISOS, but at this point ISOS is not yet initialized) , firstdevice(-1) , seconddevice(-1) , m_iTexture(0) @@ -500,6 +581,8 @@ CMainApplication::CMainApplication(int argc, char *argv[]) , myargc(argc) , myargv(argv) , currentConfig(1) + , tcpconn(0) + , sock(-1) { LoadConfigFile(argv[currentConfig]); for (int j=0;j<3;j++) @@ -1006,6 +1089,22 @@ bool CMainApplication::HandleInput() currentConfig++; if (currentConfig>=myargc) currentConfig=1; + if (sock>=0) { + char w='c'; + int32_t tmp; + tmp=htonl(currentConfig); + int n; + n=send(sock, &w, sizeof(w), 0); + if (n<sizeof(w)) { + closesocket(sock); + sock=-1; + } + n=send(sock, (char*)&tmp, sizeof(tmp), 0); + if (n<sizeof(tmp)) { + closesocket(sock); + sock=-1; + } + } CleanScene(); LoadConfigFile(myargv[currentConfig]); SetupScene(); @@ -1492,6 +1591,8 @@ bool CMainApplication::SetupTexturemaps() else path=s.substr(0, l)+"\\"+NUMBERTEXTURE; numbersTexture=LoadPNG(path.c_str(), nearest); + if (numbersTexture==0) + eprintf ("Error loading %s\n", path); return ( m_iTexture != 0 && e==GL_NO_ERROR); } @@ -1535,8 +1636,10 @@ void CMainApplication::CleanScene() ISOS=0; } //atoms - ::CleanAtoms(&m_unAtomVAO, &m_glAtomVertBuffer, &BondIndices); - ::cleanAtoms(&numAtoms, TIMESTEPS, &atoms); + if (atoms) { + ::CleanAtoms(&m_unAtomVAO, &m_glAtomVertBuffer, &BondIndices); + ::cleanAtoms(&numAtoms, TIMESTEPS, &atoms); + } //unit cell ::CleanUnitCell(&m_unUnitCellVAO, &m_glUnitCellVertBuffer, &m_glUnitCellIndexBuffer); //marker @@ -1739,49 +1842,39 @@ float GetTextureCoordinate (char c) return u; } +//if selected atom, display atom # and distance. +//Otherwise, display timestep in firstdevice and iso in seconddevice void CMainApplication::RenderControllerGlyph (const vr::Hmd_Eye nEye, const int controller) { - if (selectedAtom==-1) - return; - if (controller == seconddevice) { - Vector3 pos; - PrepareControllerGlyph(nEye, controller, &pos); - pos /=scaling; - pos-=UserPosition; - pos=Vector3(pos[0], -pos[2], pos[1]); - - pos-=Vector3(atoms[currentset][selectedAtom*4+0], atoms[currentset][selectedAtom*4+1], atoms[currentset][selectedAtom*4+2]); - - char dis [200]; - sprintf (dis, "%0.2fa", pos.length()); - int l=strlen (dis); - float *vert; - vert=new float[l*4*(4+3+2)]; - for (int i=0;i<l;i++) { - float u=GetTextureCoordinate(dis[i]); - FillVerticesGlyph (vert, i, u); - } //for - short int *ind=FillIndicesGlyph(l); - RenderNumbersControllerGlyph (l, vert, ind, numbersTexture); - return; - } // if - - if (selectedAtom==-1) - return; - + char string[200]; Vector3 pos; PrepareControllerGlyph(nEye, controller, &pos); - - //display atom number - char atom [200]; - sprintf (atom, "%d", selectedAtom+1); - //sprintf (atom, "%d %.2f %.2f %.2f", selectedAtom+1, atoms[currentset][selectedAtom*4+0], atoms[currentset][selectedAtom*4+1], atoms[currentset][selectedAtom*4+2]); - int l=strlen (atom); - + if (controller == seconddevice) { + if (selectedAtom==-1) { //isos + sprintf (string, "%d", currentiso+1); + } else { + pos /=scaling; + pos-=UserPosition; + pos=Vector3(pos[0], -pos[2], pos[1]); + + pos-=Vector3(atoms[currentset][selectedAtom*4+0], atoms[currentset][selectedAtom*4+1], atoms[currentset][selectedAtom*4+2]); + + sprintf (string, "%0.2fa", pos.length()); + } //if selectedatom + } else { // if controller == firstdevice + if (selectedAtom==-1) { //timestep + sprintf (string, "%d", currentset+1); + } else { + //display atom number + sprintf (string, "%d", selectedAtom+1); + //sprintf (atom, "%d %.2f %.2f %.2f", selectedAtom+1, atoms[currentset][selectedAtom*4+0], atoms[currentset][selectedAtom*4+1], atoms[currentset][selectedAtom*4+2]); + } + } + int l=strlen (string); float *vert; vert=new float[l*4*(4+3+2)]; for (int i=0;i<l;i++) { - float u=GetTextureCoordinate(atom[i]); + float u=GetTextureCoordinate(string[i]); FillVerticesGlyph (vert, i, u); } @@ -2814,7 +2907,7 @@ void CMainApplication::RenderScene(vr::Hmd_Eye nEye) PaintGrid(nEye, i); } //for all isos in descending order if ((e = glGetError()) != GL_NO_ERROR) - dprintf("Gl error after paintgrid: %d, %s\n", e, gluErrorString(e)); + dprintf("Gl error after paintgrid within RenderScene: %d, %s\n", e, gluErrorString(e)); if (numAtoms!=0) { if (menubutton == Infobox && savetodisk) RenderInfo(nEye);