1 /*
2 OpenVR for PyMOL Copyright Notice
3 =====================================
4 
5 The OpenVR for PyMOL source code is copyrighted, but you can freely use and
6 copy it as long as you don't change or remove any of the Copyright notices.
7 OpenVR for PyMOL is made available under the following open-source license
8 terms:
9 
10 ------------------------------------------------------------------------------
11 Copyright (c) 2018 EPAM Systems, Inc.
12 
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19 
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22 
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30 ------------------------------------------------------------------------------
31 
32 */
33 
34 // this header
35 #include "OpenVRControllerModel.h"
36 
37 // system headers
38 #include <vector>
39 #include "os_std.h"
40 #include "os_gl.h"
41 
42 // pymol headers
43 #include "Feedback.h"
44 #include "Matrix.h"
45 
46 // local headers
47 #include "OpenVRController.h"
48 
49 static std::vector<OpenVRControllerModel *> s_vecRenderModels;
50 
51 //-----------------------------------------------------------------------------
52 // Purpose: Create/destroy GL Render Models
53 //-----------------------------------------------------------------------------
OpenVRControllerModel(const std::string & sRenderModelName)54 OpenVRControllerModel::OpenVRControllerModel(const std::string & sRenderModelName) : m_sModelName( sRenderModelName ) {
55   m_glIndexBuffer = 0;
56   m_glVertArray = 0;
57   m_glVertBuffer = 0;
58   m_glTexture = 0;
59   m_pShader = NULL;
60 }
61 
~OpenVRControllerModel()62 OpenVRControllerModel::~OpenVRControllerModel() {
63   Free();
64 }
65 
66 //-----------------------------------------------------------------------------
67 // Purpose: Allocates and populates the GL resources for a render model
68 //-----------------------------------------------------------------------------
Init(PyMOLGlobals * G,const vr::RenderModel_t & vrModel,const vr::RenderModel_TextureMap_t & vrDiffuseTexture)69 bool OpenVRControllerModel::Init(PyMOLGlobals *G, const vr::RenderModel_t &vrModel, const vr::RenderModel_TextureMap_t &vrDiffuseTexture) {
70   InitGeometry(vrModel);
71   InitTexture(vrDiffuseTexture);
72   InitShaders(G);
73   return true;
74 }
75 
76 //-----------------------------------------------------------------------------
77 // Purpose: Frees the GL resources for a render model
78 //-----------------------------------------------------------------------------
Free()79 void OpenVRControllerModel::Free() {
80   FreeShaders();
81   FreeTexture();
82   FreeGeometry();
83 }
84 
InitGeometry(const vr::RenderModel_t & vrModel)85 void OpenVRControllerModel::InitGeometry(const vr::RenderModel_t &vrModel) {
86  // create and bind a VAO to hold state for this model
87   glGenVertexArrays( 1, &m_glVertArray );
88   glBindVertexArray( m_glVertArray );
89 
90   // Populate a vertex buffer
91   glGenBuffers( 1, &m_glVertBuffer );
92   glBindBuffer( GL_ARRAY_BUFFER, m_glVertBuffer );
93   glBufferData( GL_ARRAY_BUFFER, sizeof(vr::RenderModel_Vertex_t) *vrModel.unVertexCount, vrModel.rVertexData, GL_STATIC_DRAW);
94 
95   // Identify the components in the vertex buffer
96   glEnableVertexAttribArray(0);
97   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof( vr::RenderModel_Vertex_t ), (void *)offsetof( vr::RenderModel_Vertex_t, vPosition));
98   glEnableVertexAttribArray(1);
99   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof( vr::RenderModel_Vertex_t ), (void *)offsetof(vr::RenderModel_Vertex_t, rfTextureCoord));
100 
101   // Create and populate the index buffer
102   glGenBuffers( 1, &m_glIndexBuffer );
103   glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, m_glIndexBuffer );
104   glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof( uint16_t ) * vrModel.unTriangleCount * 3, vrModel.rIndexData, GL_STATIC_DRAW );
105 
106   glBindVertexArray( 0 );
107 
108   m_unVertexCount = vrModel.unTriangleCount * 3;
109 }
110 
FreeGeometry()111 void OpenVRControllerModel::FreeGeometry() {
112   if( m_glVertBuffer ) {
113     glDeleteBuffers(1, &m_glIndexBuffer);
114     glDeleteVertexArrays( 1, &m_glVertArray );
115     glDeleteBuffers(1, &m_glVertBuffer);
116     m_glIndexBuffer = 0;
117     m_glVertArray = 0;
118     m_glVertBuffer = 0;
119   }
120 }
121 
InitTexture(const vr::RenderModel_TextureMap_t & vrDiffuseTexture)122 void OpenVRControllerModel::InitTexture(const vr::RenderModel_TextureMap_t &vrDiffuseTexture) {
123 // create and populate the texture
124   glGenTextures(1, &m_glTexture );
125   glBindTexture( GL_TEXTURE_2D, m_glTexture );
126 
127   glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, vrDiffuseTexture.unWidth, vrDiffuseTexture.unHeight,
128     0, GL_RGBA, GL_UNSIGNED_BYTE, vrDiffuseTexture.rubTextureMapData );
129 
130   // If this renders black ask McJohn what's wrong.
131   glGenerateMipmap(GL_TEXTURE_2D);
132 
133   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
134   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
135   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
136   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
137 
138   GLfloat fLargest;
139   glGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest );
140   glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest );
141 
142   glBindTexture( GL_TEXTURE_2D, 0 );
143 }
144 
FreeTexture()145 void OpenVRControllerModel::FreeTexture() {
146   if (m_glTexture) {
147     glDeleteTextures(1, &m_glTexture);
148     m_glTexture = 0;
149   }
150 }
151 
InitShaders(PyMOLGlobals * G)152 bool OpenVRControllerModel::InitShaders(PyMOLGlobals * G) {
153   m_pShader = new CShaderPrg(G, "CRenderModel", "vrcontroller.vs", "vrcontroller.fs");
154   if (m_pShader) {
155     m_pShader->reload();
156     glBindAttribLocation(m_pShader->id, 0, "position");
157     glBindAttribLocation(m_pShader->id, 1, "texcoords_in");
158     glLinkProgram(m_pShader->id);
159   }
160   return m_pShader != NULL;
161 }
162 
FreeShaders()163 void OpenVRControllerModel::FreeShaders() {
164   if (m_pShader) {
165     delete m_pShader;
166     m_pShader = NULL;
167   }
168 }
169 
170 //-----------------------------------------------------------------------------
171 // Purpose: Draws the render model
172 //-----------------------------------------------------------------------------
Draw()173 void OpenVRControllerModel::Draw() {
174   GL_DEBUG_FUN();
175   m_pShader->Enable();
176   glBindVertexArray( m_glVertArray );
177 
178   glActiveTexture( GL_TEXTURE0 );
179   glBindTexture( GL_TEXTURE_2D, m_glTexture );
180 
181   glDrawElements( GL_TRIANGLES, m_unVertexCount, GL_UNSIGNED_SHORT, 0 );
182 
183   glBindVertexArray( 0 );
184   m_pShader->Disable();
185 }
186 
187 // Purpose:
188 //-----------------------------------------------------------------------------
189 static
ThreadSleep(unsigned long nMilliseconds)190 void ThreadSleep( unsigned long nMilliseconds )
191 {
192 #if defined(_WIN32)
193   ::Sleep( nMilliseconds );
194 #elif defined(POSIX)
195   usleep( nMilliseconds * 1000 );
196 #endif
197 }
198 
199 // Purpose: Finds a render model we've already loaded or loads a new one
200 //-----------------------------------------------------------------------------
FindOrLoadRenderModel(PyMOLGlobals * G,const char * pchRenderModelName)201 OpenVRControllerModel *FindOrLoadRenderModel(PyMOLGlobals * G, const char *pchRenderModelName)
202 {
203   OpenVRControllerModel *pRenderModel = NULL;
204   for(std::vector<OpenVRControllerModel *>::iterator i = s_vecRenderModels.begin(); i != s_vecRenderModels.end(); i++) {
205     if(!
206 #ifdef _WIN32
207         stricmp
208 #else
209         strcasecmp
210 #endif
211         ((*i)->GetName().c_str(), pchRenderModelName)){
212       pRenderModel = *i;
213       break;
214     }
215   }
216 
217   // load the model if we didn't find one
218   if(!pRenderModel) {
219     vr::RenderModel_t *pModel;
220     vr::EVRRenderModelError error;
221     while (true) {
222       error = vr::VRRenderModels()->LoadRenderModel_Async(pchRenderModelName, &pModel);
223       if (error != vr::VRRenderModelError_Loading)
224         break;
225 
226       ThreadSleep( 1 );
227     }
228 
229     if (error != vr::VRRenderModelError_None) {
230       PRINTF
231         " Unable to load render model %s - %s\n",
232         pchRenderModelName,
233         vr::VRRenderModels()->GetRenderModelErrorNameFromEnum(error)
234       ENDF(G);
235       return NULL; // move on to the next tracked device
236     }
237 
238     vr::RenderModel_TextureMap_t *pTexture;
239     while (true) {
240       error = vr::VRRenderModels()->LoadTexture_Async(pModel->diffuseTextureId, &pTexture);
241       if (error != vr::VRRenderModelError_Loading)
242         break;
243       ThreadSleep( 1 );
244     }
245 
246     if (error != vr::VRRenderModelError_None) {
247       PRINTF
248         " Unable to load render texture id:%d for render model %s\n",
249         pModel->diffuseTextureId,
250         pchRenderModelName
251       ENDF(G);
252       vr::VRRenderModels()->FreeRenderModel(pModel);
253       return NULL; // move on to the next tracked device
254     }
255 
256     pRenderModel = new OpenVRControllerModel(pchRenderModelName);
257     if (!pRenderModel->Init(G, *pModel, *pTexture)) {
258       PRINTF
259         " Unable to create GL model from render model %s\n",
260         pchRenderModelName
261       ENDF(G);
262       delete pRenderModel;
263       pRenderModel = NULL;
264     } else {
265       s_vecRenderModels.push_back(pRenderModel);
266     }
267     vr::VRRenderModels()->FreeRenderModel(pModel);
268     vr::VRRenderModels()->FreeTexture(pTexture);
269   }
270   return pRenderModel;
271 }
272 
ShutdownRenderModels()273 void ShutdownRenderModels() {
274   for(std::vector<OpenVRControllerModel *>::iterator i = s_vecRenderModels.begin(); i != s_vecRenderModels.end(); i++) {
275     (*i)->Free();
276     delete (*i);
277   }
278   s_vecRenderModels.clear();
279 }
280