diff --git a/examples/example/entities/zoneSkyboxExample.js b/examples/example/entities/zoneSkyboxExample.js new file mode 100644 index 0000000000..a1f5f1917a --- /dev/null +++ b/examples/example/entities/zoneSkyboxExample.js @@ -0,0 +1,60 @@ +// +// zoneSkyboxExample.js +// examples +// +// Created by Brad Hefta-Gaub on 4/16/15. +// Copyright 2015 High Fidelity, Inc. +// +// This is an example script that demonstrates creating a zone using the atmosphere features +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +var count = 0; +var stopAfter = 600; + +var zoneEntityA = Entities.addEntity({ + type: "Zone", + position: { x: 1000, y: 1000, z: 1000}, + dimensions: { x: 2000, y: 2000, z: 2000 }, + keyLightColor: { red: 255, green: 0, blue: 0 }, + stageSunModelEnabled: false, + shapeType: "sphere", + backgroundMode: "skybox", + atmosphere: { + center: { x: 1000, y: 0, z: 1000}, + innerRadius: 1000.0, + outerRadius: 1025.0, + rayleighScattering: 0.0025, + mieScattering: 0.0010, + scatteringWavelengths: { x: 0.650, y: 0.570, z: 0.475 }, + hasStars: false + }, + skybox: { + color: { red: 255, green: 0, blue: 255 }, + url: "" + }, + stageLatitude: 37.777, + stageLongitude: 122.407, + stageAltitude: 0.03, + stageDay: 60, + stageHour: 0, + stageSunModelEnabled: true +}); + +var props = Entities.getEntityProperties(zoneEntityA); +print(JSON.stringify(props)); + +// register the call back so it fires before each data send +Script.update.connect(function(deltaTime) { + // stop it... + if (count >= stopAfter) { + print("calling Script.stop()"); + Script.stop(); + } + count++; +}); + diff --git a/examples/example/games/planky.js b/examples/example/games/planky.js new file mode 100644 index 0000000000..77711958ea --- /dev/null +++ b/examples/example/games/planky.js @@ -0,0 +1,140 @@ +// +// planky.js +// examples +// +// Created by Thijs Wenker on 5/2/14. +// Copyright 2015 High Fidelity, Inc. +// +// Pull blocks off the bottom and put them on the top using the grab.js script. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +const NUM_LAYERS = 16; +const BASE_DIMENSION = { x: 7, y: 2, z: 7 }; +const BLOCKS_PER_LAYER = 3; +const BLOCK_SIZE = {x: 0.2, y: 0.1, z: 0.8}; +const BLOCK_SPACING = BLOCK_SIZE.x / 3; +const GRAVITY = {x: 0, y: -2.8, z: 0}; +const DENSITY = 2000; +const DAMPING_FACTOR = 0.98; +const ANGULAR_DAMPING_FACTOR = 0.8; +const SPAWN_DISTANCE = 3; +const BLOCK_YAW_OFFSET = 45; +const BUTTON_DIMENSIONS = {width: 49, height: 49}; + +var windowWidth = Window.innerWidth; +var size; +var pieces = []; +var ground = false; +var layerRotated = false; + +function grabLowestJointY() { + var jointNames = MyAvatar.getJointNames(); + var floorY = MyAvatar.position.y; + for (var jointName in jointNames) { + if (MyAvatar.getJointPosition(jointNames[jointName]).y < floorY) { + floorY = MyAvatar.getJointPosition(jointNames[jointName]).y; + } + } + return floorY; +} + +function getButtonPosX() { + return windowWidth - ((BUTTON_DIMENSIONS.width / 2) + BUTTON_DIMENSIONS.width); +} + +var button = Overlays.addOverlay('image', { + x: getButtonPosX(), + y: 10, + width: BUTTON_DIMENSIONS.width, + height: BUTTON_DIMENSIONS.height, + imageURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/planky_button.svg', + alpha: 1 +}); + + +function resetBlocks() { + pieces.forEach(function(piece) { + Entities.deleteEntity(piece); + }); + pieces = []; + var avatarRot = Quat.fromPitchYawRollDegrees(0.0, MyAvatar.bodyYaw, 0.0); + basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(SPAWN_DISTANCE, Quat.getFront(avatarRot))); + basePosition.y = grabLowestJointY() - (BASE_DIMENSION.y / 2); + if (!ground) { + ground = Entities.addEntity({ + type: 'Model', + modelURL: HIFI_PUBLIC_BUCKET + 'eric/models/woodFloor.fbx', + dimensions: BASE_DIMENSION, + position: basePosition, + rotation: avatarRot, + shapeType: 'box' + }); + } else { + Entities.editEntity(ground, {position: basePosition, rotation: avatarRot}); + } + var offsetRot = Quat.multiply(avatarRot, Quat.fromPitchYawRollDegrees(0.0, BLOCK_YAW_OFFSET, 0.0)); + basePosition.y += (BASE_DIMENSION.y / 2); + for (var layerIndex = 0; layerIndex < NUM_LAYERS; layerIndex++) { + var layerRotated = layerIndex % 2 === 0; + var offset = -(BLOCK_SPACING); + var layerRotation = Quat.fromPitchYawRollDegrees(0, layerRotated ? 0 : 90, 0.0); + for (var blockIndex = 0; blockIndex < BLOCKS_PER_LAYER; blockIndex++) { + var blockPositionXZ = BLOCK_SIZE.x * blockIndex - (BLOCK_SIZE.x * 3 / 2 - BLOCK_SIZE.x / 2); + var localTransform = Vec3.multiplyQbyV(offsetRot, { + x: (layerRotated ? blockPositionXZ + offset: 0), + y: (BLOCK_SIZE.y / 2) + (BLOCK_SIZE.y * layerIndex), + z: (layerRotated ? 0 : blockPositionXZ + offset) + }); + pieces.push(Entities.addEntity({ + type: 'Model', + modelURL: HIFI_PUBLIC_BUCKET + 'marketplace/hificontent/Games/blocks/block.fbx', + shapeType: 'box', + name: 'JengaBlock' + ((layerIndex * BLOCKS_PER_LAYER) + blockIndex), + dimensions: BLOCK_SIZE, + position: { + x: basePosition.x + localTransform.x, + y: basePosition.y + localTransform.y, + z: basePosition.z + localTransform.z + }, + rotation: Quat.multiply(layerRotation, offsetRot), + collisionsWillMove: true, + damping: DAMPING_FACTOR, + angularDamping: ANGULAR_DAMPING_FACTOR, + gravity: GRAVITY, + density: DENSITY + })); + offset += BLOCK_SPACING; + } + } +} + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + if (clickedOverlay === button) { + resetBlocks(); + } +} + +Controller.mousePressEvent.connect(mousePressEvent); + +function cleanup() { + Overlays.deleteOverlay(button); + if (ground) { + Entities.deleteEntity(ground); + } + pieces.forEach(function(piece) { + Entities.deleteEntity(piece); + }); + pieces = []; +} + +function onUpdate() { + +} + +Script.update.connect(onUpdate) +Script.scriptEnding.connect(cleanup); diff --git a/examples/libraries/zoneOverlayManager.js b/examples/libraries/zoneOverlayManager.js index aac3af119b..92694f8e07 100644 --- a/examples/libraries/zoneOverlayManager.js +++ b/examples/libraries/zoneOverlayManager.js @@ -35,6 +35,7 @@ ZoneOverlayManager = function(isEntityFunc, entityAddedFunc, entityRemovedFunc, this.setVisible = function(isVisible) { if (visible != isVisible) { visible = isVisible; + Entities.setDrawZoneBoundaries(visible); for (var id in entityOverlays) { Overlays.editOverlay(entityOverlays[id].solid, { visible: visible }); Overlays.editOverlay(entityOverlays[id].outline, { visible: visible }); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 837d3df505..7ae82f56b8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3255,6 +3255,11 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs renderMode = RenderArgs::MIRROR_RENDER_MODE; } _entities.render(renderMode, renderSide, renderDebugFlags); + + if (!Menu::getInstance()->isOptionChecked(MenuOption::Wireframe)) { + // Restaure polygon mode + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } } // render JS/scriptable overlays diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 667a89a46b..a470867129 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1173,8 +1173,10 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode ren Camera *camera = Application::getInstance()->getCamera(); const glm::vec3 cameraPos = camera->getPosition(); + + // HACK: comment this block which possibly change the near and break the rendering 5/6/2015 // Only tweak the frustum near far if it's not shadow - if (renderMode != RenderArgs::SHADOW_RENDER_MODE) { + /* if (renderMode != RenderArgs::SHADOW_RENDER_MODE) { // Set near clip distance according to skeleton model dimensions if first person and there is no separate head model. if (shouldRenderHead(cameraPos, renderMode) || !getHead()->getFaceModel().getURL().isEmpty()) { renderFrustum->setNearClip(DEFAULT_NEAR_CLIP); @@ -1184,7 +1186,7 @@ void MyAvatar::renderBody(ViewFrustum* renderFrustum, RenderArgs::RenderMode ren + camera->getOrientation() * glm::vec3(0.0f, 0.0f, -clipDistance) - cameraPos); renderFrustum->setNearClip(clipDistance); } - } + }*/ // Render the body's voxels and head RenderArgs::RenderMode modelRenderMode = renderMode; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index c410b992c4..5c878b484c 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -190,8 +190,8 @@ void ApplicationOverlay::renderOverlay() { Overlays& overlays = qApp->getOverlays(); _textureFov = glm::radians(_hmdUIAngularSize); - auto deviceSize = Application::getInstance()->getDeviceSize(); - _textureAspectRatio = (float)deviceSize.width() / (float)deviceSize.height(); + glm::vec2 deviceSize = qApp->getCanvasSize(); + _textureAspectRatio = (float)deviceSize.x / (float)deviceSize.y; //Handle fading and deactivation/activation of UI @@ -209,7 +209,7 @@ void ApplicationOverlay::renderOverlay() { const float NEAR_CLIP = -10000; const float FAR_CLIP = 10000; glLoadIdentity(); - glOrtho(0, deviceSize.width(), deviceSize.height(), 0, NEAR_CLIP, FAR_CLIP); + glOrtho(0, deviceSize.x, deviceSize.y, 0, NEAR_CLIP, FAR_CLIP); glMatrixMode(GL_MODELVIEW); @@ -270,11 +270,11 @@ void ApplicationOverlay::displayOverlayTexture() { glEnable(GL_BLEND); } + static const glm::vec2 topLeft(-1, 1); + static const glm::vec2 bottomRight(1, -1); + static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); + static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); with_each_texture(_overlays.getTexture(), _newUiTexture, [&] { - static const glm::vec2 topLeft(-1, 1); - static const glm::vec2 bottomRight(1, -1); - static const glm::vec2 texCoordTopLeft(0.0f, 1.0f); - static const glm::vec2 texCoordBottomRight(1.0f, 0.0f); DependencyManager::get()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(1.0f, 1.0f, 1.0f, _alpha)); }); @@ -685,7 +685,7 @@ void ApplicationOverlay::renderControllerPointers() { } //If the cursor is out of the screen then don't render it - if (mouseX < 0 || mouseX >= canvasSize.x || mouseY < 0 || mouseY >= canvasSize.y) { + if (mouseX < 0 || mouseX >= (int)canvasSize.x || mouseY < 0 || mouseY >= (int)canvasSize.y) { _reticleActive[index] = false; continue; } @@ -998,7 +998,7 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() { if (nodeList && !nodeList->getDomainHandler().isConnected()) { auto geometryCache = DependencyManager::get(); auto canvasSize = qApp->getCanvasSize(); - if (canvasSize.x != _previousBorderWidth || canvasSize.y != _previousBorderHeight) { + if ((int)canvasSize.x != _previousBorderWidth || (int)canvasSize.y != _previousBorderHeight) { glm::vec4 color(CONNECTION_STATUS_BORDER_COLOR[0], CONNECTION_STATUS_BORDER_COLOR[1], CONNECTION_STATUS_BORDER_COLOR[2], 1.0f); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index a9eb9184dd..eb2c0d77a7 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -87,11 +87,10 @@ void Overlays::renderHUD() { QReadLocker lock(&_lock); auto lodManager = DependencyManager::get(); - RenderArgs args = { NULL, Application::getInstance()->getViewFrustum(), - lodManager->getOctreeSizeScale(), - lodManager->getBoundaryLevelAdjust(), - RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + RenderArgs args(NULL, Application::getInstance()->getViewFrustum(), + lodManager->getOctreeSizeScale(), + lodManager->getBoundaryLevelAdjust(), + RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE); foreach(Overlay* thisOverlay, _overlaysHUD) { if (thisOverlay->is3D()) { @@ -125,11 +124,10 @@ void Overlays::renderWorld(bool drawFront, float myAvatarScale = 1.0f; auto lodManager = DependencyManager::get(); - RenderArgs args = { NULL, Application::getInstance()->getDisplayViewFrustum(), - lodManager->getOctreeSizeScale(), - lodManager->getBoundaryLevelAdjust(), - renderMode, renderSide, renderDebugFlags, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + RenderArgs args(NULL, Application::getInstance()->getDisplayViewFrustum(), + lodManager->getOctreeSizeScale(), + lodManager->getBoundaryLevelAdjust(), + renderMode, renderSide, renderDebugFlags); foreach(Overlay* thisOverlay, _overlaysWorld) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 97676d6e5d..0fb9296b64 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -392,8 +392,8 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, ViewFrustum* frustum = (renderMode == RenderArgs::SHADOW_RENDER_MODE) ? _viewState->getShadowViewFrustum() : _viewState->getCurrentViewFrustum(); - RenderArgs args = { this, frustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, - renderDebugFlags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + RenderArgs args(this, frustum, getSizeScale(), getBoundaryLevelAdjust(), + renderMode, renderSide, renderDebugFlags); _tree->lockForRead(); @@ -445,7 +445,22 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, data.setSunBrightness(sunBrightness); _viewState->overrideEnvironmentData(data); + scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); + + } else { + _viewState->endOverrideEnvironmentData(); + if (_bestZone->getBackgroundMode() == BACKGROUND_MODE_SKYBOX) { + auto stage = scene->getSkyStage(); + stage->getSkybox()->setColor(_bestZone->getSkyboxProperties().getColorVec3()); + if (_bestZone->getSkyboxProperties().getURL().isEmpty()) { + stage->getSkybox()->clearCubemap(); + } else { + stage->getSkybox()->clearCubemap(); // NOTE: this should be changed to do something to set the cubemap + } + stage->setBackgroundMode(model::SunSkyStage::SKY_BOX); + } } + } else { if (_hasPreviousZone) { scene->setKeyLightColor(_previousKeyLightColor); @@ -460,6 +475,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, _hasPreviousZone = false; } _viewState->endOverrideEnvironmentData(); + scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME); } // we must call endScene while we still have the tree locked so that no one deletes a model @@ -661,8 +677,7 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) if (entityItem->isVisible()) { - // NOTE: Zone Entities are a special case we handle here... Zones don't render - // like other entity types. So we will skip the normal rendering tests + // NOTE: Zone Entities are a special case we handle here... if (entityItem->getType() == EntityTypes::Zone) { if (entityItem->contains(_viewState->getAvatarPosition())) { float entityVolumeEstimate = entityItem->getVolumeEstimate(); @@ -683,42 +698,42 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) } } } - } else { - // render entityItem - AABox entityBox = entityItem->getAABox(); - - // TODO: some entity types (like lights) might want to be rendered even - // when they are outside of the view frustum... - float distance = args->_viewFrustum->distanceToCamera(entityBox.calcCenter()); + } - bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE; - if (!outOfView) { - bool bigEnoughToRender = _viewState->shouldRenderMesh(entityBox.getLargestDimension(), distance); + // render entityItem + AABox entityBox = entityItem->getAABox(); + + // TODO: some entity types (like lights) might want to be rendered even + // when they are outside of the view frustum... + float distance = args->_viewFrustum->distanceToCamera(entityBox.calcCenter()); + + bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE; + if (!outOfView) { + bool bigEnoughToRender = _viewState->shouldRenderMesh(entityBox.getLargestDimension(), distance); - if (bigEnoughToRender) { - renderProxies(entityItem, args); - - Glower* glower = NULL; - if (entityItem->getGlowLevel() > 0.0f) { - glower = new Glower(entityItem->getGlowLevel()); - } - entityItem->render(args); - args->_itemsRendered++; - if (glower) { - delete glower; - } - } else { - args->_itemsTooSmall++; + if (bigEnoughToRender) { + renderProxies(entityItem, args); + + Glower* glower = NULL; + if (entityItem->getGlowLevel() > 0.0f) { + glower = new Glower(entityItem->getGlowLevel()); + } + entityItem->render(args); + args->_itemsRendered++; + if (glower) { + delete glower; } } else { - args->_itemsOutOfView++; + args->_itemsTooSmall++; } + } else { + args->_itemsOutOfView++; } } } } -float EntityTreeRenderer::getSizeScale() const { +float EntityTreeRenderer::getSizeScale() const { return _viewState->getSizeScale(); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 0b51cf75f2..d9bc0f0b4a 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -11,8 +11,10 @@ #include "RenderableZoneEntityItem.h" +#include #include #include +#include EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return new RenderableZoneEntityItem(entityID, properties); @@ -27,10 +29,12 @@ void RenderableZoneEntityItem::changeProperties(Lambda setNewProperties) { setNewProperties(); if (oldShapeURL != getCompoundShapeURL()) { - if (!_model) { - _model = getModel(); - _needsInitialSimulation = true; + if (_model) { + delete _model; } + + _model = getModel(); + _needsInitialSimulation = true; _model->setURL(getCompoundShapeURL(), QUrl(), true, true); } if (oldPosition != getPosition() || @@ -61,6 +65,7 @@ int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch Model* RenderableZoneEntityItem::getModel() { Model* model = new Model(); + model->setIsWireframe(true); model->init(); return model; } @@ -74,9 +79,66 @@ void RenderableZoneEntityItem::initialSimulation() { _needsInitialSimulation = false; } +void RenderableZoneEntityItem::updateGeometry() { + if (_model && !_model->isActive() && hasCompoundShapeURL()) { + // Since we have a delayload, we need to update the geometry if it has been downloaded + _model->setURL(getCompoundShapeURL(), QUrl(), true); + } + if (_model && _model->isActive() && _needsInitialSimulation) { + initialSimulation(); + } +} + void RenderableZoneEntityItem::render(RenderArgs* args) { if (_drawZoneBoundaries) { - // TODO: Draw the zone boundaries... + switch (getShapeType()) { + case SHAPE_TYPE_COMPOUND: { + updateGeometry(); + + if (_model && _model->isActive()) { + PerformanceTimer perfTimer("zone->renderCompound"); + glPushMatrix(); + _model->renderInScene(getLocalRenderAlpha(), args); + glPopMatrix(); + } + break; + } + case SHAPE_TYPE_BOX: + case SHAPE_TYPE_SPHERE: { + PerformanceTimer perfTimer("zone->renderPrimitive"); + glm::vec3 position = getPosition(); + glm::vec3 center = getCenter(); + glm::vec3 dimensions = getDimensions(); + glm::quat rotation = getRotation(); + + glm::vec4 DEFAULT_COLOR(1.0f, 1.0f, 1.0f, getLocalRenderAlpha()); + + glPushMatrix(); { + glTranslatef(position.x, position.y, position.z); + glm::vec3 axis = glm::axis(rotation); + glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); + glPushMatrix(); { + glm::vec3 positionToCenter = center - position; + glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z); + glScalef(dimensions.x, dimensions.y, dimensions.z); + + auto deferredLightingEffect = DependencyManager::get(); + + if (getShapeType() == SHAPE_TYPE_SPHERE) { + const int SLICES = 15; + const int STACKS = 15; + deferredLightingEffect->renderWireSphere(0.5f, SLICES, STACKS, DEFAULT_COLOR); + } else { + deferredLightingEffect->renderWireCube(1.0f, DEFAULT_COLOR); + } + } glPopMatrix(); + } glPopMatrix(); + break; + } + default: + // Not handled + break; + } } } @@ -84,16 +146,9 @@ bool RenderableZoneEntityItem::contains(const glm::vec3& point) const { if (getShapeType() != SHAPE_TYPE_COMPOUND) { return EntityItem::contains(point); } - - if (_model && !_model->isActive() && hasCompoundShapeURL()) { - // Since we have a delayload, we need to update the geometry if it has been downloaded - _model->setURL(getCompoundShapeURL(), QUrl(), true); - } + const_cast(this)->updateGeometry(); if (_model && _model->isActive() && EntityItem::contains(point)) { - if (_needsInitialSimulation) { - const_cast(this)->initialSimulation(); - } return _model->convexHullContains(point); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 18840e274b..90a16a8a9f 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -38,6 +38,7 @@ public: private: Model* getModel(); void initialSimulation(); + void updateGeometry(); template void changeProperties(Lambda functor); diff --git a/libraries/entities/src/AtmospherePropertyGroup.cpp b/libraries/entities/src/AtmospherePropertyGroup.cpp index 54e48023b8..b9b49f8c45 100644 --- a/libraries/entities/src/AtmospherePropertyGroup.cpp +++ b/libraries/entities/src/AtmospherePropertyGroup.cpp @@ -26,13 +26,13 @@ AtmospherePropertyGroup::AtmospherePropertyGroup() { } void AtmospherePropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(Atmosphere, Center, center); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, InnerRadius, innerRadius); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, OuterRadius, outerRadius); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, MieScattering, mieScattering); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, RayleighScattering, rayleighScattering); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(Atmosphere, ScatteringWavelengths, scatteringWavelengths); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, HasStars, hasStars); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(Atmosphere, atmosphere, Center, center); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, InnerRadius, innerRadius); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, OuterRadius, outerRadius); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, MieScattering, mieScattering); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, RayleighScattering, rayleighScattering); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(Atmosphere, atmosphere, ScatteringWavelengths, scatteringWavelengths); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Atmosphere, atmosphere, HasStars, hasStars); } void AtmospherePropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 2e107bc958..ab41367fa9 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -28,6 +28,7 @@ #include "ZoneEntityItem.h" AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere; +SkyboxPropertyGroup EntityItemProperties::_staticSkybox; EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1); @@ -237,7 +238,7 @@ void EntityItemProperties::setShapeTypeFromString(const QString& shapeName) { } } -const char* backgroundModeNames[] = {"inherit", "atmosphere", "texture" }; +const char* backgroundModeNames[] = {"inherit", "atmosphere", "skybox" }; QHash stringToBackgroundModeLookup; @@ -248,7 +249,7 @@ void addBackgroundMode(BackgroundMode type) { void buildStringToBackgroundModeLookup() { addBackgroundMode(BACKGROUND_MODE_INHERIT); addBackgroundMode(BACKGROUND_MODE_ATMOSPHERE); - addBackgroundMode(BACKGROUND_MODE_TEXTURE); + addBackgroundMode(BACKGROUND_MODE_SKYBOX); } QString EntityItemProperties::getBackgroundModeAsString() const { @@ -337,6 +338,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode); changedProperties += _atmosphere.getChangedProperties(); + changedProperties += _skybox.getChangedProperties(); return changedProperties; } @@ -455,6 +457,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool } _atmosphere.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); + _skybox.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties); return properties; } @@ -526,6 +529,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageHour, setStageHour); COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode); _atmosphere.copyFromScriptValue(object, _defaultSettings); + _skybox.copyFromScriptValue(object, _defaultSettings); _lastEdited = usecTimestampNow(); } @@ -735,6 +739,9 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem _staticAtmosphere.setProperties(properties); _staticAtmosphere.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState ); + + _staticSkybox.setProperties(properties); + _staticSkybox.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState ); } APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, properties.getMarketplaceID()); @@ -986,6 +993,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode); properties.getAtmosphere().decodeFromEditPacket(propertyFlags, dataAt , processedBytes); + properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt , processedBytes); } READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID); @@ -1090,6 +1098,7 @@ void EntityItemProperties::markAllChanged() { _backgroundModeChanged = true; _atmosphere.markAllChanged(); + _skybox.markAllChanged(); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index ef3bc5cbfb..8ea521a8e9 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -30,6 +30,7 @@ #include #include "AtmospherePropertyGroup.h" +#include "SkyboxPropertyGroup.h" #include "EntityItemID.h" #include "EntityItemPropertiesMacros.h" #include "EntityTypes.h" @@ -138,8 +139,9 @@ public: DEFINE_PROPERTY(PROP_STAGE_DAY, StageDay, stageDay, quint16); DEFINE_PROPERTY(PROP_STAGE_HOUR, StageHour, stageHour, float); DEFINE_PROPERTY_REF(PROP_NAME, Name, name, QString); - DEFINE_PROPERTY_GROUP(Atmosphere, atmosphere, AtmospherePropertyGroup); DEFINE_PROPERTY_REF_ENUM(PROP_BACKGROUND_MODE, BackgroundMode, backgroundMode, BackgroundMode); + DEFINE_PROPERTY_GROUP(Atmosphere, atmosphere, AtmospherePropertyGroup); + DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); static QString getBackgroundModeString(BackgroundMode mode); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index aa4bd674cd..3f25f9353e 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -116,6 +116,17 @@ bytesRead += sizeof(rgbColor); \ } +#define READ_ENTITY_PROPERTY_XCOLOR(P,M) \ + if (propertyFlags.getHasProperty(P)) { \ + if (overwriteLocalData) { \ + M.red = dataAt[RED_INDEX]; \ + M.green = dataAt[GREEN_INDEX]; \ + M.blue = dataAt[BLUE_INDEX]; \ + } \ + dataAt += sizeof(rgbColor); \ + bytesRead += sizeof(rgbColor); \ + } + #define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \ if (propertyFlags.getHasProperty(P)) { \ T fromBuffer; \ @@ -206,27 +217,40 @@ } -#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(G,P,p) \ +#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_VEC3(G,g,P,p) \ if (!skipDefaults || defaultEntityProperties.get##G().get##P() != _##p) { \ - QScriptValue groupProperties = properties.property(#G); \ + QScriptValue groupProperties = properties.property(#g); \ if (!groupProperties.isValid()) { \ groupProperties = engine->newObject(); \ } \ QScriptValue V = vec3toScriptValue(engine, _##p); \ groupProperties.setProperty(#p, V); \ - properties.setProperty(#G, groupProperties); \ + properties.setProperty(#g, groupProperties); \ } -#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,P,p) \ +#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \ if (!skipDefaults || defaultEntityProperties.get##G().get##P() != _##p) { \ - QScriptValue groupProperties = properties.property(#G); \ + QScriptValue groupProperties = properties.property(#g); \ if (!groupProperties.isValid()) { \ groupProperties = engine->newObject(); \ } \ groupProperties.setProperty(#p, _##p); \ - properties.setProperty(#G, groupProperties); \ + properties.setProperty(#g, groupProperties); \ } + +#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_COLOR(G,g,P,p) \ + if (!skipDefaults || defaultEntityProperties.get##G().get##P() != _##p) { \ + QScriptValue groupProperties = properties.property(#g); \ + if (!groupProperties.isValid()) { \ + groupProperties = engine->newObject(); \ + } \ + QScriptValue colorValue = xColorToScriptValue(engine, _##p); \ + groupProperties.setProperty(#p, colorValue); \ + properties.setProperty(#g, groupProperties); \ + } + + #define COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(P) \ if (!skipDefaults || defaultEntityProperties._##P != _##P) { \ QScriptValue P = vec3toScriptValue(engine, _##P); \ @@ -328,6 +352,20 @@ } \ } +#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_STRING(G, P, S)\ + { \ + QScriptValue G = object.property(#G); \ + if (G.isValid()) { \ + QScriptValue P = G.property(#P); \ + if (P.isValid()) { \ + QString newValue = P.toVariant().toString().trimmed();\ + if (_defaultSettings || newValue != _##P) { \ + S(newValue); \ + } \ + } \ + } \ + } + #define COPY_PROPERTY_FROM_QSCRIPTVALUE_UUID(P, S) \ QScriptValue P = object.property(#P); \ if (P.isValid()) { \ @@ -428,6 +466,31 @@ } \ } +#define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_COLOR(G, P, S) \ + { \ + QScriptValue G = object.property(#G); \ + if (G.isValid()) { \ + QScriptValue P = G.property(#P); \ + if (P.isValid()) { \ + QScriptValue r = P.property("red"); \ + QScriptValue g = P.property("green"); \ + QScriptValue b = P.property("blue"); \ + if (r.isValid() && g.isValid() && b.isValid()) {\ + xColor newColor; \ + newColor.red = r.toVariant().toInt(); \ + newColor.green = g.toVariant().toInt(); \ + newColor.blue = b.toVariant().toInt(); \ + if (_defaultSettings || \ + (newColor.red != _color.red || \ + newColor.green != _color.green || \ + newColor.blue != _color.blue)) { \ + S(newColor); \ + } \ + } \ + } \ + } \ + } + #define COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(P, S) \ QScriptValue P = object.property(#P); \ if (P.isValid()) { \ diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index 3569a3dcc9..f40fa67195 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -144,6 +144,8 @@ enum EntityPropertyList { PROP_ATMOSPHERE_SCATTERING_WAVELENGTHS = PROP_LOCAL_GRAVITY, PROP_ATMOSPHERE_HAS_STARS = PROP_PARTICLE_RADIUS, PROP_BACKGROUND_MODE = PROP_MODEL_URL, + PROP_SKYBOX_COLOR = PROP_ANIMATION_URL, + PROP_SKYBOX_URL = PROP_ANIMATION_FPS, // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above }; @@ -158,7 +160,7 @@ extern EntityPropertyList PROP_LAST_ITEM; enum BackgroundMode { BACKGROUND_MODE_INHERIT, BACKGROUND_MODE_ATMOSPHERE, - BACKGROUND_MODE_TEXTURE, + BACKGROUND_MODE_SKYBOX, }; diff --git a/libraries/entities/src/SkyboxPropertyGroup.cpp b/libraries/entities/src/SkyboxPropertyGroup.cpp new file mode 100644 index 0000000000..8b304d0523 --- /dev/null +++ b/libraries/entities/src/SkyboxPropertyGroup.cpp @@ -0,0 +1,130 @@ +// +// SkyboxPropertyGroup.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include + +#include "SkyboxPropertyGroup.h" +#include "EntityItemProperties.h" +#include "EntityItemPropertiesMacros.h" + +SkyboxPropertyGroup::SkyboxPropertyGroup() { + _color.red = _color.green = _color.blue = 0; + _url = QString(); +} + +void SkyboxPropertyGroup::copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const { + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_COLOR(Skybox, skybox, Color, color); + COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(Skybox, skybox, URL, url); +} + +void SkyboxPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) { + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_COLOR(skybox, color, setColor); + COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_STRING(skybox, url, setURL); +} + +void SkyboxPropertyGroup::debugDump() const { + qDebug() << " SkyboxPropertyGroup: ---------------------------------------------"; + qDebug() << " Color:" << getColor() << " has changed:" << colorChanged(); + qDebug() << " URL:" << getURL() << " has changed:" << urlChanged(); +} + +bool SkyboxPropertyGroup::appentToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, appendColor, getColor()); + APPEND_ENTITY_PROPERTY(PROP_SKYBOX_URL, appendValue, getURL()); + + return true; +} + + +bool SkyboxPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + + READ_ENTITY_PROPERTY_XCOLOR(PROP_SKYBOX_COLOR, _color); + READ_ENTITY_PROPERTY_STRING(PROP_SKYBOX_URL, setURL); + + processedBytes += bytesRead; + + return true; +} + +void SkyboxPropertyGroup::markAllChanged() { + _colorChanged = true; + _urlChanged = true; +} + +EntityPropertyFlags SkyboxPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + + CHECK_PROPERTY_CHANGE(PROP_SKYBOX_COLOR, color); + CHECK_PROPERTY_CHANGE(PROP_SKYBOX_URL, url); + + return changedProperties; +} + +void SkyboxPropertyGroup::getProperties(EntityItemProperties& properties) const { + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Skybox, Color, getColor); + COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Skybox, URL, getURL); +} + +bool SkyboxPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Skybox, Color, color, setColor); + SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Skybox, URL, url, setURL); + + return somethingChanged; +} + +EntityPropertyFlags SkyboxPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + + requestedProperties += PROP_SKYBOX_COLOR; + requestedProperties += PROP_SKYBOX_URL; + + return requestedProperties; +} + +void SkyboxPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, appendColor, getColor()); + APPEND_ENTITY_PROPERTY(PROP_SKYBOX_URL, appendValue, getURL()); +} + +int SkyboxPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY_XCOLOR(PROP_SKYBOX_COLOR, _color); + READ_ENTITY_PROPERTY_STRING(PROP_SKYBOX_URL, setURL); + + return bytesRead; +} diff --git a/libraries/entities/src/SkyboxPropertyGroup.h b/libraries/entities/src/SkyboxPropertyGroup.h new file mode 100644 index 0000000000..a92ec5abbb --- /dev/null +++ b/libraries/entities/src/SkyboxPropertyGroup.h @@ -0,0 +1,85 @@ +// +// SkyboxPropertyGroup.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_SkyboxPropertyGroup_h +#define hifi_SkyboxPropertyGroup_h + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; + +#include +#include + + +class SkyboxPropertyGroup : public PropertyGroup { +public: + SkyboxPropertyGroup(); + virtual ~SkyboxPropertyGroup() {} + + // EntityItemProperty related helpers + virtual void copyToScriptValue(QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const; + virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings); + virtual void debugDump() const; + + virtual bool appentToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const; + + virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes); + virtual void markAllChanged(); + virtual EntityPropertyFlags getChangedProperties() const; + + // EntityItem related helpers + // methods for getting/setting all properties of an entity + virtual void getProperties(EntityItemProperties& propertiesOut) const; + + /// returns true if something changed + virtual bool setProperties(const EntityItemProperties& properties); + + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const; + + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData); + + glm::vec3 getColorVec3() const { + const quint8 MAX_COLOR = 255; + glm::vec3 color = { (float)_color.red / (float)MAX_COLOR, + (float)_color.green / (float)MAX_COLOR, + (float)_color.blue / (float)MAX_COLOR }; + return color; + } + + + DEFINE_PROPERTY_REF(PROP_SKYBOX_COLOR, Color, color, xColor); + DEFINE_PROPERTY_REF(PROP_SKYBOX_URL, URL, url, QString); +}; + +#endif // hifi_SkyboxPropertyGroup_h diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index c4646bebdf..f8e8eceb9f 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -71,13 +71,13 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityIte EnvironmentData ZoneEntityItem::getEnvironmentData() const { EnvironmentData result; - result.setAtmosphereCenter(_atmospherePropeties.getCenter()); - result.setAtmosphereInnerRadius(_atmospherePropeties.getInnerRadius()); - result.setAtmosphereOuterRadius(_atmospherePropeties.getOuterRadius()); - result.setRayleighScattering(_atmospherePropeties.getRayleighScattering()); - result.setMieScattering(_atmospherePropeties.getMieScattering()); - result.setScatteringWavelengths(_atmospherePropeties.getScatteringWavelengths()); - result.setHasStars(_atmospherePropeties.getHasStars()); + result.setAtmosphereCenter(_atmosphereProperties.getCenter()); + result.setAtmosphereInnerRadius(_atmosphereProperties.getInnerRadius()); + result.setAtmosphereOuterRadius(_atmosphereProperties.getOuterRadius()); + result.setRayleighScattering(_atmosphereProperties.getRayleighScattering()); + result.setMieScattering(_atmosphereProperties.getMieScattering()); + result.setScatteringWavelengths(_atmosphereProperties.getScatteringWavelengths()); + result.setHasStars(_atmosphereProperties.getHasStars()); // NOTE: The sunLocation and SunBrightness will be overwritten in the EntityTreeRenderer to use the // keyLight details from the scene interface @@ -105,7 +105,8 @@ EntityItemProperties ZoneEntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundMode, getBackgroundMode); - _atmospherePropeties.getProperties(properties); + _atmosphereProperties.getProperties(properties); + _skyboxProperties.getProperties(properties); return properties; } @@ -128,9 +129,10 @@ bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundMode, setBackgroundMode); - bool somethingChangedInAtmosphere = _atmospherePropeties.setProperties(properties); + bool somethingChangedInAtmosphere = _atmosphereProperties.setProperties(properties); + bool somethingChangedInSkybox = _skyboxProperties.setProperties(properties); - somethingChanged = somethingChanged || somethingChangedInAtmosphere; + somethingChanged = somethingChanged || somethingChangedInAtmosphere || somethingChangedInSkybox; if (somethingChanged) { bool wantDebug = false; @@ -165,8 +167,17 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType); READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL); READ_ENTITY_PROPERTY_SETTER(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode); - bytesRead += _atmospherePropeties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + + int bytesFromAtmosphere = _atmosphereProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, + propertyFlags, overwriteLocalData); + + bytesRead += bytesFromAtmosphere; + dataAt += bytesFromAtmosphere; + + int bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); + bytesRead += bytesFromSkybox; + dataAt += bytesFromSkybox; return bytesRead; } @@ -189,7 +200,8 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p requestedProperties += PROP_SHAPE_TYPE; requestedProperties += PROP_COMPOUND_SHAPE_URL; requestedProperties += PROP_BACKGROUND_MODE; - requestedProperties += _atmospherePropeties.getEntityProperties(params); + requestedProperties += _atmosphereProperties.getEntityProperties(params); + requestedProperties += _skyboxProperties.getEntityProperties(params); return requestedProperties; } @@ -218,7 +230,10 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL()); APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, appendValue, (uint32_t)getBackgroundMode()); // could this be a uint16?? - _atmospherePropeties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + _atmosphereProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, + propertyFlags, propertiesDidntFit, propertyCount, appendState); + + _skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); } @@ -241,23 +256,22 @@ void ZoneEntityItem::debugDump() const { qCDebug(entities) << " _stageHour:" << _stageHour; qCDebug(entities) << " _backgroundMode:" << EntityItemProperties::getBackgroundModeString(_backgroundMode); - _atmospherePropeties.debugDump(); + _atmosphereProperties.debugDump(); + _skyboxProperties.debugDump(); } ShapeType ZoneEntityItem::getShapeType() const { // Zones are not allowed to have a SHAPE_TYPE_NONE... they are always at least a SHAPE_TYPE_BOX if (_shapeType == SHAPE_TYPE_COMPOUND) { - return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_BOX; + return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : DEFAULT_SHAPE_TYPE; } else { - return _shapeType == SHAPE_TYPE_NONE ? SHAPE_TYPE_BOX : _shapeType; + return _shapeType == SHAPE_TYPE_NONE ? DEFAULT_SHAPE_TYPE : _shapeType; } } void ZoneEntityItem::setCompoundShapeURL(const QString& url) { _compoundShapeURL = url; - if (!_compoundShapeURL.isEmpty()) { - updateShapeType(SHAPE_TYPE_COMPOUND); - } else if (_shapeType == SHAPE_TYPE_COMPOUND) { + if (_compoundShapeURL.isEmpty() && _shapeType == SHAPE_TYPE_COMPOUND) { _shapeType = DEFAULT_SHAPE_TYPE; } } diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index 147cad7e45..6c67ea72dd 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -44,11 +44,6 @@ public: ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData); - // NOTE: Apparently if you begin to return a shape type, then the physics system will prevent an avatar - // from penetrating the walls of the entity. This fact will likely be important to Clement as he works - // on better defining the shape/volume of a zone. - //virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } - xColor getKeyLightColor() const { xColor color = { _keyLightColor[RED_INDEX], _keyLightColor[GREEN_INDEX], _keyLightColor[BLUE_INDEX] }; return color; } void setKeyLightColor(const xColor& value) { _keyLightColor[RED_INDEX] = value.red; @@ -110,6 +105,8 @@ public: BackgroundMode getBackgroundMode() const { return _backgroundMode; } EnvironmentData getEnvironmentData() const; + const AtmospherePropertyGroup& getAtmosphereProperties() const { return _atmosphereProperties; } + const SkyboxPropertyGroup& getSkyboxProperties() const { return _skyboxProperties; } virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, @@ -144,11 +141,12 @@ protected: uint16_t _stageDay; float _stageHour; - ShapeType _shapeType = SHAPE_TYPE_NONE; + ShapeType _shapeType = DEFAULT_SHAPE_TYPE; QString _compoundShapeURL; BackgroundMode _backgroundMode = BACKGROUND_MODE_INHERIT; - AtmospherePropertyGroup _atmospherePropeties; + AtmospherePropertyGroup _atmosphereProperties; + SkyboxPropertyGroup _skyboxProperties; static bool _drawZoneBoundaries; static bool _zonesArePickable; diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 2d3eacd37f..23cfef7764 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -31,36 +31,51 @@ typedef GLBackend::GLState::Command1 CommandDepthTest; typedef GLBackend::GLState::Command3 CommandStencil; typedef GLBackend::GLState::Command1 CommandBlend; -// The state commands to reset to default, -// WARNING depending on the order of the State::Field enum -const GLBackend::GLState::Commands GLBackend::GLState::_resetStateCommands = { - CommandPointer(new Command1I(&GLBackend::do_setStateFillMode, State::DEFAULT.fillMode)), - CommandPointer(new Command1I(&GLBackend::do_setStateCullMode, State::DEFAULT.cullMode)), - CommandPointer(new Command1B(&GLBackend::do_setStateFrontFaceClockwise, State::DEFAULT.frontFaceClockwise)), - CommandPointer(new Command1B(&GLBackend::do_setStateDepthClipEnable, State::DEFAULT.depthClipEnable)), - CommandPointer(new Command1B(&GLBackend::do_setStateScissorEnable, State::DEFAULT.scissorEnable)), - CommandPointer(new Command1B(&GLBackend::do_setStateMultisampleEnable, State::DEFAULT.multisampleEnable)), - CommandPointer(new Command1B(&GLBackend::do_setStateAntialiasedLineEnable, State::DEFAULT.antialisedLineEnable)), +const GLBackend::GLState::Commands makeResetStateCommands(); +const GLBackend::GLState::Commands GLBackend::GLState::_resetStateCommands = makeResetStateCommands(); - // Depth bias has 2 fields in State but really one call in GLBackend - CommandPointer(new CommandDepthBias(&GLBackend::do_setStateDepthBias, Vec2(State::DEFAULT.depthBias, State::DEFAULT.depthBiasSlopeScale))), - CommandPointer(new CommandDepthBias(&GLBackend::do_setStateDepthBias, Vec2(State::DEFAULT.depthBias, State::DEFAULT.depthBiasSlopeScale))), - - CommandPointer(new CommandDepthTest(&GLBackend::do_setStateDepthTest, State::DEFAULT.depthTest)), - // Depth bias has 3 fields in State but really one call in GLBackend - CommandPointer(new CommandStencil(&GLBackend::do_setStateStencil, State::DEFAULT.stencilActivation, State::DEFAULT.stencilTestFront, State::DEFAULT.stencilTestBack)), - CommandPointer(new CommandStencil(&GLBackend::do_setStateStencil, State::DEFAULT.stencilActivation, State::DEFAULT.stencilTestFront, State::DEFAULT.stencilTestBack)), - CommandPointer(new CommandStencil(&GLBackend::do_setStateStencil, State::DEFAULT.stencilActivation, State::DEFAULT.stencilTestFront, State::DEFAULT.stencilTestBack)), - - CommandPointer(new Command1B(&GLBackend::do_setStateAlphaToCoverageEnable, State::DEFAULT.alphaToCoverageEnable)), - - CommandPointer(new Command1U(&GLBackend::do_setStateSampleMask, State::DEFAULT.sampleMask)), - - CommandPointer(new CommandBlend(&GLBackend::do_setStateBlend, State::DEFAULT.blendFunction)), - - CommandPointer(new Command1U(&GLBackend::do_setStateColorWriteMask, State::DEFAULT.colorWriteMask)) -}; +const GLBackend::GLState::Commands makeResetStateCommands() { + // Since State::DEFAULT is a static defined in another .cpp the initialisation order is random + // and we have a 50/50 chance that State::DEFAULT is not yet initialized. + // Since State::DEFAULT = State::Data() it is much easier to not use the actual State::DEFAULT + // but another State::Data object with a default initialization. + State::Data DEFAULT = State::Data(); + + CommandPointer depthBiasCommand = CommandPointer(new CommandDepthBias(&GLBackend::do_setStateDepthBias, Vec2(DEFAULT.depthBias, DEFAULT.depthBiasSlopeScale))); + CommandPointer stencilCommand = CommandPointer(new CommandStencil(&GLBackend::do_setStateStencil, DEFAULT.stencilActivation, DEFAULT.stencilTestFront, DEFAULT.stencilTestBack)); + + // The state commands to reset to default, + // WARNING depending on the order of the State::Field enum + return { + CommandPointer(new Command1I(&GLBackend::do_setStateFillMode, DEFAULT.fillMode)), + CommandPointer(new Command1I(&GLBackend::do_setStateCullMode, DEFAULT.cullMode)), + CommandPointer(new Command1B(&GLBackend::do_setStateFrontFaceClockwise, DEFAULT.frontFaceClockwise)), + CommandPointer(new Command1B(&GLBackend::do_setStateDepthClipEnable, DEFAULT.depthClipEnable)), + CommandPointer(new Command1B(&GLBackend::do_setStateScissorEnable, DEFAULT.scissorEnable)), + CommandPointer(new Command1B(&GLBackend::do_setStateMultisampleEnable, DEFAULT.multisampleEnable)), + CommandPointer(new Command1B(&GLBackend::do_setStateAntialiasedLineEnable, DEFAULT.antialisedLineEnable)), + + // Depth bias has 2 fields in State but really one call in GLBackend + CommandPointer(depthBiasCommand), + CommandPointer(depthBiasCommand), + + CommandPointer(new CommandDepthTest(&GLBackend::do_setStateDepthTest, DEFAULT.depthTest)), + + // Depth bias has 3 fields in State but really one call in GLBackend + CommandPointer(stencilCommand), + CommandPointer(stencilCommand), + CommandPointer(stencilCommand), + + CommandPointer(new Command1B(&GLBackend::do_setStateAlphaToCoverageEnable, DEFAULT.alphaToCoverageEnable)), + + CommandPointer(new Command1U(&GLBackend::do_setStateSampleMask, DEFAULT.sampleMask)), + + CommandPointer(new CommandBlend(&GLBackend::do_setStateBlend, DEFAULT.blendFunction)), + + CommandPointer(new Command1U(&GLBackend::do_setStateColorWriteMask, DEFAULT.colorWriteMask)) + }; +} void generateFillMode(GLBackend::GLState::Commands& commands, State::FillMode fillMode) { commands.push_back(CommandPointer(new Command1I(&GLBackend::do_setStateFillMode, int32(fillMode)))); diff --git a/libraries/gpu/src/gpu/State.cpp b/libraries/gpu/src/gpu/State.cpp index 76a444a2e6..ca254626e9 100755 --- a/libraries/gpu/src/gpu/State.cpp +++ b/libraries/gpu/src/gpu/State.cpp @@ -20,6 +20,8 @@ State::State() { State::~State() { } +// WARNING: GLBackend::GLState::_resetStateCommands heavily relies on the fact that State::DEFAULT = State::Data() +// Please make sure to go check makeResetStateCommands() before modifying this value const State::Data State::DEFAULT = State::Data(); State::Signature State::evalSignature(const Data& state) { diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index 8495baf600..d10b97a455 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -41,10 +41,13 @@ void Skybox::setCubemap(const gpu::TexturePointer& cubemap) { _cubemap = cubemap; } +void Skybox::clearCubemap() { + _cubemap.reset(); +} + void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) { if (skybox.getCubemap()) { - static gpu::PipelinePointer thePipeline; static gpu::BufferPointer theBuffer; static gpu::Stream::FormatPointer theFormat; diff --git a/libraries/model/src/model/Skybox.h b/libraries/model/src/model/Skybox.h index 8eb910a96e..de0ede8d90 100755 --- a/libraries/model/src/model/Skybox.h +++ b/libraries/model/src/model/Skybox.h @@ -32,6 +32,7 @@ public: void setCubemap(const gpu::TexturePointer& cubemap); const gpu::TexturePointer& getCubemap() const { return _cubemap; } + void clearCubemap(); static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox); diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index 3f1c3fbbfa..ec83e18c3d 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_ZONE_ENTITIES_HAVE_ATMOSPHERE; + return VERSION_ENTITIES_ZONE_ENTITIES_HAVE_SKYBOX; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index c43b98d41f..38aeed4993 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -141,5 +141,6 @@ const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 17; const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE = 18; const PacketVersion VERSION_ENTITIES_HAVE_NAMES = 19; const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_ATMOSPHERE = 20; +const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_SKYBOX = 21; #endif // hifi_PacketHeaders_h diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 4347934d87..946ad3aa1b 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -167,8 +167,8 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) { void OctreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide, RenderArgs::DebugFlags renderDebugFlags) { - RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, - renderDebugFlags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + RenderArgs args(this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), + renderMode, renderSide, renderDebugFlags); if (_tree) { _tree->lockForRead(); _tree->recurseTreeWithOperation(renderOperation, &args); diff --git a/libraries/octree/src/ViewFrustum.h b/libraries/octree/src/ViewFrustum.h index dfb0dcb308..5b20126293 100644 --- a/libraries/octree/src/ViewFrustum.h +++ b/libraries/octree/src/ViewFrustum.h @@ -30,7 +30,8 @@ const float DEFAULT_KEYHOLE_RADIUS = 3.0f; const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f; const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f; -const float DEFAULT_NEAR_CLIP = 0.08f; +//const float DEFAULT_NEAR_CLIP = 0.08f; +const float DEFAULT_NEAR_CLIP = 0.25f; const float DEFAULT_FAR_CLIP = (float)TREE_SCALE; class ViewFrustum { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 59700d70fc..eb010f874d 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -84,6 +84,7 @@ Model::Model(QObject* parent) : _calculatedMeshBoxesValid(false), _calculatedMeshTrianglesValid(false), _meshGroupsKnown(false), + _isWireframe(false), _renderCollisionHull(false) { // we may have been created in the network thread, but we live in the main thread @@ -100,8 +101,8 @@ Model::RenderPipelineLib Model::_renderPipelineLib; const GLint MATERIAL_GPU_SLOT = 3; void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, - gpu::ShaderPointer& vertexShader, - gpu::ShaderPointer& pixelShader ) { + gpu::ShaderPointer& vertexShader, + gpu::ShaderPointer& pixelShader ) { gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); @@ -119,7 +120,7 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - + // Backface on shadow if (key.isShadow()) { state->setCullMode(gpu::State::CULL_FRONT); @@ -140,7 +141,20 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, // Good to go add the brand new pipeline auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); - + + + if (!key.isWireFrame()) { + + RenderKey wireframeKey(key.getRaw() | RenderKey::IS_WIREFRAME); + gpu::StatePointer wireframeState = gpu::StatePointer(new gpu::State(state->getValues())); + + wireframeState->setFillMode(gpu::State::FILL_LINE); + + // create a new RenderPipeline with the same shader side and the mirrorState + auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); + insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); + } + // If not a shadow pass, create the mirror version from the same state, just change the FrontFace if (!key.isShadow()) { @@ -152,6 +166,17 @@ void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key, // create a new RenderPipeline with the same shader side and the mirrorState auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState)); insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations))); + + if (!key.isWireFrame()) { + RenderKey wireframeKey(key.getRaw() | RenderKey::IS_MIRROR | RenderKey::IS_WIREFRAME); + gpu::StatePointer wireframeState = gpu::StatePointer(new gpu::State(state->getValues()));; + + wireframeState->setFillMode(gpu::State::FILL_LINE); + + // create a new RenderPipeline with the same shader side and the mirrorState + auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); + insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); + } } } @@ -808,19 +833,19 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { //renderMeshes(batch, mode, translucent, alphaThreshold, hasTangents, hasSpecular, isSkinned, args, forceRenderMeshes); int opaqueMeshPartsRendered = 0; - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, true, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, false, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, true, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, false, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, true, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, false, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, true, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, true, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, true, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, true, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, true, false, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, false, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, false, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, false, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, false, false, args, true); // render translucent meshes afterwards //DependencyManager::get()->setPrimaryDrawBuffers(false, true, true); @@ -834,14 +859,14 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { int translucentMeshPartsRendered = 0; const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, false, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, true, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, false, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, true, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, false, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, true, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, false, args, true); { GLenum buffers[1]; @@ -855,14 +880,14 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { // batch.setFramebuffer(DependencyManager::get()->getPrimaryTransparentFramebuffer()); const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, false, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, true, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, false, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args, true); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, false, args, true); // batch.setFramebuffer(DependencyManager::get()->getPrimaryOpaqueFramebuffer()); } @@ -1110,7 +1135,7 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo // if so instructed, keep the current geometry until the new one is loaded _nextBaseGeometry = _nextGeometry = DependencyManager::get()->getGeometry(url, fallback, delayLoad); _nextLODHysteresis = NetworkGeometry::NO_HYSTERESIS; - if (!retainCurrent || !isActive() || _nextGeometry->isLoaded()) { + if (!retainCurrent || !isActive() || (_nextGeometry && _nextGeometry->isLoaded())) { applyNextGeometry(); } } @@ -1873,19 +1898,21 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { int opaqueMeshPartsRendered = 0; // now, for each model in the scene, render the mesh portions - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, true, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, false, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, true, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, false, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, true, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, false, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, true, args); - - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, false, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, false, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, false, args); - opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, true, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, true, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, true, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, true, false, args); + + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, false, false, args); + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, false, false, args); + + opaqueMeshPartsRendered += renderMeshesForModelsInScene(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, true, args); // render translucent meshes afterwards { @@ -1898,14 +1925,14 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { int translucentParts = 0; const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, false, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, true, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, false, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, true, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, false, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, true, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, false, args); { @@ -1921,14 +1948,14 @@ void Model::endScene(RenderMode mode, RenderArgs* args) { // batch.setFramebuffer(DependencyManager::get()->getPrimaryTransparentFramebuffer()); const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, false, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, true, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, false, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args); - translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, false, args); + translucentParts += renderMeshesForModelsInScene(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, false, args); // batch.setFramebuffer(DependencyManager::get()->getPrimaryOpaqueFramebuffer()); } @@ -2017,7 +2044,7 @@ bool Model::renderInScene(float alpha, RenderArgs* args) { updateGeometry(); simulate(0.0, true); } - + renderSetup(args); _modelsInScene.push_back(this); return true; @@ -2057,8 +2084,8 @@ void Model::segregateMeshGroups() { if (wantDebug) { qCDebug(renderutils) << "materialID:" << materialID << "parts:" << mesh.parts.size(); } - - RenderKey key(translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned); + + RenderKey key(translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe()); // reuse or create the bucket corresponding to that key and insert the mesh as unsorted _renderBuckets[key.getRaw()]._unsortedMeshes.insertMulti(materialID, i); @@ -2067,20 +2094,20 @@ void Model::segregateMeshGroups() { for(auto& b : _renderBuckets) { foreach(auto i, b.second._unsortedMeshes) { b.second._meshes.append(i); - b.second._unsortedMeshes.clear(); } + b.second._unsortedMeshes.clear(); } _meshGroupsKnown = true; -} +} -QVector* Model::pickMeshList(bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned) { +QVector* Model::pickMeshList(bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) { PROFILE_RANGE(__FUNCTION__); // depending on which parameters we were called with, pick the correct mesh group to render QVector* whichList = NULL; - RenderKey key(translucent, hasLightmap, hasTangents, hasSpecular, isSkinned); + RenderKey key(translucent, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); auto bucket = _renderBuckets.find(key.getRaw()); if (bucket != _renderBuckets.end()) { @@ -2091,10 +2118,10 @@ QVector* Model::pickMeshList(bool translucent, float alphaThreshold, bool h } void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, Locations*& locations) { - RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); + RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); auto pipeline = _renderPipelineLib.find(key.getRaw()); if (pipeline == _renderPipelineLib.end()) { qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw(); @@ -2119,7 +2146,7 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f } int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args) { PROFILE_RANGE(__FUNCTION__); int meshPartsRendered = 0; @@ -2128,12 +2155,12 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool Locations* locations = nullptr; foreach(Model* model, _modelsInScene) { - QVector* whichList = model->pickMeshList(translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); + QVector* whichList = model->pickMeshList(translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); if (whichList) { QVector& list = *whichList; if (list.size() > 0) { if (pickProgramsNeeded) { - pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, args, locations); + pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe, args, locations); pickProgramsNeeded = false; } @@ -2147,14 +2174,14 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool } int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, bool forceRenderSomeMeshes) { PROFILE_RANGE(__FUNCTION__); int meshPartsRendered = 0; //Pick the mesh list with the requested render flags - QVector* whichList = pickMeshList(translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned); + QVector* whichList = pickMeshList(translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe); if (!whichList) { return 0; } @@ -2166,9 +2193,9 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl } Locations* locations = nullptr; - pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, + pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe, args, locations); - meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, + meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, args, locations, forceRenderSomeMeshes); return meshPartsRendered; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index dba8f5277f..126e8ad4d1 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -116,6 +116,9 @@ public: Q_INVOKABLE void setCollisionModelURL(const QUrl& url); const QUrl& getCollisionURL() const { return _collisionUrl; } + void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } + bool isWireframe() const { return _isWireframe; } + /// Sets the distance parameter used for LOD computations. void setLODDistance(float distance) { _lodDistance = distance; } @@ -350,6 +353,7 @@ private: void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes bool _meshGroupsKnown; + bool _isWireframe; // debug rendering support @@ -366,23 +370,23 @@ private: // helper functions used by render() or renderInScene() void renderSetup(RenderArgs* args); bool renderCore(float alpha, RenderArgs::RenderMode mode, RenderArgs* args); - int renderMeshes(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL, + int renderMeshes(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args = NULL, bool forceRenderMeshes = false); void setupBatchTransform(gpu::Batch& batch, RenderArgs* args); - QVector* pickMeshList(bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned); + QVector* pickMeshList(bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe); int renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args, Locations* locations, bool forceRenderSomeMeshes = false); static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args, Locations*& locations); static int renderMeshesForModelsInScene(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args); + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args); static AbstractViewStateInterface* _viewState; @@ -400,7 +404,8 @@ private: IS_DEPTH_ONLY_FLAG, IS_SHADOW_FLAG, IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror" - + IS_WIREFRAME_FLAG, + NUM_FLAGS, }; @@ -415,7 +420,7 @@ private: IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG), IS_SHADOW = (1 << IS_SHADOW_FLAG), IS_MIRROR = (1 << IS_MIRROR_FLAG), - + IS_WIREFRAME = (1 << IS_WIREFRAME_FLAG), }; typedef unsigned short Flags; @@ -433,6 +438,7 @@ private: bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); } bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing bool isMirror() const { return isFlag(IS_MIRROR); } + bool isWireFrame() const { return isFlag(IS_WIREFRAME); } Flags _flags = 0; short _spare = 0; @@ -442,22 +448,24 @@ private: RenderKey( bool translucent, bool hasLightmap, - bool hasTangents, bool hasSpecular, bool isSkinned) : + bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : RenderKey( (translucent ? IS_TRANSLUCENT : 0) | (hasLightmap ? HAS_LIGHTMAP : 0) | (hasTangents ? HAS_TANGENTS : 0) | (hasSpecular ? HAS_SPECULAR : 0) | (isSkinned ? IS_SKINNED : 0) + | (isWireframe ? IS_WIREFRAME : 0) ) {} RenderKey(RenderArgs::RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, - bool hasTangents, bool hasSpecular, bool isSkinned) : + bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) : RenderKey( ((translucent && (alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0) | (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly | (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0) | (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0) | (isSkinned ? IS_SKINNED : 0) + | (isWireframe ? IS_WIREFRAME : 0) | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0) | ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0) | ((mode == RenderArgs::MIRROR_RENDER_MODE) ? IS_MIRROR :0) diff --git a/libraries/render-utils/src/TextureCache.cpp b/libraries/render-utils/src/TextureCache.cpp index 2f9960355f..bd243cbe88 100644 --- a/libraries/render-utils/src/TextureCache.cpp +++ b/libraries/render-utils/src/TextureCache.cpp @@ -294,7 +294,7 @@ GLuint TextureCache::getShadowDepthTextureID() { /// Returns a texture version of an image file gpu::TexturePointer TextureCache::getImageTexture(const QString & path) { - QImage image(path); + QImage image = QImage(path).mirrored(false, true); gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); if (image.hasAlphaChannel()) { diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index bc3e2edb6d..3019535d2a 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -22,10 +22,60 @@ public: enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; enum DebugFlags { - RENDER_DEBUG_NONE=0, - RENDER_DEBUG_HULLS=1, - RENDER_DEBUG_SIMULATION_OWNERSHIP=2 + RENDER_DEBUG_NONE = 0, + RENDER_DEBUG_HULLS = 1, + RENDER_DEBUG_SIMULATION_OWNERSHIP = 2, }; + + RenderArgs(OctreeRenderer* renderer = nullptr, + ViewFrustum* viewFrustum = nullptr, + float sizeScale = 1.0f, + int boundaryLevelAdjust = 0, + RenderMode renderMode = DEFAULT_RENDER_MODE, + RenderSide renderSide = MONO, + DebugFlags debugFlags = RENDER_DEBUG_NONE, + + int elementsTouched = 0, + int itemsRendered = 0, + int itemsOutOfView = 0, + int itemsTooSmall = 0, + + int meshesConsidered = 0, + int meshesRendered = 0, + int meshesOutOfView = 0, + int meshesTooSmall = 0, + + int materialSwitches = 0, + int trianglesRendered = 0, + int quadsRendered = 0, + + int translucentMeshPartsRendered = 0, + int opaqueMeshPartsRendered = 0) : + _renderer(renderer), + _viewFrustum(viewFrustum), + _sizeScale(sizeScale), + _boundaryLevelAdjust(boundaryLevelAdjust), + _renderMode(renderMode), + _renderSide(renderSide), + _debugFlags(debugFlags), + + _elementsTouched(elementsTouched), + _itemsRendered(itemsRendered), + _itemsOutOfView(itemsOutOfView), + _itemsTooSmall(itemsTooSmall), + + _meshesConsidered(meshesConsidered), + _meshesRendered(meshesRendered), + _meshesOutOfView(meshesOutOfView), + _meshesTooSmall(meshesTooSmall), + + _materialSwitches(materialSwitches), + _trianglesRendered(trianglesRendered), + _quadsRendered(quadsRendered), + + _translucentMeshPartsRendered(translucentMeshPartsRendered), + _opaqueMeshPartsRendered(opaqueMeshPartsRendered) { + } OctreeRenderer* _renderer; ViewFrustum* _viewFrustum; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 68d448114c..17a32e7910 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -23,11 +23,19 @@ const int BYTES_PER_COLOR = 3; const int BYTES_PER_FLAGS = 1; -typedef unsigned char rgbColor[BYTES_PER_COLOR]; typedef unsigned char colorPart; typedef unsigned char nodeColor[BYTES_PER_COLOR + BYTES_PER_FLAGS]; typedef unsigned char rgbColor[BYTES_PER_COLOR]; +inline QDebug& operator<<(QDebug& dbg, const rgbColor& c) { + dbg.nospace() << "{type='rgbColor'" + ", red=" << c[0] << + ", green=" << c[1] << + ", blue=" << c[2] << + "}"; + return dbg; +} + struct xColor { unsigned char red; unsigned char green;