This reverts commit 4d18bd7cec710b5188d1f6ad5c58010117d7a77d, reversing changes made to 24fda9a7336e4eff1d1310dd3359dd6cbbb6acb5.
Showing the changes to interface/src/ui/ApplicationOverlay.cpp (1 of 10 files). Show all
Unified · Split
| @@ -14,16 +14,13 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <QOpenGLFramebufferObject> |
| 15 | 15 | #include <QOpenGLTexture> |
| 16 | 16 | |
| 17 | −#include <glm/gtc/type_ptr.hpp> | |
| 18 | − | |
| 19 | 17 | #include <avatar/AvatarManager.h> |
| 20 | −#include <DeferredLightingEffect.h> | |
| 21 | 18 | #include <GLMHelpers.h> |
| 19 | +#include <PathUtils.h> | |
| 22 | 20 | #include <gpu/GLBackend.h> |
| 23 | 21 | #include <GLMHelpers.h> |
| 24 | −#include <OffscreenUi.h> | |
| 25 | −#include <CursorManager.h> | |
| 26 | 22 | #include <PerfStat.h> |
| 23 | +#include <OffscreenUi.h> | |
| 27 | 24 | |
| 28 | 25 | #include "AudioClient.h" |
| 29 | 26 | #include "audio/AudioIOStatsRenderer.h" |
| @@ -36,9 +33,6 @@ · 6 unmodified lines | ||
| 36 | 33 | #include "Util.h" |
| 37 | 34 | #include "ui/Stats.h" |
| 38 | 35 | |
| 39 | −#include "../../libraries/render-utils/standardTransformPNTC_vert.h" | |
| 40 | −#include "../../libraries/render-utils/standardDrawTexture_frag.h" | |
| 41 | − | |
| 42 | 36 | // Used to animate the magnification windows |
| 43 | 37 | const float MAG_SPEED = 0.08f; |
| 44 | 38 | |
| @@ -120,6 +114,27 @@ bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, · 75 unmodified lines | ||
| 120 | 114 | } |
| 121 | 115 | } |
| 122 | 116 | |
| 117 | +void ApplicationOverlay::renderReticle(glm::quat orientation, float alpha) { | |
| 118 | + glPushMatrix(); { | |
| 119 | + glm::vec3 axis = glm::axis(orientation); | |
| 120 | + glRotatef(glm::degrees(glm::angle(orientation)), axis.x, axis.y, axis.z); | |
| 121 | + glm::vec3 topLeft = getPoint(reticleSize / 2.0f, -reticleSize / 2.0f); | |
| 122 | + glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f); | |
| 123 | + glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f); | |
| 124 | + glm::vec3 bottomRight = getPoint(-reticleSize / 2.0f, reticleSize / 2.0f); | |
| 125 | + | |
| 126 | + // TODO: this version of renderQuad() needs to take a color | |
| 127 | + glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], alpha }; | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomLeft, bottomRight, topRight, | |
| 132 | + glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f), | |
| 133 | + glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f), | |
| 134 | + reticleColor, _reticleQuad); | |
| 135 | + } glPopMatrix(); | |
| 136 | +} | |
| 137 | + | |
| 123 | 138 | ApplicationOverlay::ApplicationOverlay() : |
| 124 | 139 | _textureFov(glm::radians(DEFAULT_HMD_UI_ANGULAR_SIZE)), |
| 125 | 140 | _textureAspectRatio(1.0f), |
| @@ -133,8 +148,7 @@ ApplicationOverlay::ApplicationOverlay() : · 7 unmodified lines | ||
| 133 | 148 | _previousMagnifierBottomLeft(), |
| 134 | 149 | _previousMagnifierBottomRight(), |
| 135 | 150 | _previousMagnifierTopLeft(), |
| 136 | − _previousMagnifierTopRight(), | |
| 137 | − _framebufferObject(nullptr) | |
| 151 | + _previousMagnifierTopRight() | |
| 138 | 152 | { |
| 139 | 153 | memset(_reticleActive, 0, sizeof(_reticleActive)); |
| 140 | 154 | memset(_magActive, 0, sizeof(_reticleActive)); |
| @@ -181,17 +195,16 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { · 40 unmodified lines | ||
| 181 | 195 | //Handle fading and deactivation/activation of UI |
| 182 | 196 | |
| 183 | 197 | // Render 2D overlay |
| 198 | + glMatrixMode(GL_PROJECTION); | |
| 184 | 199 | glDisable(GL_DEPTH_TEST); |
| 185 | 200 | glDisable(GL_LIGHTING); |
| 186 | 201 | glEnable(GL_BLEND); |
| 187 | 202 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
| 188 | − buildFramebufferObject(); | |
| 189 | − | |
| 190 | − _framebufferObject->bind(); | |
| 203 | + _overlays.buildFramebufferObject(); | |
| 204 | + _overlays.bind(); | |
| 191 | 205 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 192 | 206 | glViewport(0, 0, size.x, size.y); |
| 193 | 207 | |
| 194 | − glMatrixMode(GL_PROJECTION); | |
| 195 | 208 | glPushMatrix(); { |
| 196 | 209 | const float NEAR_CLIP = -10000; |
| 197 | 210 | const float FAR_CLIP = 10000; |
| @@ -213,22 +226,6 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { · 15 unmodified lines | ||
| 213 | 226 | renderPointers(); |
| 214 | 227 | |
| 215 | 228 | renderDomainConnectionStatusBorder(); |
| 216 | − if (_newUiTexture) { | |
| 217 | − glMatrixMode(GL_PROJECTION); | |
| 218 | − glLoadIdentity(); | |
| 219 | − glMatrixMode(GL_MODELVIEW); | |
| 220 | − glLoadIdentity(); | |
| 221 | − glEnable(GL_TEXTURE_2D); | |
| 222 | − glEnable(GL_BLEND); | |
| 223 | − glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 224 | − glBindTexture(GL_TEXTURE_2D, _newUiTexture); | |
| 225 | − DependencyManager::get<GeometryCache>()->renderUnitQuad(); | |
| 226 | − glBindTexture(GL_TEXTURE_2D, 0); | |
| 227 | − glDisable(GL_TEXTURE_2D); | |
| 228 | − glDisable(GL_BLEND); | |
| 229 | − } | |
| 230 | − glLoadIdentity(); | |
| 231 | − | |
| 232 | 229 | |
| 233 | 230 | glMatrixMode(GL_PROJECTION); |
| 234 | 231 | } glPopMatrix(); |
| @@ -238,160 +235,258 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { · 3 unmodified lines | ||
| 238 | 235 | glEnable(GL_LIGHTING); |
| 239 | 236 | glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); |
| 240 | 237 | |
| 241 | − _framebufferObject->release(); | |
| 238 | + _overlays.release(); | |
| 242 | 239 | } |
| 243 | 240 | |
| 244 | −gpu::PipelinePointer ApplicationOverlay::getDrawPipeline() { | |
| 245 | − if (!_standardDrawPipeline) { | |
| 246 | − auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert))); | |
| 247 | − auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag))); | |
| 248 | − auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); | |
| 249 | − gpu::Shader::makeProgram((*program)); | |
| 250 | − | |
| 251 | − auto state = gpu::StatePointer(new gpu::State()); | |
| 252 | − | |
| 253 | − // enable decal blend | |
| 254 | − state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); | |
| 255 | − | |
| 256 | − _standardDrawPipeline.reset(gpu::Pipeline::create(program, state)); | |
| 241 | +// A quick and dirty solution for compositing the old overlay | |
| 242 | +// texture with the new one | |
| 243 | +template <typename F> | |
| 244 | +void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) { | |
| 245 | + glEnable(GL_TEXTURE_2D); | |
| 246 | + glActiveTexture(GL_TEXTURE0); | |
| 247 | + if (firstPassTexture) { | |
| 248 | + glBindTexture(GL_TEXTURE_2D, firstPassTexture); | |
| 249 | + f(); | |
| 257 | 250 | } |
| 258 | − | |
| 259 | − return _standardDrawPipeline; | |
| 260 | −} | |
| 261 | − | |
| 262 | −void ApplicationOverlay::bindCursorTexture(gpu::Batch& batch, uint8_t cursorIndex) { | |
| 263 | − auto& cursorManager = Cursor::Manager::instance(); | |
| 264 | − auto cursor = cursorManager.getCursor(cursorIndex); | |
| 265 | − auto iconId = cursor->getIcon(); | |
| 266 | − if (!_cursors.count(iconId)) { | |
| 267 | − auto iconPath = cursorManager.getIconImage(cursor->getIcon()); | |
| 268 | − _cursors[iconId] = DependencyManager::get<TextureCache>()-> | |
| 269 | − getImageTexture(iconPath); | |
| 251 | + if (secondPassTexture) { | |
| 252 | + glBindTexture(GL_TEXTURE_2D, secondPassTexture); | |
| 253 | + f(); | |
| 270 | 254 | } |
| 271 | − batch.setUniformTexture(0, _cursors[iconId]); | |
| 255 | + glBindTexture(GL_TEXTURE_2D, 0); | |
| 256 | + glDisable(GL_TEXTURE_2D); | |
| 272 | 257 | } |
| 273 | 258 | |
| 274 | −#define CURSOR_PIXEL_SIZE 32.0f | |
| 275 | − | |
| 276 | 259 | // Draws the FBO texture for the screen |
| 277 | −void ApplicationOverlay::displayOverlayTexture(RenderArgs* renderArgs) { | |
| 260 | +void ApplicationOverlay::displayOverlayTexture() { | |
| 278 | 261 | if (_alpha == 0.0f) { |
| 279 | 262 | return; |
| 280 | 263 | } |
| 281 | − | |
| 282 | − renderArgs->_context->syncCache(); | |
| 283 | − | |
| 284 | − gpu::Batch batch; | |
| 285 | − Transform model; | |
| 286 | − //DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, true); | |
| 287 | − batch.setPipeline(getDrawPipeline()); | |
| 288 | − batch.setModelTransform(Transform()); | |
| 289 | − batch.setProjectionTransform(mat4()); | |
| 290 | − batch.setViewTransform(model); | |
| 291 | − batch._glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); | |
| 292 | − batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 293 | − batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 294 | − DependencyManager::get<GeometryCache>()->renderUnitQuad(batch, vec4(vec3(1), _alpha)); | |
| 295 | − | |
| 296 | − //draw the mouse pointer | |
| 297 | − glm::vec2 canvasSize = qApp->getCanvasSize(); | |
| 298 | − | |
| 299 | − // Get the mouse coordinates and convert to NDC [-1, 1] | |
| 300 | − vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY()); | |
| 301 | − mousePosition /= canvasSize; | |
| 302 | − mousePosition *= 2.0f; | |
| 303 | − mousePosition -= 1.0f; | |
| 304 | − mousePosition.y *= -1.0f; | |
| 305 | − model.setTranslation(vec3(mousePosition, 0)); | |
| 306 | − glm::vec2 mouseSize = CURSOR_PIXEL_SIZE / canvasSize; | |
| 307 | − model.setScale(vec3(mouseSize, 1.0f)); | |
| 308 | − batch.setModelTransform(model); | |
| 309 | − bindCursorTexture(batch); | |
| 310 | − glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 311 | − DependencyManager::get<GeometryCache>()->renderUnitQuad(batch, vec4(1)); | |
| 312 | − renderArgs->_context->render(batch); | |
| 313 | −} | |
| 314 | − | |
| 315 | − | |
| 316 | −static gpu::BufferPointer _hemiVertices; | |
| 317 | −static gpu::BufferPointer _hemiIndices; | |
| 318 | −static int _hemiIndexCount{ 0 }; | |
| 264 | + glMatrixMode(GL_PROJECTION); | |
| 265 | + glPushMatrix(); { | |
| 266 | + glLoadIdentity(); | |
| 267 | + glDisable(GL_DEPTH_TEST); | |
| 268 | + glDisable(GL_LIGHTING); | |
| 269 | + glEnable(GL_BLEND); | |
| 270 | + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 271 | + glViewport(0, 0, qApp->getDeviceSize().width(), qApp->getDeviceSize().height()); | |
| 272 | + | |
| 273 | + static const glm::vec2 topLeft(-1, 1); | |
| 274 | + static const glm::vec2 bottomRight(1, -1); | |
| 275 | + static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); | |
| 276 | + static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); | |
| 277 | + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 278 | + DependencyManager::get<GeometryCache>()->renderQuad( | |
| 279 | + topLeft, bottomRight, | |
| 280 | + texCoordTopLeft, texCoordBottomRight, | |
| 281 | + glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); | |
| 282 | + }); | |
| 283 | + | |
| 284 | + if (!_crosshairTexture) { | |
| 285 | + _crosshairTexture = DependencyManager::get<TextureCache>()-> | |
| 286 | + getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png"); | |
| 287 | + } | |
| 319 | 288 | |
| 320 | −glm::vec2 getPolarCoordinates(const PalmData& palm) { | |
| 321 | − MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 322 | − auto avatarOrientation = myAvatar->getOrientation(); | |
| 323 | − auto eyePos = myAvatar->getDefaultEyePosition(); | |
| 324 | − glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); | |
| 325 | − // Direction of the tip relative to the eye | |
| 326 | − glm::vec3 tipDirection = tip - eyePos; | |
| 327 | − // orient into avatar space | |
| 328 | − tipDirection = glm::inverse(avatarOrientation) * tipDirection; | |
| 329 | − // Normalize for trig functions | |
| 330 | − tipDirection = glm::normalize(tipDirection); | |
| 331 | − // Convert to polar coordinates | |
| 332 | − glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y)); | |
| 333 | − return polar; | |
| 289 | + //draw the mouse pointer | |
| 290 | + glm::vec2 canvasSize = qApp->getCanvasSize(); | |
| 291 | + glm::vec2 mouseSize = 32.0f / canvasSize; | |
| 292 | + auto mouseTopLeft = topLeft * mouseSize; | |
| 293 | + auto mouseBottomRight = bottomRight * mouseSize; | |
| 294 | + vec2 mousePosition = vec2(qApp->getMouseX(), qApp->getMouseY()); | |
| 295 | + mousePosition /= canvasSize; | |
| 296 | + mousePosition *= 2.0f; | |
| 297 | + mousePosition -= 1.0f; | |
| 298 | + mousePosition.y *= -1.0f; | |
| 299 | + | |
| 300 | + glEnable(GL_TEXTURE_2D); | |
| 301 | + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 302 | + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 303 | + glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 304 | + DependencyManager::get<GeometryCache>()->renderQuad( | |
| 305 | + mouseTopLeft + mousePosition, mouseBottomRight + mousePosition, | |
| 306 | + texCoordTopLeft, texCoordBottomRight, | |
| 307 | + reticleColor); | |
| 308 | + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 309 | + glDisable(GL_TEXTURE_2D); | |
| 310 | + } glPopMatrix(); | |
| 334 | 311 | } |
| 335 | 312 | |
| 336 | 313 | // Draws the FBO texture for Oculus rift. |
| 337 | −void ApplicationOverlay::displayOverlayTextureHmd(RenderArgs* renderArgs, Camera& whichCamera) { | |
| 314 | +void ApplicationOverlay::displayOverlayTextureHmd(Camera& whichCamera) { | |
| 338 | 315 | if (_alpha == 0.0f) { |
| 339 | 316 | return; |
| 340 | 317 | } |
| 341 | 318 | |
| 342 | − renderArgs->_context->syncCache(); | |
| 319 | + glEnable(GL_BLEND); | |
| 320 | + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 321 | + glEnable(GL_DEPTH_TEST); | |
| 322 | + glDepthMask(GL_TRUE); | |
| 323 | + glDisable(GL_LIGHTING); | |
| 324 | + glEnable(GL_ALPHA_TEST); | |
| 325 | + glAlphaFunc(GL_GREATER, 0.01f); | |
| 343 | 326 | |
| 344 | − gpu::Batch batch; | |
| 345 | − batch.setPipeline(getDrawPipeline()); | |
| 346 | − batch._glDisable(GL_DEPTH_TEST); | |
| 347 | − batch._glDisable(GL_CULL_FACE); | |
| 348 | − batch._glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture()); | |
| 349 | − batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
| 350 | − batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |
| 351 | − batch.setProjectionTransform(whichCamera.getProjection()); | |
| 352 | − batch.setViewTransform(Transform()); | |
| 353 | 327 | |
| 328 | + //Update and draw the magnifiers | |
| 354 | 329 | MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); |
| 355 | − const quat& avatarOrientation = myAvatar->getOrientation(); | |
| 356 | − quat hmdOrientation = qApp->getCamera()->getHmdRotation(); | |
| 357 | − vec3 hmdPosition = glm::inverse(avatarOrientation) * qApp->getCamera()->getHmdPosition(); | |
| 358 | − mat4 overlayXfm = glm::mat4_cast(glm::inverse(hmdOrientation)) * glm::translate(mat4(), -hmdPosition); | |
| 359 | − batch.setModelTransform(Transform(overlayXfm)); | |
| 360 | − drawSphereSection(batch); | |
| 330 | + const glm::quat& orientation = myAvatar->getOrientation(); | |
| 331 | + // Always display the HMD overlay relative to the camera position but | |
| 332 | + // remove the HMD pose offset. This results in an overlay that sticks with you | |
| 333 | + // even in third person mode, but isn't drawn at a fixed distance. | |
| 334 | + glm::vec3 position = whichCamera.getPosition(); | |
| 335 | + position -= qApp->getCamera()->getHmdPosition(); | |
| 336 | + const float scale = myAvatar->getScale() * _oculusUIRadius; | |
| 337 | + | |
| 338 | +// glm::vec3 eyeOffset = setEyeOffsetPosition; | |
| 339 | + glMatrixMode(GL_MODELVIEW); | |
| 340 | + glPushMatrix(); { | |
| 341 | + glTranslatef(position.x, position.y, position.z); | |
| 342 | + glm::mat4 rotation = glm::toMat4(orientation); | |
| 343 | + glMultMatrixf(&rotation[0][0]); | |
| 344 | + glScalef(scale, scale, scale); | |
| 345 | + for (int i = 0; i < NUMBER_OF_RETICLES; i++) { | |
| 346 | + | |
| 347 | + if (_magActive[i]) { | |
| 348 | + _magSizeMult[i] += MAG_SPEED; | |
| 349 | + if (_magSizeMult[i] > 1.0f) { | |
| 350 | + _magSizeMult[i] = 1.0f; | |
| 351 | + } | |
| 352 | + } else { | |
| 353 | + _magSizeMult[i] -= MAG_SPEED; | |
| 354 | + if (_magSizeMult[i] < 0.0f) { | |
| 355 | + _magSizeMult[i] = 0.0f; | |
| 356 | + } | |
| 357 | + } | |
| 358 | + | |
| 359 | + if (_magSizeMult[i] > 0.0f) { | |
| 360 | + //Render magnifier, but dont show border for mouse magnifier | |
| 361 | + glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 362 | + _reticlePosition[MOUSE].y())); | |
| 363 | + with_each_texture(_overlays.getTexture(), 0, [&] { | |
| 364 | + renderMagnifier(projection, _magSizeMult[i], i != MOUSE); | |
| 365 | + }); | |
| 366 | + } | |
| 367 | + } | |
| 368 | + | |
| 369 | + glDepthMask(GL_FALSE); | |
| 370 | + glDisable(GL_ALPHA_TEST); | |
| 371 | + | |
| 372 | + static float textureFOV = 0.0f, textureAspectRatio = 1.0f; | |
| 373 | + if (textureFOV != _textureFov || | |
| 374 | + textureAspectRatio != _textureAspectRatio) { | |
| 375 | + textureFOV = _textureFov; | |
| 376 | + textureAspectRatio = _textureAspectRatio; | |
| 377 | + | |
| 378 | + _overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80); | |
| 379 | + } | |
| 361 | 380 | |
| 381 | + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 382 | + _overlays.render(); | |
| 383 | + }); | |
| 362 | 384 | |
| 363 | − bindCursorTexture(batch); | |
| 364 | − auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 365 | − vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize); | |
| 366 | − //Controller Pointers | |
| 367 | − for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) { | |
| 368 | − PalmData& palm = myAvatar->getHand()->getPalms()[i]; | |
| 369 | − if (palm.isActive()) { | |
| 370 | − glm::vec2 polar = getPolarCoordinates(palm); | |
| 371 | − // Convert to quaternion | |
| 372 | − mat4 pointerXfm = glm::mat4_cast(quat(vec3(polar.y, -polar.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); | |
| 373 | − mat4 reticleXfm = overlayXfm * pointerXfm; | |
| 374 | − reticleXfm = glm::scale(reticleXfm, reticleScale); | |
| 375 | − batch.setModelTransform(reticleXfm); | |
| 376 | − // Render reticle at location | |
| 377 | − geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad); | |
| 385 | + if (!Application::getInstance()->isMouseHidden()) { | |
| 386 | + renderPointersOculus(); | |
| 378 | 387 | } |
| 388 | + glDepthMask(GL_TRUE); | |
| 389 | + glDisable(GL_TEXTURE_2D); | |
| 390 | + | |
| 391 | + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 392 | + glEnable(GL_LIGHTING); | |
| 393 | + } glPopMatrix(); | |
| 394 | +} | |
| 395 | + | |
| 396 | +// Draws the FBO texture for 3DTV. | |
| 397 | +void ApplicationOverlay::displayOverlayTextureStereo(Camera& whichCamera, float aspectRatio, float fov) { | |
| 398 | + if (_alpha == 0.0f) { | |
| 399 | + return; | |
| 379 | 400 | } |
| 401 | + | |
| 402 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 403 | + const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation(); | |
| 404 | + | |
| 405 | + glEnable(GL_BLEND); | |
| 406 | + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 407 | + glEnable(GL_DEPTH_TEST); | |
| 408 | + glDisable(GL_LIGHTING); | |
| 409 | + | |
| 410 | + glMatrixMode(GL_MODELVIEW); | |
| 411 | + | |
| 412 | + glPushMatrix(); | |
| 413 | + glLoadIdentity(); | |
| 414 | + // Transform to world space | |
| 415 | + glm::quat rotation = whichCamera.getRotation(); | |
| 416 | + glm::vec3 axis2 = glm::axis(rotation); | |
| 417 | + glRotatef(-glm::degrees(glm::angle(rotation)), axis2.x, axis2.y, axis2.z); | |
| 418 | + glTranslatef(viewMatrixTranslation.x, viewMatrixTranslation.y, viewMatrixTranslation.z); | |
| 419 | + | |
| 420 | + // Translate to the front of the camera | |
| 421 | + glm::vec3 pos = whichCamera.getPosition(); | |
| 422 | + glm::quat rot = myAvatar->getOrientation(); | |
| 423 | + glm::vec3 axis = glm::axis(rot); | |
| 424 | + | |
| 425 | + glTranslatef(pos.x, pos.y, pos.z); | |
| 426 | + glRotatef(glm::degrees(glm::angle(rot)), axis.x, axis.y, axis.z); | |
| 427 | + | |
| 428 | + glm::vec4 overlayColor = {1.0f, 1.0f, 1.0f, _alpha}; | |
| 429 | + | |
| 430 | + //Render | |
| 431 | + const GLfloat distance = 1.0f; | |
| 432 | + | |
| 433 | + const GLfloat halfQuadHeight = distance * tan(fov); | |
| 434 | + const GLfloat halfQuadWidth = halfQuadHeight * aspectRatio; | |
| 435 | + const GLfloat quadWidth = halfQuadWidth * 2.0f; | |
| 436 | + const GLfloat quadHeight = halfQuadHeight * 2.0f; | |
| 437 | + | |
| 438 | + GLfloat x = -halfQuadWidth; | |
| 439 | + GLfloat y = -halfQuadHeight; | |
| 440 | + glDisable(GL_DEPTH_TEST); | |
| 380 | 441 | |
| 381 | − //Mouse Pointer | |
| 382 | − if (_reticleActive[MOUSE]) { | |
| 383 | − glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 384 | − _reticlePosition[MOUSE].y())); | |
| 385 | − mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); | |
| 386 | − mat4 reticleXfm = overlayXfm * pointerXfm; | |
| 387 | − reticleXfm = glm::scale(reticleXfm, reticleScale); | |
| 388 | − batch.setModelTransform(reticleXfm); | |
| 389 | − geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad); | |
| 442 | + with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { | |
| 443 | + DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance), | |
| 444 | + glm::vec3(x + quadWidth, y + quadHeight, -distance), | |
| 445 | + glm::vec3(x + quadWidth, y, -distance), | |
| 446 | + glm::vec3(x, y, -distance), | |
| 447 | + glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f), | |
| 448 | + glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f), | |
| 449 | + overlayColor); | |
| 450 | + }); | |
| 451 | + | |
| 452 | + if (!_crosshairTexture) { | |
| 453 | + _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + | |
| 454 | + "images/sixense-reticle.png"); | |
| 390 | 455 | } |
| 456 | + | |
| 457 | + //draw the mouse pointer | |
| 458 | + glEnable(GL_BLEND); | |
| 459 | + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 460 | + glEnable(GL_TEXTURE_2D); | |
| 461 | + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 462 | + glm::vec2 canvasSize = qApp->getCanvasSize(); | |
| 463 | + const float reticleSize = 40.0f / canvasSize.x * quadWidth; | |
| 464 | + x -= reticleSize / 2.0f; | |
| 465 | + y += reticleSize / 2.0f; | |
| 466 | + const float mouseX = (qApp->getMouseX() / (float)canvasSize.x) * quadWidth; | |
| 467 | + const float mouseY = (1.0 - (qApp->getMouseY() / (float)canvasSize.y)) * quadHeight; | |
| 468 | + | |
| 469 | + glm::vec4 reticleColor = { RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], 1.0f }; | |
| 391 | 470 | |
| 392 | − renderArgs->_context->render(batch); | |
| 393 | −} | |
| 471 | + DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x + mouseX, y + mouseY, -distance), | |
| 472 | + glm::vec3(x + mouseX + reticleSize, y + mouseY, -distance), | |
| 473 | + glm::vec3(x + mouseX + reticleSize, y + mouseY - reticleSize, -distance), | |
| 474 | + glm::vec3(x + mouseX, y + mouseY - reticleSize, -distance), | |
| 475 | + glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 0.0f), | |
| 476 | + glm::vec2(1.0f, 1.0f), glm::vec2(0.0f, 1.0f), | |
| 477 | + reticleColor, _reticleQuad); | |
| 394 | 478 | |
| 479 | + glEnable(GL_DEPTH_TEST); | |
| 480 | + | |
| 481 | + glPopMatrix(); | |
| 482 | + | |
| 483 | + glDepthMask(GL_TRUE); | |
| 484 | + glBindTexture(GL_TEXTURE_2D, 0); | |
| 485 | + glDisable(GL_TEXTURE_2D); | |
| 486 | + | |
| 487 | + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); | |
| 488 | + glEnable(GL_LIGHTING); | |
| 489 | +} | |
| 395 | 490 | |
| 396 | 491 | void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const { |
| 397 | 492 | cursorPos *= qApp->getCanvasSize(); |
| @@ -421,6 +516,22 @@ void ApplicationOverlay::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origi · 23 unmodified lines | ||
| 421 | 516 | direction = glm::normalize(intersectionWithUi - origin); |
| 422 | 517 | } |
| 423 | 518 | |
| 519 | +glm::vec2 getPolarCoordinates(const PalmData& palm) { | |
| 520 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 521 | + auto avatarOrientation = myAvatar->getOrientation(); | |
| 522 | + auto eyePos = myAvatar->getDefaultEyePosition(); | |
| 523 | + glm::vec3 tip = myAvatar->getLaserPointerTipPosition(&palm); | |
| 524 | + // Direction of the tip relative to the eye | |
| 525 | + glm::vec3 tipDirection = tip - eyePos; | |
| 526 | + // orient into avatar space | |
| 527 | + tipDirection = glm::inverse(avatarOrientation) * tipDirection; | |
| 528 | + // Normalize for trig functions | |
| 529 | + tipDirection = glm::normalize(tipDirection); | |
| 530 | + // Convert to polar coordinates | |
| 531 | + glm::vec2 polar(glm::atan(tipDirection.x, -tipDirection.z), glm::asin(tipDirection.y)); | |
| 532 | + return polar; | |
| 533 | +} | |
| 534 | + | |
| 424 | 535 | //Caculate the click location using one of the sixense controllers. Scale is not applied |
| 425 | 536 | QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { |
| 426 | 537 | QPoint rv; |
| @@ -471,9 +582,13 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position, · 44 unmodified lines | ||
| 471 | 582 | |
| 472 | 583 | //Renders optional pointers |
| 473 | 584 | void ApplicationOverlay::renderPointers() { |
| 474 | − //glEnable(GL_TEXTURE_2D); | |
| 475 | − //glEnable(GL_BLEND); | |
| 476 | − //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 585 | + //lazily load crosshair texture | |
| 586 | + if (_crosshairTexture == 0) { | |
| 587 | + _crosshairTexture = TextureCache::getImageTexture(PathUtils::resourcesPath() + "images/sixense-reticle.png"); | |
| 588 | + } | |
| 589 | + glEnable(GL_TEXTURE_2D); | |
| 590 | + glEnable(GL_BLEND); | |
| 591 | + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 477 | 592 | |
| 478 | 593 | //glActiveTexture(GL_TEXTURE0); |
| 479 | 594 | //bindCursorTexture(); |
| @@ -635,6 +750,43 @@ void ApplicationOverlay::renderControllerPointers() { · 155 unmodified lines | ||
| 635 | 750 | } |
| 636 | 751 | } |
| 637 | 752 | |
| 753 | +void ApplicationOverlay::renderPointersOculus() { | |
| 754 | + | |
| 755 | + glEnable(GL_BLEND); | |
| 756 | + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| 757 | + glEnable(GL_TEXTURE_2D); | |
| 758 | + | |
| 759 | + glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(_crosshairTexture)); | |
| 760 | + glDisable(GL_DEPTH_TEST); | |
| 761 | + | |
| 762 | + glMatrixMode(GL_MODELVIEW); | |
| 763 | + | |
| 764 | + //Controller Pointers | |
| 765 | + MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); | |
| 766 | + for (int i = 0; i < (int)myAvatar->getHand()->getNumPalms(); i++) { | |
| 767 | + PalmData& palm = myAvatar->getHand()->getPalms()[i]; | |
| 768 | + if (palm.isActive()) { | |
| 769 | + glm::vec2 polar = getPolarCoordinates(palm); | |
| 770 | + // Convert to quaternion | |
| 771 | + glm::quat orientation = glm::quat(glm::vec3(polar.y, -polar.x, 0.0f)); | |
| 772 | + // Render reticle at location | |
| 773 | + renderReticle(orientation, _alpha); | |
| 774 | + } | |
| 775 | + } | |
| 776 | + | |
| 777 | + //Mouse Pointer | |
| 778 | + if (_reticleActive[MOUSE]) { | |
| 779 | + glm::vec2 projection = screenToSpherical(glm::vec2(_reticlePosition[MOUSE].x(), | |
| 780 | + _reticlePosition[MOUSE].y())); | |
| 781 | + glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f)); | |
| 782 | + renderReticle(orientation, _alpha); | |
| 783 | + } | |
| 784 | + | |
| 785 | + glEnable(GL_DEPTH_TEST); | |
| 786 | + glDisable(GL_TEXTURE_2D); | |
| 787 | + glDisable(GL_BLEND); | |
| 788 | +} | |
| 789 | + | |
| 638 | 790 | //Renders a small magnification of the currently bound texture at the coordinates |
| 639 | 791 | void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool showBorder) { |
| 640 | 792 | if (!_magnifier) { |
| @@ -915,109 +1067,119 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() { · 274 unmodified lines | ||
| 915 | 1067 | } |
| 916 | 1068 | } |
| 917 | 1069 | |
| 1070 | +ApplicationOverlay::TexturedHemisphere::TexturedHemisphere() : | |
| 1071 | + _vertices(0), | |
| 1072 | + _indices(0), | |
| 1073 | + _framebufferObject(NULL), | |
| 1074 | + _vbo(0, 0) { | |
| 1075 | +} | |
| 918 | 1076 | |
| 919 | −void ApplicationOverlay::buildHemiVertices( | |
| 920 | − const float fov, const float aspectRatio, const int slices, const int stacks) { | |
| 921 | − static float textureFOV = 0.0f, textureAspectRatio = 1.0f; | |
| 922 | − if (textureFOV == fov && textureAspectRatio == aspectRatio) { | |
| 923 | − return; | |
| 1077 | +ApplicationOverlay::TexturedHemisphere::~TexturedHemisphere() { | |
| 1078 | + cleanupVBO(); | |
| 1079 | + if (_framebufferObject != NULL) { | |
| 1080 | + delete _framebufferObject; | |
| 924 | 1081 | } |
| 1082 | +} | |
| 925 | 1083 | |
| 926 | − textureFOV = fov; | |
| 927 | − textureAspectRatio = aspectRatio; | |
| 928 | − | |
| 929 | − auto geometryCache = DependencyManager::get<GeometryCache>(); | |
| 930 | − | |
| 931 | − _hemiVertices = gpu::BufferPointer(new gpu::Buffer()); | |
| 932 | − _hemiIndices = gpu::BufferPointer(new gpu::Buffer()); | |
| 1084 | +void ApplicationOverlay::TexturedHemisphere::bind() { | |
| 1085 | + _framebufferObject->bind(); | |
| 1086 | +} | |
| 933 | 1087 | |
| 1088 | +void ApplicationOverlay::TexturedHemisphere::release() { | |
| 1089 | + _framebufferObject->release(); | |
| 1090 | +} | |
| 934 | 1091 | |
| 1092 | +void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov, | |
| 1093 | + const float aspectRatio, | |
| 1094 | + const int slices, | |
| 1095 | + const int stacks) { | |
| 935 | 1096 | if (fov >= PI) { |
| 936 | 1097 | qDebug() << "TexturedHemisphere::buildVBO(): FOV greater or equal than Pi will create issues"; |
| 937 | 1098 | } |
| 938 | − | |
| 1099 | + // Cleanup old VBO if necessary | |
| 1100 | + cleanupVBO(); | |
| 1101 | + | |
| 939 | 1102 | //UV mapping source: http://www.mvps.org/directx/articles/spheremap.htm |
| 940 | 1103 | |
| 941 | − vec3 pos; | |
| 942 | − vec2 uv; | |
| 1104 | + // Compute number of vertices needed | |
| 1105 | + _vertices = slices * stacks; | |
| 1106 | + | |
| 943 | 1107 | // Compute vertices positions and texture UV coordinate |
| 944 | − // Create and write to buffer | |
| 1108 | + TextureVertex* vertexData = new TextureVertex[_vertices]; | |
| 1109 | + TextureVertex* vertexPtr = &vertexData[0]; | |
| 945 | 1110 | for (int i = 0; i < stacks; i++) { |
| 946 | − uv.y = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f | |
| 1111 | + float stacksRatio = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f | |
| 947 | 1112 | // abs(theta) <= fov / 2.0f |
| 948 | − float pitch = -fov * (uv.y - 0.5f); | |
| 1113 | + float pitch = -fov * (stacksRatio - 0.5f); | |
| 1114 | + | |
| 949 | 1115 | for (int j = 0; j < slices; j++) { |
| 950 | − uv.x = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f | |
| 1116 | + float slicesRatio = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f | |
| 951 | 1117 | // abs(phi) <= fov * aspectRatio / 2.0f |
| 952 | − float yaw = -fov * aspectRatio * (uv.x - 0.5f); | |
| 953 | − pos = getPoint(yaw, pitch); | |
| 954 | − static const vec4 color(1); | |
| 955 | − _hemiVertices->append(sizeof(pos), (gpu::Byte*)&pos); | |
| 956 | − _hemiVertices->append(sizeof(vec2), (gpu::Byte*)&uv); | |
| 957 | − _hemiVertices->append(sizeof(vec4), (gpu::Byte*)&color); | |
| 1118 | + float yaw = -fov * aspectRatio * (slicesRatio - 0.5f); | |
| 1119 | + | |
| 1120 | + vertexPtr->position = getPoint(yaw, pitch); | |
| 1121 | + vertexPtr->uv.x = slicesRatio; | |
| 1122 | + vertexPtr->uv.y = stacksRatio; | |
| 1123 | + vertexPtr++; | |
| 958 | 1124 | } |
| 959 | 1125 | } |
| 1126 | + // Create and write to buffer | |
| 1127 | + glGenBuffers(1, &_vbo.first); | |
| 1128 | + glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); | |
| 1129 | + static const int BYTES_PER_VERTEX = sizeof(TextureVertex); | |
| 1130 | + glBufferData(GL_ARRAY_BUFFER, _vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW); | |
| 1131 | + delete[] vertexData; | |
| 1132 | + | |
| 960 | 1133 | |
| 961 | 1134 | // Compute number of indices needed |
| 962 | 1135 | static const int VERTEX_PER_TRANGLE = 3; |
| 963 | 1136 | static const int TRIANGLE_PER_RECTANGLE = 2; |
| 964 | 1137 | int numberOfRectangles = (slices - 1) * (stacks - 1); |
| 965 | − _hemiIndexCount = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; | |
| 1138 | + _indices = numberOfRectangles * TRIANGLE_PER_RECTANGLE * VERTEX_PER_TRANGLE; | |
| 966 | 1139 | |
| 967 | 1140 | // Compute indices order |
| 968 | − std::vector<GLushort> indices; | |
| 1141 | + GLushort* indexData = new GLushort[_indices]; | |
| 1142 | + GLushort* indexPtr = indexData; | |
| 969 | 1143 | for (int i = 0; i < stacks - 1; i++) { |
| 970 | 1144 | for (int j = 0; j < slices - 1; j++) { |
| 971 | 1145 | GLushort bottomLeftIndex = i * slices + j; |
| 972 | 1146 | GLushort bottomRightIndex = bottomLeftIndex + 1; |
| 973 | 1147 | GLushort topLeftIndex = bottomLeftIndex + slices; |
| 974 | 1148 | GLushort topRightIndex = topLeftIndex + 1; |
| 975 | − // FIXME make a z-order curve for better vertex cache locality | |
| 976 | − indices.push_back(topLeftIndex); | |
| 977 | − indices.push_back(bottomLeftIndex); | |
| 978 | − indices.push_back(topRightIndex); | |
| 979 | − | |
| 980 | − indices.push_back(topRightIndex); | |
| 981 | − indices.push_back(bottomLeftIndex); | |
| 982 | − indices.push_back(bottomRightIndex); | |
| 1149 | + | |
| 1150 | + *(indexPtr++) = topLeftIndex; | |
| 1151 | + *(indexPtr++) = bottomLeftIndex; | |
| 1152 | + *(indexPtr++) = topRightIndex; | |
| 1153 | + | |
| 1154 | + *(indexPtr++) = topRightIndex; | |
| 1155 | + *(indexPtr++) = bottomLeftIndex; | |
| 1156 | + *(indexPtr++) = bottomRightIndex; | |
| 983 | 1157 | } |
| 984 | 1158 | } |
| 985 | − _hemiIndices->append(sizeof(GLushort) * indices.size(), (gpu::Byte*)&indices[0]); | |
| 986 | −} | |
| 987 | − | |
| 988 | − | |
| 989 | −void ApplicationOverlay::drawSphereSection(gpu::Batch& batch) { | |
| 990 | − buildHemiVertices(_textureFov, _textureAspectRatio, 80, 80); | |
| 991 | − static const int VERTEX_DATA_SLOT = 0; | |
| 992 | − static const int TEXTURE_DATA_SLOT = 1; | |
| 993 | − static const int COLOR_DATA_SLOT = 2; | |
| 994 | − gpu::Stream::FormatPointer streamFormat(new gpu::Stream::Format()); // 1 for everyone | |
| 995 | − streamFormat->setAttribute(gpu::Stream::POSITION, VERTEX_DATA_SLOT, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); | |
| 996 | − streamFormat->setAttribute(gpu::Stream::TEXCOORD, TEXTURE_DATA_SLOT, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV)); | |
| 997 | − streamFormat->setAttribute(gpu::Stream::COLOR, COLOR_DATA_SLOT, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA)); | |
| 998 | − batch.setInputFormat(streamFormat); | |
| 999 | − | |
| 1000 | − static const int VERTEX_STRIDE = sizeof(vec3) + sizeof(vec2) + sizeof(vec4); | |
| 1001 | − gpu::BufferView posView(_hemiVertices, 0, _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::POSITION)._element); | |
| 1002 | − gpu::BufferView uvView(_hemiVertices, sizeof(vec3), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::TEXCOORD)._element); | |
| 1003 | − gpu::BufferView colView(_hemiVertices, sizeof(vec3) + sizeof(vec2), _hemiVertices->getSize(), VERTEX_STRIDE, streamFormat->getAttributes().at(gpu::Stream::COLOR)._element); | |
| 1004 | − batch.setInputBuffer(VERTEX_DATA_SLOT, posView); | |
| 1005 | − batch.setInputBuffer(TEXTURE_DATA_SLOT, uvView); | |
| 1006 | − batch.setInputBuffer(COLOR_DATA_SLOT, colView); | |
| 1007 | − batch.setIndexBuffer(gpu::UINT16, _hemiIndices, 0); | |
| 1008 | − batch.drawIndexed(gpu::TRIANGLES, _hemiIndexCount); | |
| 1159 | + // Create and write to buffer | |
| 1160 | + glGenBuffers(1, &_vbo.second); | |
| 1161 | + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); | |
| 1162 | + static const int BYTES_PER_INDEX = sizeof(GLushort); | |
| 1163 | + glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW); | |
| 1164 | + delete[] indexData; | |
| 1009 | 1165 | } |
| 1010 | 1166 | |
| 1011 | − | |
| 1012 | −GLuint ApplicationOverlay::getOverlayTexture() { | |
| 1013 | − return _framebufferObject->texture(); | |
| 1167 | +void ApplicationOverlay::TexturedHemisphere::cleanupVBO() { | |
| 1168 | + if (_vbo.first != 0) { | |
| 1169 | + glDeleteBuffers(1, &_vbo.first); | |
| 1170 | + _vbo.first = 0; | |
| 1171 | + } | |
| 1172 | + if (_vbo.second != 0) { | |
| 1173 | + glDeleteBuffers(1, &_vbo.second); | |
| 1174 | + _vbo.second = 0; | |
| 1175 | + } | |
| 1014 | 1176 | } |
| 1015 | 1177 | |
| 1016 | −void ApplicationOverlay::buildFramebufferObject() { | |
| 1178 | +void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() { | |
| 1017 | 1179 | auto canvasSize = qApp->getCanvasSize(); |
| 1018 | 1180 | QSize fboSize = QSize(canvasSize.x, canvasSize.y); |
| 1019 | 1181 | if (_framebufferObject != NULL && fboSize == _framebufferObject->size()) { |
| 1020 | − // Already built | |
| 1182 | + // Already build | |
| 1021 | 1183 | return; |
| 1022 | 1184 | } |
| 1023 | 1185 | |
| @@ -1026,7 +1188,7 @@ void ApplicationOverlay::buildFramebufferObject() { · 2 unmodified lines | ||
| 1026 | 1188 | } |
| 1027 | 1189 | |
| 1028 | 1190 | _framebufferObject = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); |
| 1029 | − glBindTexture(GL_TEXTURE_2D, getOverlayTexture()); | |
| 1191 | + glBindTexture(GL_TEXTURE_2D, getTexture()); | |
| 1030 | 1192 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 1031 | 1193 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 1032 | 1194 | glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); |
| @@ -1036,6 +1198,38 @@ void ApplicationOverlay::buildFramebufferObject() { · 3 unmodified lines | ||
| 1036 | 1198 | glBindTexture(GL_TEXTURE_2D, 0); |
| 1037 | 1199 | } |
| 1038 | 1200 | |
| 1201 | +//Renders a hemisphere with texture coordinates. | |
| 1202 | +void ApplicationOverlay::TexturedHemisphere::render() { | |
| 1203 | + if (_framebufferObject == NULL || _vbo.first == 0 || _vbo.second == 0) { | |
| 1204 | + qDebug() << "TexturedHemisphere::render(): Incorrect initialisation"; | |
| 1205 | + return; | |
| 1206 | + } | |
| 1207 | + | |
| 1208 | + glBindBuffer(GL_ARRAY_BUFFER, _vbo.first); | |
| 1209 | + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vbo.second); | |
| 1210 | + | |
| 1211 | + glEnableClientState(GL_VERTEX_ARRAY); | |
| 1212 | + glEnableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 1213 | + | |
| 1214 | + static const int STRIDE = sizeof(TextureVertex); | |
| 1215 | + static const void* VERTEX_POINTER = 0; | |
| 1216 | + static const void* TEX_COORD_POINTER = (void*)sizeof(glm::vec3); | |
| 1217 | + glVertexPointer(3, GL_FLOAT, STRIDE, VERTEX_POINTER); | |
| 1218 | + glTexCoordPointer(2, GL_FLOAT, STRIDE, TEX_COORD_POINTER); | |
| 1219 | + | |
| 1220 | + glDrawRangeElements(GL_TRIANGLES, 0, _vertices - 1, _indices, GL_UNSIGNED_SHORT, 0); | |
| 1221 | + | |
| 1222 | + glDisableClientState(GL_VERTEX_ARRAY); | |
| 1223 | + glDisableClientState(GL_TEXTURE_COORD_ARRAY); | |
| 1224 | + | |
| 1225 | + glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 1226 | + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
| 1227 | +} | |
| 1228 | + | |
| 1229 | +GLuint ApplicationOverlay::TexturedHemisphere::getTexture() { | |
| 1230 | + return _framebufferObject->texture(); | |
| 1231 | +} | |
| 1232 | + | |
| 1039 | 1233 | glm::vec2 ApplicationOverlay::directionToSpherical(const glm::vec3& direction) { |
| 1040 | 1234 | glm::vec2 result; |
| 1041 | 1235 | // Compute yaw |