ovr_sdk

annotate LibOVR/Src/CAPI/GL/CAPI_GL_HSWDisplay.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
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