rev |
line source |
nuclear@0
|
1 /************************************************************************************
|
nuclear@0
|
2
|
nuclear@0
|
3 Filename : CAPI_GL_HSWDisplay.cpp
|
nuclear@0
|
4 Content : Implements Health and Safety Warning system.
|
nuclear@0
|
5 Created : July 7, 2014
|
nuclear@0
|
6 Authors : Paul Pedriana
|
nuclear@0
|
7
|
nuclear@0
|
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
|
nuclear@0
|
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
|
nuclear@0
|
12 which is provided at the time of installation or download, or which
|
nuclear@0
|
13 otherwise accompanies this software in either electronic or hard copy form.
|
nuclear@0
|
14
|
nuclear@0
|
15 You may obtain a copy of the License at
|
nuclear@0
|
16
|
nuclear@0
|
17 http://www.oculusvr.com/licenses/LICENSE-3.2
|
nuclear@0
|
18
|
nuclear@0
|
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
|
nuclear@0
|
20 distributed under the License is distributed on an "AS IS" BASIS,
|
nuclear@0
|
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
nuclear@0
|
22 See the License for the specific language governing permissions and
|
nuclear@0
|
23 limitations under the License.
|
nuclear@0
|
24
|
nuclear@0
|
25 ************************************************************************************/
|
nuclear@0
|
26
|
nuclear@0
|
27
|
nuclear@0
|
28 #include "CAPI_GL_HSWDisplay.h"
|
nuclear@0
|
29 #include "CAPI_GL_DistortionShaders.h"
|
nuclear@0
|
30 #include "../../OVR_CAPI_GL.h"
|
nuclear@0
|
31 #include "../../Kernel/OVR_File.h"
|
nuclear@0
|
32 #include "../../Kernel/OVR_Math.h"
|
nuclear@0
|
33 #include "../../Kernel/OVR_Allocator.h"
|
nuclear@0
|
34 #include "../../Kernel/OVR_Color.h"
|
nuclear@0
|
35
|
nuclear@0
|
36
|
nuclear@0
|
37 OVR_DISABLE_MSVC_WARNING(4996) // "This function or variable may be unsafe..."
|
nuclear@0
|
38
|
nuclear@0
|
39
|
nuclear@0
|
40 namespace OVR { namespace CAPI {
|
nuclear@0
|
41
|
nuclear@0
|
42
|
nuclear@0
|
43 // Loads the TGA data from the File as an array of width * height 32 bit Texture_RGBA values.
|
nuclear@0
|
44 // Returned pointer must be freed with OVR_FREE.
|
nuclear@0
|
45 uint8_t* LoadTextureTgaData(OVR::File* f, uint8_t alpha, int& width, int& height)
|
nuclear@0
|
46 {
|
nuclear@0
|
47 // See http://www.fileformat.info/format/tga/egff.htm for format details.
|
nuclear@0
|
48 // TGA files are stored with little-endian data.
|
nuclear@0
|
49 uint8_t* pRGBA = NULL;
|
nuclear@0
|
50
|
nuclear@0
|
51 f->SeekToBegin();
|
nuclear@0
|
52
|
nuclear@0
|
53 const int desclen = f->ReadUByte();
|
nuclear@0
|
54 const int palette = f->ReadUByte();
|
nuclear@0
|
55 OVR_UNUSED(palette);
|
nuclear@0
|
56 const int imgtype = f->ReadUByte();
|
nuclear@0
|
57 f->ReadUInt16(); // Skip bytes
|
nuclear@0
|
58 int palCount = f->ReadUInt16();
|
nuclear@0
|
59 int palSize = f->ReadUByte();
|
nuclear@0
|
60 f->ReadUInt16();
|
nuclear@0
|
61 f->ReadUInt16();
|
nuclear@0
|
62 width = f->ReadUInt16();
|
nuclear@0
|
63 height = f->ReadUInt16();
|
nuclear@0
|
64 int bpp = f->ReadUByte();
|
nuclear@0
|
65 f->ReadUByte();
|
nuclear@0
|
66
|
nuclear@0
|
67 const int ImgTypeBGRAUncompressed = 2;
|
nuclear@0
|
68 const int ImgTypeBGRARLECompressed = 10;
|
nuclear@0
|
69
|
nuclear@0
|
70 OVR_ASSERT(((imgtype == ImgTypeBGRAUncompressed) || (imgtype == ImgTypeBGRARLECompressed)) && ((bpp == 24) || (bpp == 32)));
|
nuclear@0
|
71
|
nuclear@0
|
72 // imgType 2 is uncompressed true-color image.
|
nuclear@0
|
73 // imgType 10 is run-length encoded true-color image.
|
nuclear@0
|
74 if(((imgtype == ImgTypeBGRAUncompressed) || (imgtype == ImgTypeBGRARLECompressed)) && ((bpp == 24) || (bpp == 32)))
|
nuclear@0
|
75 {
|
nuclear@0
|
76 int imgsize = width * height * 4;
|
nuclear@0
|
77 pRGBA = (uint8_t*) OVR_ALLOC(imgsize);
|
nuclear@0
|
78 f->Skip(desclen);
|
nuclear@0
|
79 f->Skip(palCount * (palSize + 7) >> 3);
|
nuclear@0
|
80 int strideBytes = width * 4; // This is the number of bytes between successive rows.
|
nuclear@0
|
81
|
nuclear@0
|
82 unsigned char buf[4] = { 0, 0, 0, alpha }; // If bpp is 24 then this alpha will be unmodified below.
|
nuclear@0
|
83
|
nuclear@0
|
84 switch (imgtype)
|
nuclear@0
|
85 {
|
nuclear@0
|
86 case ImgTypeBGRAUncompressed:
|
nuclear@0
|
87 switch (bpp)
|
nuclear@0
|
88 {
|
nuclear@0
|
89 case 24:
|
nuclear@0
|
90 case 32:
|
nuclear@0
|
91 for (int y = 0; y < height; y++)
|
nuclear@0
|
92 {
|
nuclear@0
|
93 for (int x = 0; x < width; x++)
|
nuclear@0
|
94 {
|
nuclear@0
|
95 f->Read(buf, bpp / 8); // Data is stored as B, G, R
|
nuclear@0
|
96 pRGBA[y*strideBytes + x*4 + 0] = buf[2];
|
nuclear@0
|
97 pRGBA[y*strideBytes + x*4 + 1] = buf[1];
|
nuclear@0
|
98 pRGBA[y*strideBytes + x*4 + 2] = buf[0];
|
nuclear@0
|
99 pRGBA[y*strideBytes + x*4 + 3] = buf[3];
|
nuclear@0
|
100 }
|
nuclear@0
|
101 }
|
nuclear@0
|
102 break;
|
nuclear@0
|
103 }
|
nuclear@0
|
104 break;
|
nuclear@0
|
105
|
nuclear@0
|
106 case ImgTypeBGRARLECompressed:
|
nuclear@0
|
107 switch (bpp)
|
nuclear@0
|
108 {
|
nuclear@0
|
109 case 24:
|
nuclear@0
|
110 case 32:
|
nuclear@0
|
111 for (int y = 0; y < height; y++) // RLE spans don't cross successive rows.
|
nuclear@0
|
112 {
|
nuclear@0
|
113 int x = 0;
|
nuclear@0
|
114
|
nuclear@0
|
115 while(x < width)
|
nuclear@0
|
116 {
|
nuclear@0
|
117 uint8_t rleByte;
|
nuclear@0
|
118 f->Read(&rleByte, 1);
|
nuclear@0
|
119
|
nuclear@0
|
120 if(rleByte & 0x80) // If the high byte is set then what follows are RLE bytes.
|
nuclear@0
|
121 {
|
nuclear@0
|
122 size_t rleCount = ((rleByte & 0x7f) + 1);
|
nuclear@0
|
123 f->Read(buf, bpp / 8); // Data is stored as B, G, R, A
|
nuclear@0
|
124
|
nuclear@0
|
125 for (; rleCount; --rleCount, ++x)
|
nuclear@0
|
126 {
|
nuclear@0
|
127 pRGBA[y*strideBytes + x*4 + 0] = buf[2];
|
nuclear@0
|
128 pRGBA[y*strideBytes + x*4 + 1] = buf[1];
|
nuclear@0
|
129 pRGBA[y*strideBytes + x*4 + 2] = buf[0];
|
nuclear@0
|
130 pRGBA[y*strideBytes + x*4 + 3] = buf[3];
|
nuclear@0
|
131 }
|
nuclear@0
|
132 }
|
nuclear@0
|
133 else // Else what follows are regular bytes of a count indicated by rleByte
|
nuclear@0
|
134 {
|
nuclear@0
|
135 for (size_t rleCount = (rleByte + 1); rleCount; --rleCount, ++x)
|
nuclear@0
|
136 {
|
nuclear@0
|
137 f->Read(buf, bpp / 8); // Data is stored as B, G, R, A
|
nuclear@0
|
138 pRGBA[y*strideBytes + x*4 + 0] = buf[2];
|
nuclear@0
|
139 pRGBA[y*strideBytes + x*4 + 1] = buf[1];
|
nuclear@0
|
140 pRGBA[y*strideBytes + x*4 + 2] = buf[0];
|
nuclear@0
|
141 pRGBA[y*strideBytes + x*4 + 3] = buf[3];
|
nuclear@0
|
142 }
|
nuclear@0
|
143 }
|
nuclear@0
|
144 }
|
nuclear@0
|
145 }
|
nuclear@0
|
146 break;
|
nuclear@0
|
147 }
|
nuclear@0
|
148 break;
|
nuclear@0
|
149 }
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 return pRGBA;
|
nuclear@0
|
153 } // LoadTextureTgaData
|
nuclear@0
|
154
|
nuclear@0
|
155
|
nuclear@0
|
156
|
nuclear@0
|
157 namespace GL {
|
nuclear@0
|
158
|
nuclear@0
|
159
|
nuclear@0
|
160 // To do: This needs to be promoted to a central version, possibly in CAPI_HSWDisplay.h
|
nuclear@0
|
161 struct HASWVertex
|
nuclear@0
|
162 {
|
nuclear@0
|
163 Vector3f Pos;
|
nuclear@0
|
164 Color C;
|
nuclear@0
|
165 float U, V;
|
nuclear@0
|
166
|
nuclear@0
|
167 HASWVertex(const Vector3f& p, const Color& c = Color(64,0,0,255), float u = 0, float v = 0)
|
nuclear@0
|
168 : Pos(p), C(c), U(u), V(v)
|
nuclear@0
|
169 {}
|
nuclear@0
|
170
|
nuclear@0
|
171 HASWVertex(float x, float y, float z, const Color& c = Color(64,0,0,255), float u = 0, float v = 0)
|
nuclear@0
|
172 : Pos(x,y,z), C(c), U(u), V(v)
|
nuclear@0
|
173 {}
|
nuclear@0
|
174
|
nuclear@0
|
175 bool operator==(const HASWVertex& b) const
|
nuclear@0
|
176 {
|
nuclear@0
|
177 return (Pos == b.Pos) && (C == b.C) && (U == b.U) && (V == b.V);
|
nuclear@0
|
178 }
|
nuclear@0
|
179 };
|
nuclear@0
|
180
|
nuclear@0
|
181
|
nuclear@0
|
182
|
nuclear@0
|
183 // This is a temporary function implementation, and it functionality needs to be implemented in a more generic way.
|
nuclear@0
|
184 Texture* LoadTextureTga(RenderParams& rParams, int samplerMode, OVR::File* f, uint8_t alpha)
|
nuclear@0
|
185 {
|
nuclear@0
|
186 OVR::CAPI::GL::Texture* pTexture = NULL;
|
nuclear@0
|
187
|
nuclear@0
|
188 int width, height;
|
nuclear@0
|
189 const uint8_t* pRGBA = LoadTextureTgaData(f, alpha, width, height);
|
nuclear@0
|
190
|
nuclear@0
|
191 if (pRGBA)
|
nuclear@0
|
192 {
|
nuclear@0
|
193 pTexture = new OVR::CAPI::GL::Texture(&rParams, width, height);
|
nuclear@0
|
194
|
nuclear@0
|
195 // SetSampleMode forces the use of mipmaps through GL_LINEAR_MIPMAP_LINEAR.
|
nuclear@0
|
196 pTexture->SetSampleMode(samplerMode); // Calls glBindTexture internally.
|
nuclear@0
|
197
|
nuclear@0
|
198 // We are intentionally not using mipmaps. We need to use this because Texture::SetSampleMode unilaterally uses GL_LINEAR_MIPMAP_LINEAR.
|
nuclear@0
|
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
|
nuclear@0
|
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
nuclear@0
|
201 OVR_ASSERT(glGetError() == 0);
|
nuclear@0
|
202
|
nuclear@0
|
203 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pRGBA);
|
nuclear@0
|
204 OVR_ASSERT(glGetError() == 0);
|
nuclear@0
|
205
|
nuclear@0
|
206 // With OpenGL 4.2+ we can use this instead of glTexImage2D:
|
nuclear@0
|
207 // glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
|
nuclear@0
|
208 // glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pRGBA);
|
nuclear@0
|
209
|
nuclear@0
|
210 OVR_FREE(const_cast<uint8_t*>(pRGBA));
|
nuclear@0
|
211 }
|
nuclear@0
|
212
|
nuclear@0
|
213 return pTexture;
|
nuclear@0
|
214 }
|
nuclear@0
|
215
|
nuclear@0
|
216
|
nuclear@0
|
217 // Loads a texture from a memory image of a TGA file.
|
nuclear@0
|
218 Texture* LoadTextureTga(RenderParams& rParams, int samplerMode, const uint8_t* pData, int dataSize, uint8_t alpha)
|
nuclear@0
|
219 {
|
nuclear@0
|
220 MemoryFile memoryFile("", pData, dataSize);
|
nuclear@0
|
221
|
nuclear@0
|
222 return LoadTextureTga(rParams, samplerMode, &memoryFile, alpha);
|
nuclear@0
|
223 }
|
nuclear@0
|
224
|
nuclear@0
|
225
|
nuclear@0
|
226
|
nuclear@0
|
227
|
nuclear@0
|
228 // The texture below may conceivably be shared between HSWDisplay instances. However,
|
nuclear@0
|
229 // beware that sharing may not be possible if two HMDs are using different locales
|
nuclear@0
|
230 // simultaneously. As of this writing it's not clear if that can occur in practice.
|
nuclear@0
|
231
|
nuclear@0
|
232 HSWDisplay::HSWDisplay(ovrRenderAPIType api, ovrHmd hmd, const HMDRenderState& renderState)
|
nuclear@0
|
233 : OVR::CAPI::HSWDisplay(api, hmd, renderState)
|
nuclear@0
|
234 , RenderParams()
|
nuclear@0
|
235 , GLContext()
|
nuclear@0
|
236 , FrameBuffer(0)
|
nuclear@0
|
237 , pTexture()
|
nuclear@0
|
238 , pShaderSet()
|
nuclear@0
|
239 , pVertexShader()
|
nuclear@0
|
240 , pFragmentShader()
|
nuclear@0
|
241 , pVB()
|
nuclear@0
|
242 , VAO(0)
|
nuclear@0
|
243 , VAOInitialized(false)
|
nuclear@0
|
244 , OrthoProjection()
|
nuclear@0
|
245 {
|
nuclear@0
|
246 }
|
nuclear@0
|
247
|
nuclear@0
|
248
|
nuclear@0
|
249 bool HSWDisplay::Initialize(const ovrRenderAPIConfig* apiConfig)
|
nuclear@0
|
250 {
|
nuclear@0
|
251 const ovrGLConfig* config = (const ovrGLConfig*)apiConfig;
|
nuclear@0
|
252
|
nuclear@0
|
253 if(config)
|
nuclear@0
|
254 {
|
nuclear@0
|
255 // The following is essentially copied from CAPI_GL_DistortionRender.cpp's
|
nuclear@0
|
256 // Initialize function. To do: Merge this to a central location.
|
nuclear@0
|
257 RenderParams.Multisample = config->OGL.Header.Multisample;
|
nuclear@0
|
258 RenderParams.BackBufferSize = config->OGL.Header.BackBufferSize;
|
nuclear@0
|
259
|
nuclear@0
|
260 #if defined(OVR_OS_WIN32)
|
nuclear@0
|
261 RenderParams.Window = (config->OGL.Window) ? config->OGL.Window : GetActiveWindow();
|
nuclear@0
|
262 RenderParams.DC = config->OGL.DC;
|
nuclear@0
|
263 #elif defined(OVR_OS_LINUX)
|
nuclear@0
|
264 if (config->OGL.Disp)
|
nuclear@0
|
265 {
|
nuclear@0
|
266 RenderParams.Disp = config->OGL.Disp;
|
nuclear@0
|
267 }
|
nuclear@0
|
268 if (!RenderParams.Disp)
|
nuclear@0
|
269 {
|
nuclear@0
|
270 RenderParams.Disp = glXGetCurrentDisplay();
|
nuclear@0
|
271 }
|
nuclear@0
|
272 if (!RenderParams.Disp)
|
nuclear@0
|
273 {
|
nuclear@0
|
274 OVR_DEBUG_LOG(("glXGetCurrentDisplay failed."));
|
nuclear@0
|
275 return false;
|
nuclear@0
|
276 }
|
nuclear@0
|
277 #endif
|
nuclear@0
|
278 }
|
nuclear@0
|
279 else
|
nuclear@0
|
280 {
|
nuclear@0
|
281 UnloadGraphics();
|
nuclear@0
|
282 }
|
nuclear@0
|
283
|
nuclear@0
|
284 return true;
|
nuclear@0
|
285 }
|
nuclear@0
|
286
|
nuclear@0
|
287
|
nuclear@0
|
288 void HSWDisplay::Shutdown()
|
nuclear@0
|
289 {
|
nuclear@0
|
290 UnloadGraphics();
|
nuclear@0
|
291 }
|
nuclear@0
|
292
|
nuclear@0
|
293
|
nuclear@0
|
294 void HSWDisplay::DisplayInternal()
|
nuclear@0
|
295 {
|
nuclear@0
|
296 HSWDISPLAY_LOG(("[HSWDisplay GL] DisplayInternal()"));
|
nuclear@0
|
297 // We may want to call LoadGraphics here instead of within Render.
|
nuclear@0
|
298 }
|
nuclear@0
|
299
|
nuclear@0
|
300
|
nuclear@0
|
301 void HSWDisplay::DismissInternal()
|
nuclear@0
|
302 {
|
nuclear@0
|
303 HSWDISPLAY_LOG(("[HSWDisplay GL] DismissInternal()"));
|
nuclear@0
|
304 UnloadGraphicsRequested = true; // We don't directly call UnloadGraphics here because this may be executed within a different thread.
|
nuclear@0
|
305 }
|
nuclear@0
|
306
|
nuclear@0
|
307
|
nuclear@0
|
308 void HSWDisplay::UnloadGraphics()
|
nuclear@0
|
309 {
|
nuclear@0
|
310 if(pTexture) // If initialized...
|
nuclear@0
|
311 {
|
nuclear@0
|
312 Context currentGLContext;
|
nuclear@0
|
313 currentGLContext.InitFromCurrent();
|
nuclear@0
|
314 GLContext.Bind();
|
nuclear@0
|
315
|
nuclear@0
|
316 // RenderParams: No need to clear.
|
nuclear@0
|
317 if(FrameBuffer != 0)
|
nuclear@0
|
318 {
|
nuclear@0
|
319 glDeleteFramebuffers(1, &FrameBuffer);
|
nuclear@0
|
320 FrameBuffer = 0;
|
nuclear@0
|
321 }
|
nuclear@0
|
322 pTexture.Clear();
|
nuclear@0
|
323 pShaderSet.Clear();
|
nuclear@0
|
324 pVertexShader.Clear();
|
nuclear@0
|
325 pFragmentShader.Clear();
|
nuclear@0
|
326 pVB.Clear();
|
nuclear@0
|
327 if(VAO)
|
nuclear@0
|
328 {
|
nuclear@0
|
329 glDeleteVertexArrays(1, &VAO);
|
nuclear@0
|
330 currentGLContext.Bind();
|
nuclear@0
|
331 GLContext.Destroy();
|
nuclear@0
|
332 }
|
nuclear@0
|
333 }
|
nuclear@0
|
334 }
|
nuclear@0
|
335
|
nuclear@0
|
336
|
nuclear@0
|
337 void HSWDisplay::LoadGraphics()
|
nuclear@0
|
338 {
|
nuclear@0
|
339 // We assume here that the current GL context is the one our resources will be associated with.
|
nuclear@0
|
340
|
nuclear@0
|
341 if (FrameBuffer == 0)
|
nuclear@0
|
342 {
|
nuclear@0
|
343 glGenFramebuffers(1, &FrameBuffer);
|
nuclear@0
|
344 }
|
nuclear@0
|
345
|
nuclear@0
|
346 if (!pTexture) // To do: Add support for .dds files, which would be significantly smaller than the size of the tga.
|
nuclear@0
|
347 {
|
nuclear@0
|
348 size_t textureSize;
|
nuclear@0
|
349 const uint8_t* TextureData = GetDefaultTexture(textureSize);
|
nuclear@0
|
350 pTexture = *LoadTextureTga(RenderParams, Sample_Linear | Sample_Clamp, TextureData, (int)textureSize, 255);
|
nuclear@0
|
351 }
|
nuclear@0
|
352
|
nuclear@0
|
353 if (!pShaderSet)
|
nuclear@0
|
354 {
|
nuclear@0
|
355 pShaderSet = *new ShaderSet();
|
nuclear@0
|
356 }
|
nuclear@0
|
357
|
nuclear@0
|
358 if(!pVertexShader)
|
nuclear@0
|
359 {
|
nuclear@0
|
360 OVR::String strShader((GLEContext::GetCurrentContext()->WholeVersion >= 302) ? glsl3Prefix : glsl2Prefix);
|
nuclear@0
|
361 strShader += SimpleTexturedQuad_vs;
|
nuclear@0
|
362
|
nuclear@0
|
363 pVertexShader = *new VertexShader(&RenderParams, const_cast<char*>(strShader.ToCStr()), strShader.GetLength(), SimpleTexturedQuad_vs_refl, OVR_ARRAY_COUNT(SimpleTexturedQuad_vs_refl));
|
nuclear@0
|
364 pShaderSet->SetShader(pVertexShader);
|
nuclear@0
|
365 }
|
nuclear@0
|
366
|
nuclear@0
|
367 if(!pFragmentShader)
|
nuclear@0
|
368 {
|
nuclear@0
|
369 OVR::String strShader((GLEContext::GetCurrentContext()->WholeVersion >= 302) ? glsl3Prefix : glsl2Prefix);
|
nuclear@0
|
370 strShader += SimpleTexturedQuad_ps;
|
nuclear@0
|
371
|
nuclear@0
|
372 pFragmentShader = *new FragmentShader(&RenderParams, const_cast<char*>(strShader.ToCStr()), strShader.GetLength(), SimpleTexturedQuad_ps_refl, OVR_ARRAY_COUNT(SimpleTexturedQuad_ps_refl));
|
nuclear@0
|
373 pShaderSet->SetShader(pFragmentShader);
|
nuclear@0
|
374 }
|
nuclear@0
|
375
|
nuclear@0
|
376 if(!pVB)
|
nuclear@0
|
377 {
|
nuclear@0
|
378 pVB = *new Buffer(&RenderParams);
|
nuclear@0
|
379
|
nuclear@0
|
380 pVB->Data(Buffer_Vertex, NULL, 4 * sizeof(HASWVertex));
|
nuclear@0
|
381 HASWVertex* pVertices = (HASWVertex*)pVB->Map(0, 4 * sizeof(HASWVertex), Map_Discard);
|
nuclear@0
|
382 OVR_ASSERT(pVertices);
|
nuclear@0
|
383
|
nuclear@0
|
384 if(pVertices)
|
nuclear@0
|
385 {
|
nuclear@0
|
386 const bool flip = ((RenderState.DistortionCaps & ovrDistortionCap_FlipInput) != 0);
|
nuclear@0
|
387 const float left = -1.0f; // We currently draw this in normalized device coordinates with an stereo translation
|
nuclear@0
|
388 const float top = -1.1f; // applied as a vertex shader uniform. In the future when we have a more formal graphics
|
nuclear@0
|
389 const float right = 1.0f; // API abstraction we may move this draw to an overlay layer or to a more formal
|
nuclear@0
|
390 const float bottom = 0.9f; // model/mesh scheme with a perspective projection.
|
nuclear@0
|
391
|
nuclear@0
|
392 pVertices[0] = HASWVertex(left, top, 0.f, Color(255, 255, 255, 255), 0.f, flip ? 1.f : 0.f);
|
nuclear@0
|
393 pVertices[1] = HASWVertex(left, bottom, 0.f, Color(255, 255, 255, 255), 0.f, flip ? 0.f : 1.f);
|
nuclear@0
|
394 pVertices[2] = HASWVertex(right, top, 0.f, Color(255, 255, 255, 255), 1.f, flip ? 1.f : 0.f);
|
nuclear@0
|
395 pVertices[3] = HASWVertex(right, bottom, 0.f, Color(255, 255, 255, 255), 1.f, flip ? 0.f : 1.f);
|
nuclear@0
|
396
|
nuclear@0
|
397 pVB->Unmap(pVertices);
|
nuclear@0
|
398 }
|
nuclear@0
|
399 }
|
nuclear@0
|
400
|
nuclear@0
|
401 // We don't bind or initialize the vertex arrays here.
|
nuclear@0
|
402 if (!VAO && GLE_ARB_vertex_array_object)
|
nuclear@0
|
403 {
|
nuclear@0
|
404 OVR_ASSERT(!VAOInitialized);
|
nuclear@0
|
405 glGenVertexArrays(1, &VAO);
|
nuclear@0
|
406 }
|
nuclear@0
|
407 }
|
nuclear@0
|
408
|
nuclear@0
|
409
|
nuclear@0
|
410 void HSWDisplay::RenderInternal(ovrEyeType eye, const ovrTexture* eyeTexture)
|
nuclear@0
|
411 {
|
nuclear@0
|
412 if(RenderEnabled && eyeTexture)
|
nuclear@0
|
413 {
|
nuclear@0
|
414 // We need to render to the eyeTexture with the texture viewport.
|
nuclear@0
|
415 // Setup rendering to the texture.
|
nuclear@0
|
416 ovrGLTexture* eyeTextureGL = const_cast<ovrGLTexture*>(reinterpret_cast<const ovrGLTexture*>(eyeTexture));
|
nuclear@0
|
417 OVR_ASSERT(eyeTextureGL->Texture.Header.API == ovrRenderAPI_OpenGL);
|
nuclear@0
|
418
|
nuclear@0
|
419 GL::AutoContext autoGLContext(GLContext); // Saves the current GL context, binds our GLContext, then at the end of scope re-binds the current GL context.
|
nuclear@0
|
420
|
nuclear@0
|
421 // Load the graphics if not loaded already.
|
nuclear@0
|
422 if (!pTexture)
|
nuclear@0
|
423 LoadGraphics();
|
nuclear@0
|
424
|
nuclear@0
|
425 // Calculate ortho projection.
|
nuclear@0
|
426 GetOrthoProjection(RenderState, OrthoProjection);
|
nuclear@0
|
427
|
nuclear@0
|
428 // Set the rendering to be to the eye texture.
|
nuclear@0
|
429 glBindFramebuffer(GL_FRAMEBUFFER, FrameBuffer);
|
nuclear@0
|
430 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, eyeTextureGL->OGL.TexId, 0);
|
nuclear@0
|
431 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); // We aren't using depth, as we currently want this to overwrite everything.
|
nuclear@0
|
432 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
nuclear@0
|
433 OVR_ASSERT(status == GL_FRAMEBUFFER_COMPLETE); OVR_UNUSED(status);
|
nuclear@0
|
434
|
nuclear@0
|
435 // Set up the viewport
|
nuclear@0
|
436 const GLint x = (GLint)eyeTextureGL->Texture.Header.RenderViewport.Pos.x;
|
nuclear@0
|
437 const GLint y = (GLint)eyeTextureGL->Texture.Header.RenderViewport.Pos.y; // Note that GL uses bottom-up coordinates.
|
nuclear@0
|
438 const GLsizei w = (GLsizei)eyeTextureGL->Texture.Header.RenderViewport.Size.w;
|
nuclear@0
|
439 const GLsizei h = (GLsizei)eyeTextureGL->Texture.Header.RenderViewport.Size.h;
|
nuclear@0
|
440 glViewport(x, y, w, h);
|
nuclear@0
|
441
|
nuclear@0
|
442 // Set fixed-function render states.
|
nuclear@0
|
443 //glDepthRange(0.0, 1.0); // This is the default
|
nuclear@0
|
444 glDepthMask(GL_FALSE);
|
nuclear@0
|
445 glDisable(GL_DEPTH_TEST);
|
nuclear@0
|
446 glFrontFace(GL_CW);
|
nuclear@0
|
447 glEnable(GL_BLEND);
|
nuclear@0
|
448 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
nuclear@0
|
449
|
nuclear@0
|
450 // Enable the buffer and shaders we use.
|
nuclear@0
|
451 ShaderFill fill(pShaderSet);
|
nuclear@0
|
452 if (pTexture)
|
nuclear@0
|
453 fill.SetTexture(0, pTexture);
|
nuclear@0
|
454
|
nuclear@0
|
455 // Set shader uniforms.
|
nuclear@0
|
456 const float scale = HSWDISPLAY_SCALE * ((RenderState.OurHMDInfo.HmdType == HmdType_DK1) ? 0.70f : 1.f);
|
nuclear@0
|
457 pShaderSet->SetUniform2f("Scale", scale, scale / 2.f); // X and Y scale. Y is a fixed proportion to X in order to give a certain aspect ratio.
|
nuclear@0
|
458 pShaderSet->SetUniform2f("PositionOffset", OrthoProjection[eye].GetTranslation().x, 0.0f);
|
nuclear@0
|
459
|
nuclear@0
|
460 // Set vertex attributes
|
nuclear@0
|
461 if (GLE_ARB_vertex_array_object)
|
nuclear@0
|
462 {
|
nuclear@0
|
463 OVR_ASSERT(VAO != 0);
|
nuclear@0
|
464 glBindVertexArray(VAO);
|
nuclear@0
|
465 }
|
nuclear@0
|
466
|
nuclear@0
|
467 if(!VAOInitialized) // This executes for the case that VAO isn't supported.
|
nuclear@0
|
468 {
|
nuclear@0
|
469 glBindBuffer(GL_ARRAY_BUFFER, pVB->GLBuffer); // This must be called before glVertexAttribPointer is called below.
|
nuclear@0
|
470
|
nuclear@0
|
471 const GLuint shaderProgram = pShaderSet->Prog;
|
nuclear@0
|
472 GLint attributeLocationArray[3];
|
nuclear@0
|
473
|
nuclear@0
|
474 attributeLocationArray[0] = glGetAttribLocation(shaderProgram, "Position");
|
nuclear@0
|
475 glVertexAttribPointer(attributeLocationArray[0], sizeof(Vector3f)/sizeof(float), GL_FLOAT, false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, Pos)));
|
nuclear@0
|
476
|
nuclear@0
|
477 attributeLocationArray[1] = glGetAttribLocation(shaderProgram, "Color");
|
nuclear@0
|
478 glVertexAttribPointer(attributeLocationArray[1], sizeof(Color)/sizeof(uint8_t), GL_UNSIGNED_BYTE, true, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, C))); // True because we want it to convert [0,255] to [0,1] for us.
|
nuclear@0
|
479
|
nuclear@0
|
480 attributeLocationArray[2] = glGetAttribLocation(shaderProgram, "TexCoord");
|
nuclear@0
|
481 glVertexAttribPointer(attributeLocationArray[2], sizeof(float[2])/sizeof(float), GL_FLOAT, false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, U)));
|
nuclear@0
|
482
|
nuclear@0
|
483 for (size_t i = 0; i < OVR_ARRAY_COUNT(attributeLocationArray); i++)
|
nuclear@0
|
484 glEnableVertexAttribArray((GLuint)i);
|
nuclear@0
|
485 }
|
nuclear@0
|
486
|
nuclear@0
|
487 fill.Set(Prim_TriangleStrip);
|
nuclear@0
|
488
|
nuclear@0
|
489 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
nuclear@0
|
490
|
nuclear@0
|
491 if (GLE_ARB_vertex_array_object)
|
nuclear@0
|
492 {
|
nuclear@0
|
493 VAOInitialized = true;
|
nuclear@0
|
494 glBindVertexArray(0);
|
nuclear@0
|
495 }
|
nuclear@0
|
496 }
|
nuclear@0
|
497 }
|
nuclear@0
|
498
|
nuclear@0
|
499
|
nuclear@0
|
500 }}} // namespace OVR::CAPI::GL
|