diff --git a/examples/example/painting/hydraPaint.js b/examples/example/painting/hydraPaint.js new file mode 100644 index 0000000000..29a3323e72 --- /dev/null +++ b/examples/example/painting/hydraPaint.js @@ -0,0 +1,225 @@ +// +// hydraPaint.js +// examples +// +// Created by Eric Levin on 5/14/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +var LEFT = 0; +var RIGHT = 1; +var LASER_WIDTH = 3; +var LASER_COLOR = { + red: 50, + green: 150, + blue: 200 +}; +var TRIGGER_THRESHOLD = .1; + +var MAX_POINTS_PER_LINE = 40; + +var LIFETIME = 6000; +var DRAWING_DEPTH = 1; +var LINE_DIMENSIONS = 20; + + +var MIN_POINT_DISTANCE = 0.01; + +var MIN_BRUSH_RADIUS = 0.08; +var MAX_BRUSH_RADIUS = 0.1; + +var RIGHT_BUTTON_1 = 7 +var RIGHT_BUTTON_2 = 8 +var RIGHT_BUTTON_3 = 9; +var RIGHT_BUTTON_4 = 10 +var LEFT_BUTTON_1 = 1; +var LEFT_BUTTON_2 = 2; +var LEFT_BUTTON_3 = 3; +var LEFT_BUTTON_4 = 4; + +var colorPalette = [{ + red: 250, + green: 0, + blue: 0 +}, { + red: 214, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var MIN_STROKE_WIDTH = 0.002; +var MAX_STROKE_WIDTH = 0.05; + +function controller(side, cycleColorButton) { + this.triggerHeld = false; + this.triggerThreshold = 0.9; + this.side = side; + this.palm = 2 * side; + this.tip = 2 * side + 1; + this.trigger = side; + this.cycleColorButton = cycleColorButton; + + this.points = []; + this.normals = []; + this.strokeWidths = []; + + this.currentColorIndex = 0; + this.currentColor = colorPalette[this.currentColorIndex]; + + var self = this; + + + this.brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: this.currentColor, + dimensions: { + x: MIN_BRUSH_RADIUS, + y: MIN_BRUSH_RADIUS, + z: MIN_BRUSH_RADIUS + } + }); + + this.cycleColor = function() { + this.currentColor = colorPalette[++this.currentColorIndex]; + if (this.currentColorIndex === colorPalette.length - 1) { + this.currentColorIndex = -1; + } + } + this.newLine = function(position) { + this.linePosition = position; + this.line = Entities.addEntity({ + position: position, + type: "PolyLine", + color: this.currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + lifetime: LIFETIME + }); + this.points = []; + this.normals = [] + this.strokeWidths = []; + } + + this.update = function(deltaTime) { + this.updateControllerState(); + var newBrushPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH); + var newBrushPos = Vec3.sum(this.palmPosition, newBrushPosOffset); + var brushRadius = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_BRUSH_RADIUS, MAX_BRUSH_RADIUS) + Entities.editEntity(this.brush, { + position: newBrushPos, + color: this.currentColor, + dimensions: { + x: brushRadius, + y: brushRadius, + z: brushRadius + } + }); + + + if (this.triggerValue > TRIGGER_THRESHOLD && !this.drawing) { + this.newLine(newBrushPos); + this.drawing = true; + } else if (this.drawing && this.triggerValue < TRIGGER_THRESHOLD) { + this.drawing = false; + } + + if (this.drawing && this.points.length < MAX_POINTS_PER_LINE) { + var localPoint = Vec3.subtract(newBrushPos, this.linePosition); + if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) { + //Need a minimum distance to avoid binormal NANs + return; + } + + this.points.push(localPoint); + var normal = computeNormal(newBrushPos, Camera.getPosition()); + + this.normals.push(normal); + var strokeWidth = map(this.triggerValue, TRIGGER_THRESHOLD, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH); + this.strokeWidths.push(strokeWidth); + Entities.editEntity(this.line, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + color: this.currentColor + }); + + } + } + + + this.updateControllerState = function() { + this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton); + this.palmPosition = Controller.getSpatialControlPosition(this.palm); + this.tipPosition = Controller.getSpatialControlPosition(this.tip); + this.palmNormal = Controller.getSpatialControlNormal(this.palm); + this.triggerValue = Controller.getTriggerValue(this.trigger); + + + if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { + this.cycleColor(); + Entities.editEntity(this.brush, { + // color: this.currentColor + }); + } + + this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; + + } + + this.cleanup = function() { + Entities.deleteEntity(self.brush); + } +} + +function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); +} + +function update(deltaTime) { + leftController.update(deltaTime); + rightController.update(deltaTime); +} + +function scriptEnding() { + leftController.cleanup(); + rightController.cleanup(); +} + +function vectorIsZero(v) { + return v.x === 0 && v.y === 0 && v.z === 0; +} + + +var rightController = new controller(RIGHT, RIGHT_BUTTON_4); +var leftController = new controller(LEFT, LEFT_BUTTON_4); +Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} \ No newline at end of file diff --git a/examples/example/painting/mousePaint.js b/examples/example/painting/mousePaint.js new file mode 100644 index 0000000000..30a2e1fbf9 --- /dev/null +++ b/examples/example/painting/mousePaint.js @@ -0,0 +1,194 @@ +// +// mousePaint.js +// examples +// +// Created by Eric Levin on 6/4/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra or mouse! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +var LINE_DIMENSIONS = 10; +var LIFETIME = 6000; +var EVENT_CHANGE_THRESHOLD = 200; +var LINE_WIDTH = .07; +var MAX_POINTS_PER_LINE = 40; +var points = []; +var normals = []; +var deletedLines = []; +var strokeWidths = []; +var count = 0; +var prevEvent = {x: 0, y: 0}; +var eventChange; + +var MIN_POINT_DISTANCE = .01; + +var colorPalette = [{ + red: 250, + green: 0, + blue: 0 +}, { + red: 214, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var currentColorIndex = 0; +var currentColor = colorPalette[currentColorIndex]; + +function cycleColor() { + currentColor = colorPalette[++currentColorIndex]; + if (currentColorIndex === colorPalette.length - 1) { + currentColorIndex = -1; + } + +} + +MousePaint(); + +function MousePaint() { + var DRAWING_DISTANCE = 5; + var lines = []; + var isDrawing = false; + + var line, linePosition; + + var BRUSH_SIZE = .05; + + var brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: currentColor, + dimensions: { + x: BRUSH_SIZE, + y: BRUSH_SIZE, + z: BRUSH_SIZE + } + }); + + + function newLine(position) { + linePosition = position; + line = Entities.addEntity({ + position: position, + type: "PolyLine", + color: currentColor, + dimensions: { + x: LINE_DIMENSIONS, + y: LINE_DIMENSIONS, + z: LINE_DIMENSIONS + }, + linePoints: [], + lifetime: LIFETIME + }); + points = []; + normals = [] + strokeWidths = []; + lines.push(line); + } + + + + function mouseMoveEvent(event) { + + var pickRay = Camera.computePickRay(event.x, event.y); + count++; + var worldPoint = computeWorldPoint(pickRay); + Entities.editEntity(brush, { + position: worldPoint + }); + + eventChange = Math.sqrt(Math.pow(event.x - prevEvent.x, 2) + Math.pow(event.y - prevEvent.y, 2)); + localPoint = computeLocalPoint(worldPoint); + if (!isDrawing || points.length > MAX_POINTS_PER_LINE || eventChange > EVENT_CHANGE_THRESHOLD || + Vec3.distance(points[points.length - 1], localPoint) < MIN_POINT_DISTANCE) { + return; + } + + points.push(localPoint) + normals.push(computeNormal(worldPoint, pickRay.origin)); + strokeWidths.push(LINE_WIDTH); + Entities.editEntity(line, { + strokeWidths: strokeWidths, + linePoints: points, + normals: normals, + }); + prevEvent = event; + } + + function computeNormal(p1, p2) { + return Vec3.normalize(Vec3.subtract(p2, p1)); + } + + function computeWorldPoint(pickRay) { + var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE); + return Vec3.sum(pickRay.origin, addVector); + } + + function computeLocalPoint(worldPoint) { + var localPoint = Vec3.subtract(worldPoint, linePosition); + return localPoint; + } + + function mousePressEvent(event) { + if (!event.isLeftButton) { + isDrawing = false; + return; + } + var pickRay = Camera.computePickRay(event.x, event.y); + prevEvent = {x: event.x, y:event.y}; + var worldPoint = computeWorldPoint(pickRay); + newLine(worldPoint); + var localPoint = computeLocalPoint(worldPoint); + points.push(localPoint); + normals.push(computeNormal(worldPoint, pickRay.origin)); + strokeWidths.push(0.07); + isDrawing = true; + } + + function mouseReleaseEvent() { + isDrawing = false; + } + + function keyPressEvent(event) { + if (event.text === "SPACE") { + cycleColor(); + Entities.editEntity(brush, { + color: currentColor + }); + } + } + + function cleanup() { + lines.forEach(function(line) { + // Entities.deleteEntity(line); + }); + Entities.deleteEntity(brush); + } + + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Script.scriptEnding.connect(cleanup); + + Controller.keyPressEvent.connect(keyPressEvent); +} diff --git a/examples/notifications.js b/examples/notifications.js index b332fb401f..63d94fbd92 100644 --- a/examples/notifications.js +++ b/examples/notifications.js @@ -595,7 +595,7 @@ function menuItemEvent(menuItem) { LODManager.LODDecreased.connect(function() { var warningText = "\n" + "Due to the complexity of the content, the \n" - + "level of detail has been decreased." + + "level of detail has been decreased. " + "You can now see: \n" + LODManager.getLODFeedbackText(); diff --git a/interface/resources/images/paintStroke.png b/interface/resources/images/paintStroke.png new file mode 100644 index 0000000000..b9feb0d485 Binary files /dev/null and b/interface/resources/images/paintStroke.png differ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 44bcea5484..35fc0fba11 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -815,7 +815,7 @@ void Application::initializeGL() { init(); qCDebug(interfaceapp, "init() complete."); - // create thread for parsing of octee data independent of the main network and rendering threads + // create thread for parsing of octree data independent of the main network and rendering threads _octreeProcessor.initialize(_enableProcessOctreeThread); connect(&_octreeProcessor, &OctreePacketProcessor::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); _entityEditSender.initialize(_enableProcessOctreeThread); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 5ab5869a9d..5fce4d9619 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -107,12 +107,14 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); Rig::HeadParameters params; + params.modelRotation = getRotation(); + params.modelTranslation = getTranslation(); params.leanSideways = _owningAvatar->getHead()->getFinalLeanSideways(); params.leanForward = _owningAvatar->getHead()->getFinalLeanSideways(); params.torsoTwist = _owningAvatar->getHead()->getTorsoTwist(); params.localHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInLocalFrame(); params.worldHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInWorldFrame(); - params.eyeLookAt = _owningAvatar->getHead()->getCorrectedLookAtPosition(); + params.eyeLookAt = _owningAvatar->getHead()->getLookAtPosition(); params.eyeSaccade = _owningAvatar->getHead()->getSaccade(); params.leanJointIndex = geometry.leanJointIndex; params.neckJointIndex = geometry.neckJointIndex; diff --git a/libraries/animation/src/JointState.cpp b/libraries/animation/src/JointState.cpp index 440a1c18b3..78da30fdcd 100644 --- a/libraries/animation/src/JointState.cpp +++ b/libraries/animation/src/JointState.cpp @@ -230,11 +230,13 @@ void JointState::setRotationInConstrainedFrame(glm::quat targetRotation, float p } void JointState::setRotationInConstrainedFrameInternal(const glm::quat& targetRotation) { - glm::quat parentRotation = computeParentRotation(); - _rotationInConstrainedFrame = targetRotation; - _transformChanged = true; - // R' = Rp * Rpre * r' * Rpost - _rotation = parentRotation * _preRotation * _rotationInConstrainedFrame * _postRotation; + if (_rotationInConstrainedFrame != targetRotation) { + glm::quat parentRotation = computeParentRotation(); + _rotationInConstrainedFrame = targetRotation; + _transformChanged = true; + // R' = Rp * Rpre * r' * Rpost + _rotation = parentRotation * _preRotation * _rotationInConstrainedFrame * _postRotation; + } } void JointState::setVisibleRotationInConstrainedFrame(const glm::quat& targetRotation) { diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index b8bb9db6ea..1a8bd0bbad 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -27,6 +27,10 @@ void Rig::HeadParameters::dump() const { axis = glm::axis(worldHeadOrientation); theta = glm::angle(worldHeadOrientation); qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", axis.x, axis.y, axis.z, theta); + axis = glm::axis(modelRotation); + theta = glm::angle(modelRotation); + qCDebug(animation, " modelRotation axis = (%.5f, %.5f, %.5f), theta = %0.5f", axis.x, axis.y, axis.z, theta); + qCDebug(animation, " modelTranslation = (%.5f, %.5f, %.5f)", modelTranslation.x, modelTranslation.y, modelTranslation.z); qCDebug(animation, " eyeLookAt = (%.5f, %.5f, %.5f)", eyeLookAt.x, eyeLookAt.y, eyeLookAt.z); qCDebug(animation, " eyeSaccade = (%.5f, %.5f, %.5f)", eyeSaccade.x, eyeSaccade.y, eyeSaccade.z); qCDebug(animation, " leanJointIndex = %.d", leanJointIndex); @@ -782,8 +786,8 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) { void Rig::updateFromHeadParameters(const HeadParameters& params) { updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist); updateNeckJoint(params.neckJointIndex, params.localHeadOrientation, params.leanSideways, params.leanForward, params.torsoTwist); - updateEyeJoint(params.leftEyeJointIndex, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); - updateEyeJoint(params.rightEyeJointIndex, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); + updateEyeJoint(params.leftEyeJointIndex, params.modelTranslation, params.modelRotation, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); + updateEyeJoint(params.rightEyeJointIndex, params.modelTranslation, params.modelRotation, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); } void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) { @@ -824,22 +828,21 @@ void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, floa } } -void Rig::updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade) { +void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { auto& state = _jointStates[index]; auto& parentState = _jointStates[state.getParentIndex()]; // NOTE: at the moment we do the math in the world-frame, hence the inverse transform is more complex than usual. - glm::mat4 inverse = glm::inverse(parentState.getTransform() * - glm::translate(getJointDefaultTranslationInConstrainedFrame(index)) * + glm::mat4 inverse = glm::inverse(glm::mat4_cast(modelRotation) * parentState.getTransform() * + glm::translate(state.getDefaultTranslationInConstrainedFrame()) * state.getPreTransform() * glm::mat4_cast(state.getPreRotation() * state.getDefaultRotation())); glm::vec3 front = glm::vec3(inverse * glm::vec4(worldHeadOrientation * IDENTITY_FRONT, 0.0f)); - glm::vec3 lookAtDelta = lookAt; + glm::vec3 lookAtDelta = lookAtSpot - modelTranslation; glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(lookAtDelta + glm::length(lookAtDelta) * saccade, 1.0f)); glm::quat between = rotationBetween(front, lookAt); const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE; - float angle = glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE); - glm::quat rot = glm::angleAxis(angle, glm::axis(between)); - setJointRotationInConstrainedFrame(index, rot * state.getDefaultRotation(), DEFAULT_PRIORITY); + state.setRotationInConstrainedFrame(glm::angleAxis(glm::clamp(glm::angle(between), -MAX_ANGLE, MAX_ANGLE), glm::axis(between)) * + state.getDefaultRotation(), DEFAULT_PRIORITY); } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 113d097f96..face79bc15 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -54,10 +54,12 @@ public: float leanSideways = 0.0f; // degrees float leanForward = 0.0f; // degrees float torsoTwist = 0.0f; // degrees + glm::quat modelRotation = glm::quat(); glm::quat localHeadOrientation = glm::quat(); glm::quat worldHeadOrientation = glm::quat(); glm::vec3 eyeLookAt = glm::vec3(); // world space glm::vec3 eyeSaccade = glm::vec3(); // world space + glm::vec3 modelTranslation = glm::vec3(); int leanJointIndex = -1; int neckJointIndex = -1; int leftEyeJointIndex = -1; @@ -163,7 +165,7 @@ public: void updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist); void updateNeckJoint(int index, const glm::quat& localHeadOrientation, float leanSideways, float leanForward, float torsoTwist); - void updateEyeJoint(int index, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade); + void updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAt, const glm::vec3& saccade); QVector _jointStates; int _rootJointIndex = -1; diff --git a/libraries/entities-renderer/src/DeferredBufferWrite.slh b/libraries/entities-renderer/src/DeferredBufferWrite.slh new file mode 100755 index 0000000000..293d38096f --- /dev/null +++ b/libraries/entities-renderer/src/DeferredBufferWrite.slh @@ -0,0 +1,78 @@ + +<@if not DEFERRED_BUFFER_WRITE_SLH@> +<@def DEFERRED_BUFFER_WRITE_SLH@> + +layout(location = 0) out vec4 _fragColor0; +layout(location = 1) out vec4 _fragColor1; +layout(location = 2) out vec4 _fragColor2; + +// the glow intensity +uniform float glowIntensity; + +// the alpha threshold +uniform float alphaThreshold; + +uniform sampler2D normalFittingMap; + +vec3 bestFitNormal(vec3 normal) { + vec3 absNorm = abs(normal); + float maxNAbs = max(absNorm.z, max(absNorm.x, absNorm.y)); + + vec2 texcoord = (absNorm.z < maxNAbs ? + (absNorm.y < maxNAbs ? absNorm.yz : absNorm.xz) : + absNorm.xy); + texcoord = (texcoord.x < texcoord.y ? texcoord.yx : texcoord.xy); + texcoord.y /= texcoord.x; + vec3 cN = normal / maxNAbs; + float fittingScale = texture(normalFittingMap, texcoord).a; + cN *= fittingScale; + return (cN * 0.5 + 0.5); +} + +float evalOpaqueFinalAlpha(float alpha, float mapAlpha) { + return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold)); +} + +const vec3 DEFAULT_SPECULAR = vec3(0.1); +const float DEFAULT_SHININESS = 10; + +void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) { + if (alpha != glowIntensity) { + discard; + } + _fragColor0 = vec4(diffuse.rgb, alpha); + _fragColor1 = vec4(bestFitNormal(normal), 1.0); + _fragColor2 = vec4(specular, shininess / 128.0); +} + +void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess, vec3 emissive) { + if (alpha != glowIntensity) { + discard; + } + + _fragColor0 = vec4(diffuse.rgb, alpha); + //_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); + _fragColor1 = vec4(bestFitNormal(normal), 0.5); + _fragColor2 = vec4(emissive, shininess / 128.0); +} + +void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) { + if (alpha <= alphaThreshold) { + discard; + } + + _fragColor0 = vec4(diffuse.rgb, alpha); + // _fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0); + // _fragColor2 = vec4(specular, shininess / 128.0); +} + +<@endif@> diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 16324063ad..50f79e2ff3 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -38,6 +38,7 @@ #include "RenderableZoneEntityItem.h" #include "RenderableLineEntityItem.h" #include "RenderablePolyVoxEntityItem.h" +#include "RenderablePolyLineEntityItem.h" #include "EntitiesRendererLogging.h" #include "AddressManager.h" #include "EntityRig.h" @@ -66,6 +67,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(Line, RenderableLineEntityItem::factory) REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyVox, RenderablePolyVoxEntityItem::factory) + REGISTER_ENTITY_TYPE_WITH_FACTORY(PolyLine, RenderablePolyLineEntityItem::factory) _currentHoverOverEntityID = UNKNOWN_ENTITY_ID; _currentClickingOnEntityID = UNKNOWN_ENTITY_ID; diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 461b64a9e6..bf9710857a 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -18,6 +18,9 @@ namespace render { if (payload->entity->getType() == EntityTypes::Light) { return ItemKey::Builder::light(); } + if (payload && payload->entity->getType() == EntityTypes::PolyLine) { + return ItemKey::Builder::transparentShape(); + } } return ItemKey::Builder::opaqueShape(); } diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index 4b556a8339..3735690c33 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -35,6 +35,9 @@ void RenderableLineEntityItem::updateGeometry() { } } + + + void RenderableLineEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableLineEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Line); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 6d2ff30d4b..eed908e429 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -275,9 +275,12 @@ void RenderableModelEntityItem::render(RenderArgs* args) { } if (jointsMapped()) { - auto frameData = getAnimationFrame(); - for (int i = 0; i < frameData.size(); i++) { - _model->setJointState(i, true, frameData[i]); + bool newFrame; + auto frameData = getAnimationFrame(newFrame); + if (newFrame) { + for (int i = 0; i < frameData.size(); i++) { + _model->setJointState(i, true, frameData[i]); + } } } } diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp new file mode 100644 index 0000000000..c6b7b58538 --- /dev/null +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -0,0 +1,158 @@ +// +// RenderablePolyLineEntityItem.cpp +// libraries/entities-renderer/src/ +// +// Created by Eric Levin on 8/10/15 +// Copyright 2015 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 +#include +#include +#include +#include + +#include "RenderablePolyLineEntityItem.h" + +#include "paintStroke_vert.h" +#include "paintStroke_frag.h" + + + +EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + return EntityItemPointer(new RenderablePolyLineEntityItem(entityID, properties)); +} + +RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +PolyLineEntityItem(entityItemID, properties) { + _numVertices = 0; + +} + +gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline; +gpu::Stream::FormatPointer RenderablePolyLineEntityItem::_format; +gpu::TexturePointer RenderablePolyLineEntityItem::_texture; +GLint RenderablePolyLineEntityItem::PAINTSTROKE_GPU_SLOT; + +void RenderablePolyLineEntityItem::createPipeline() { + static const int NORMAL_OFFSET = 12; + static const int COLOR_OFFSET = 24; + static const int TEXTURE_OFFSET = 28; + + auto textureCache = DependencyManager::get(); + QString path = PathUtils::resourcesPath() + "images/paintStroke.png"; + _texture = textureCache->getImageTexture(path); + _format.reset(new gpu::Stream::Format()); + _format->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + _format->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), NORMAL_OFFSET); + _format->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, COLOR_OFFSET); + _format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), TEXTURE_OFFSET); + + auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(paintStroke_vert))); + auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(paintStroke_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + + gpu::Shader::BindingSet slotBindings; + PAINTSTROKE_GPU_SLOT = 0; + slotBindings.insert(gpu::Shader::Binding(std::string("paintStrokeTextureBinding"), PAINTSTROKE_GPU_SLOT)); + gpu::Shader::makeProgram(*program, slotBindings); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); +} + +void RenderablePolyLineEntityItem::updateGeometry() { + _numVertices = 0; + _verticesBuffer.reset(new gpu::Buffer()); + int vertexIndex = 0; + vec2 uv; + float tailStart = 0.0f; + float tailEnd = 0.25f; + float tailLength = tailEnd - tailStart; + + float headStart = 0.76f; + float headEnd = 1.0f; + float headLength = headEnd - headStart; + float uCoord, vCoord; + + int numTailStrips = 5; + int numHeadStrips = 10; + int startHeadIndex = _normals.size() - numHeadStrips; + for (int i = 0; i < _normals.size(); i++) { + uCoord = 0.26f; + vCoord = 0.0f; + //tail + if(i < numTailStrips) { + uCoord = float(i)/numTailStrips * tailLength + tailStart; + } + + //head + if( i > startHeadIndex) { + uCoord = float( (i+ 1) - startHeadIndex)/numHeadStrips * headLength + headStart; + } + + uv = vec2(uCoord, vCoord); + + _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_vertices.at(vertexIndex)); + _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_normals.at(i)); + _verticesBuffer->append(sizeof(int), (gpu::Byte*)&_color); + _verticesBuffer->append(sizeof(glm::vec2), (gpu::Byte*)&uv); + vertexIndex++; + + uv.y = 1.0f; + _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_vertices.at(vertexIndex)); + _verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_normals.at(i)); + _verticesBuffer->append(sizeof(int), (gpu::Byte*)_color); + _verticesBuffer->append(sizeof(glm::vec2), (const gpu::Byte*)&uv); + vertexIndex++; + + _numVertices +=2; + } + _pointsChanged = false; + +} + + +void RenderablePolyLineEntityItem::render(RenderArgs* args) { + QWriteLocker lock(&_quadReadWriteLock); + if (_points.size() < 2 || _vertices.size() != _normals.size() * 2) { + return; + } + + if (!_pipeline) { + createPipeline(); + } + + PerformanceTimer perfTimer("RenderablePolyLineEntityItem::render"); + Q_ASSERT(getType() == EntityTypes::PolyLine); + + Q_ASSERT(args->_batch); + if (_pointsChanged) { + updateGeometry(); + } + + gpu::Batch& batch = *args->_batch; + Transform transform = Transform(); + transform.setTranslation(getPosition()); + transform.setRotation(getRotation()); + batch.setModelTransform(transform); + + batch.setPipeline(_pipeline); + batch.setResourceTexture(PAINTSTROKE_GPU_SLOT, _texture); + + batch.setInputFormat(_format); + batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); + + batch.draw(gpu::TRIANGLE_STRIP, _numVertices, 0); + + RenderableDebugableEntityItem::render(this, args); +}; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h new file mode 100644 index 0000000000..59bf416d7a --- /dev/null +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -0,0 +1,47 @@ +// +// RenderablePolyLineEntityItem.h +// libraries/entities-renderer/src/ +// +// Created by Eric Levin on 6/22/15. +// Copyright 2015 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_RenderablePolyLineEntityItem_h +#define hifi_RenderablePolyLineEntityItem_h + +#include +#include +#include "RenderableDebugableEntityItem.h" +#include "RenderableEntityItem.h" +#include +#include +#include + + +class RenderablePolyLineEntityItem : public PolyLineEntityItem { +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + static void createPipeline(); + RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + + virtual void render(RenderArgs* args); + + SIMPLE_RENDERABLE(); + + static gpu::PipelinePointer _pipeline; + static gpu::Stream::FormatPointer _format; + static gpu::TexturePointer _texture; + static GLint PAINTSTROKE_GPU_SLOT; + +protected: + void updateGeometry(); + gpu::BufferPointer _verticesBuffer; + unsigned int _numVertices; + +}; + + +#endif // hifi_RenderablePolyLineEntityItem_h diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 2a41ea63fb..23093b9f3f 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -40,7 +40,7 @@ #include "EntityTreeRenderer.h" #include "polyvox_vert.h" #include "polyvox_frag.h" -#include "RenderablePolyVoxEntityItem.h" +#include "RenderablePolyVoxEntityItem.h" gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr; diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf new file mode 100644 index 0000000000..4e2bc8d097 --- /dev/null +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -0,0 +1,45 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// paintStroke.frag +// fragment shader +// +// Created by Eric Levin on 8/10/2015 +// Copyright 2015 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 DeferredBufferWrite.slh@> + + +// the diffuse texture +uniform sampler2D originalTexture; + +// the interpolated normal +in vec3 interpolatedNormal; +in vec2 varTexcoord; +in vec4 varColor; + +float rand(vec2 point){ + return fract(sin(dot(point.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + + + +void main(void) { + + + vec4 texel = texture(originalTexture, varTexcoord); + int frontCondition = 1 -int(gl_FrontFacing) * 2; + vec3 color = varColor.rgb; + //vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess + packDeferredFragmentTranslucent( + interpolatedNormal * frontCondition, + texel.a, + color *texel.rgb, + vec3(0.01, 0.01, 0.01), + 10.0); +} diff --git a/libraries/entities-renderer/src/paintStroke.slv b/libraries/entities-renderer/src/paintStroke.slv new file mode 100644 index 0000000000..7d7523deb9 --- /dev/null +++ b/libraries/entities-renderer/src/paintStroke.slv @@ -0,0 +1,40 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// paintStroke.vert +// vertex shader +// +// Created by Eric Levin on 7/20/15. +// Copyright 2014 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 gpu/Inputs.slh@> +<@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + +// the interpolated normal +out vec3 interpolatedNormal; + +//the diffuse texture +out vec2 varTexcoord; + +out vec4 varColor; + +void main(void) { + + varTexcoord = inTexCoord0.st; + + // pass along the diffuse color + varColor = inColor; + + // standard transform + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> + <$transformModelToEyeDir(cam, obj, inNormal.xyz, interpolatedNormal)$> +} \ No newline at end of file diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 698df8c669..d8b555cb59 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -28,6 +28,7 @@ #include "ZoneEntityItem.h" #include "PolyVoxEntityItem.h" #include "LineEntityItem.h" +#include "PolyLineEntityItem.h" AtmospherePropertyGroup EntityItemProperties::_staticAtmosphere; SkyboxPropertyGroup EntityItemProperties::_staticSkybox; @@ -102,6 +103,8 @@ CONSTRUCT_PROPERTY(lineWidth, LineEntityItem::DEFAULT_LINE_WIDTH), CONSTRUCT_PROPERTY(linePoints, QVector()), CONSTRUCT_PROPERTY(faceCamera, TextEntityItem::DEFAULT_FACE_CAMERA), CONSTRUCT_PROPERTY(actionData, QByteArray()), +CONSTRUCT_PROPERTY(normals, QVector()), +CONSTRUCT_PROPERTY(strokeWidths, QVector()), CONSTRUCT_PROPERTY(xTextureURL, ""), CONSTRUCT_PROPERTY(yTextureURL, ""), CONSTRUCT_PROPERTY(zTextureURL, ""), @@ -367,6 +370,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_DESCRIPTION, description); CHECK_PROPERTY_CHANGE(PROP_FACE_CAMERA, faceCamera); CHECK_PROPERTY_CHANGE(PROP_ACTION_DATA, actionData); + CHECK_PROPERTY_CHANGE(PROP_NORMALS, normals); + CHECK_PROPERTY_CHANGE(PROP_STROKE_WIDTHS, strokeWidths); CHECK_PROPERTY_CHANGE(PROP_X_TEXTURE_URL, xTextureURL); CHECK_PROPERTY_CHANGE(PROP_Y_TEXTURE_URL, yTextureURL); CHECK_PROPERTY_CHANGE(PROP_Z_TEXTURE_URL, zTextureURL); @@ -469,6 +474,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(description); COPY_PROPERTY_TO_QSCRIPTVALUE(faceCamera); COPY_PROPERTY_TO_QSCRIPTVALUE(actionData); + COPY_PROPERTY_TO_QSCRIPTVALUE(normals); + COPY_PROPERTY_TO_QSCRIPTVALUE(strokeWidths); // Sitting properties support if (!skipDefaults) { @@ -587,6 +594,8 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(description, QString, setDescription); COPY_PROPERTY_FROM_QSCRIPTVALUE(faceCamera, bool, setFaceCamera); COPY_PROPERTY_FROM_QSCRIPTVALUE(actionData, QByteArray, setActionData); + COPY_PROPERTY_FROM_QSCRIPTVALUE(normals, qVectorVec3, setNormals); + COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeWidths,qVectorFloat, setStrokeWidths); if (!honorReadOnly) { // this is used by the json reader to set things that we don't want javascript to able to affect. @@ -843,6 +852,14 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, properties.getLineWidth()); APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints()); } + + if (properties.getType() == EntityTypes::PolyLine) { + APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, properties.getLineWidth()); + APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints()); + APPEND_ENTITY_PROPERTY(PROP_NORMALS, properties.getNormals()); + APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, properties.getStrokeWidths()); + } + APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID()); APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); @@ -1097,6 +1114,14 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_WIDTH, float, setLineWidth); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector, setLinePoints); } + + + if (properties.getType() == EntityTypes::PolyLine) { + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_WIDTH, float, setLineWidth); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector, setLinePoints); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NORMALS, QVector, setNormals); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STROKE_WIDTHS, QVector, setStrokeWidths); + } READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); @@ -1215,6 +1240,9 @@ void EntityItemProperties::markAllChanged() { _descriptionChanged = true; _faceCameraChanged = true; _actionDataChanged = true; + + _normalsChanged = true; + _strokeWidthsChanged = true; _xTextureURLChanged = true; _yTextureURLChanged = true; diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 423aefd44a..8085c24d90 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -56,6 +56,7 @@ class EntityItemProperties { friend class WebEntityItem; // TODO: consider removing this friend relationship and use public methods friend class LineEntityItem; // TODO: consider removing this friend relationship and use public methods friend class PolyVoxEntityItem; // TODO: consider removing this friend relationship and use public methods + friend class PolyLineEntityItem; // TODO: consider removing this friend relationship and use public methods public: EntityItemProperties(); virtual ~EntityItemProperties(); @@ -153,6 +154,8 @@ public: DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString); DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString); DEFINE_PROPERTY(PROP_FACE_CAMERA, FaceCamera, faceCamera, bool); + DEFINE_PROPERTY(PROP_NORMALS, Normals, normals, QVector); + DEFINE_PROPERTY(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector); DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray); DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString); DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index d4fcfa8cab..e48be1da8c 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -98,7 +98,8 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { ret inline QScriptValue convertScriptValue(QScriptEngine* e, const xColor& v) { return xColorToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QScriptValue& v) { return v; } -inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorVec3ToScriptValue(e, v); } +inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) {return qVectorVec3ToScriptValue(e, v); } +inline QScriptValue convertScriptValue(QScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { QByteArray b64 = v.toBase64(); @@ -134,6 +135,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) { typedef glm::vec3 glmVec3; typedef glm::quat glmQuat; typedef QVector qVectorVec3; +typedef QVector qVectorFloat; inline float float_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); } inline quint64 quint64_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); } inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } @@ -177,6 +179,11 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal return glm::vec3(0); } +inline qVectorFloat qVectorFloat_convertFromScriptValue(const QScriptValue& v, bool& isValid) { + isValid = true; + return qVectorFloatFromScriptValue(v); +} + inline qVectorVec3 qVectorVec3_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return qVectorVec3FromScriptValue(v); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index c23c45fabf..e439710695 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -124,11 +124,17 @@ enum EntityPropertyList { PROP_FACE_CAMERA, PROP_SCRIPT_TIMESTAMP, + PROP_ACTION_DATA, - + PROP_X_TEXTURE_URL, // used by PolyVox PROP_Y_TEXTURE_URL, // used by PolyVox PROP_Z_TEXTURE_URL, // used by PolyVox + + // Used by PolyLine entity + PROP_NORMALS, + PROP_STROKE_WIDTHS, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 12f5ffe190..9654de0fc4 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -455,18 +455,18 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::function(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; } - + EntityTypes::EntityType entityType = entity->getType(); - + if (entityType != EntityTypes::Line) { return false; } - + auto now = usecTimestampNow(); auto lineEntity = std::static_pointer_cast(entity); @@ -475,19 +475,20 @@ bool EntityScriptingInterface::setPoints(QUuid entityID, std::functionsetLastEdited(now); entity->setLastBroadcast(now); _entityTree->unlock(); - + _entityTree->lockForRead(); EntityItemProperties properties = entity->getProperties(); _entityTree->unlock(); - + properties.setLinePointsDirty(); properties.setLastEdited(now); - - + + queueEntityMessage(PacketType::EntityEdit, entityID, properties); return success; } + bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value) { return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { polyVoxEntity.setSphere(center, radius, value); @@ -507,17 +508,39 @@ bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { } bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector& points) { - return setPoints(entityID, [points](LineEntityItem& lineEntity) -> bool - { - return lineEntity.setLinePoints(points); - }); + EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; + } + + EntityTypes::EntityType entityType = entity->getType(); + + if (entityType == EntityTypes::Line) { + return setPoints(entityID, [points](LineEntityItem& lineEntity) -> bool + { + return (LineEntityItem*)lineEntity.setLinePoints(points); + }); + } + + return false; } bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& point) { - return setPoints(entityID, [point](LineEntityItem& lineEntity) -> bool - { - return lineEntity.appendPoint(point); - }); + EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; + } + + EntityTypes::EntityType entityType = entity->getType(); + + if (entityType == EntityTypes::Line) { + return setPoints(entityID, [point](LineEntityItem& lineEntity) -> bool + { + return (LineEntityItem*)lineEntity.appendPoint(point); + }); + } + + return false; } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 7e74b3d26c..434134d2cd 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -22,6 +22,7 @@ #include #include "PolyVoxEntityItem.h" #include "LineEntityItem.h" +#include "PolyLineEntityItem.h" #include "EntityEditPacketSender.h" @@ -165,6 +166,7 @@ private: bool setPoints(QUuid entityID, std::function actor); void queueEntityMessage(PacketType::Value packetType, EntityItemID entityID, const EntityItemProperties& properties); + /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType, bool precisionPicking); diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index a41cc22d2e..2ed52a9e62 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -28,6 +28,7 @@ #include "ZoneEntityItem.h" #include "LineEntityItem.h" #include "PolyVoxEntityItem.h" +#include "PolyLineEntityItem.h" QMap EntityTypes::_typeToNameMap; QMap EntityTypes::_nameToTypeMap; @@ -47,6 +48,7 @@ REGISTER_ENTITY_TYPE(ParticleEffect) REGISTER_ENTITY_TYPE(Zone) REGISTER_ENTITY_TYPE(Line) REGISTER_ENTITY_TYPE(PolyVox) +REGISTER_ENTITY_TYPE(PolyLine); const QString& EntityTypes::getEntityTypeName(EntityType entityType) { QMap::iterator matchedTypeName = _typeToNameMap.find(entityType); diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 013f1064bd..30b6edbc07 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -47,7 +47,8 @@ public: Web, Line, PolyVox, - LAST = PolyVox + PolyLine, + LAST = PolyLine } EntityType; static const QString& getEntityTypeName(EntityType entityType); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 362f5dc72a..4c03f4a7da 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -218,7 +218,8 @@ void ModelEntityItem::mapJoints(const QStringList& modelJointNames) { } } -const QVector& ModelEntityItem::getAnimationFrame() { +const QVector& ModelEntityItem::getAnimationFrame(bool& newFrame) { + newFrame = false; if (!hasAnimation() || !_jointMappingCompleted) { return _lastKnownFrameData; @@ -238,6 +239,7 @@ const QVector& ModelEntityItem::getAnimationFrame() { if (animationFrameIndex != _lastKnownFrameIndex) { _lastKnownFrameIndex = animationFrameIndex; + newFrame = true; const QVector& rotations = frames[animationFrameIndex].rotations; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index e3d42e6b2c..950a95bae2 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -106,7 +106,7 @@ public: float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); } void mapJoints(const QStringList& modelJointNames); - const QVector& getAnimationFrame(); + const QVector& getAnimationFrame(bool& newFrame); bool jointsMapped() const { return _jointMappingCompleted; } bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); } diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index dc5bbb85ed..349e0c4d46 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -1,3 +1,4 @@ + // // ParticleEffectEntityItem.cpp // libraries/entities/src diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp new file mode 100644 index 0000000000..9ade80f3be --- /dev/null +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -0,0 +1,238 @@ +// +// PolyLineEntityItem.cpp +// libraries/entities/src +// +// Created by Eric Levin on 6/22/15. +// Copyright 2015 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 + +#include "PolyLineEntityItem.h" +#include "EntityTree.h" +#include "EntitiesLogging.h" +#include "EntityTreeElement.h" +#include "OctreeConstants.h" + + + +const float PolyLineEntityItem::DEFAULT_LINE_WIDTH = 0.1f; +const int PolyLineEntityItem::MAX_POINTS_PER_LINE = 70; + + +EntityItemPointer PolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + EntityItemPointer result { new PolyLineEntityItem(entityID, properties) }; + return result; +} + +PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +EntityItem(entityItemID) , +_lineWidth(DEFAULT_LINE_WIDTH), +_pointsChanged(true), +_points(QVector(0.0f)), +_vertices(QVector(0.0f)), +_normals(QVector(0.0f)), +_strokeWidths(QVector(0.0f)) +{ + _type = EntityTypes::PolyLine; + _created = properties.getCreated(); + setProperties(properties); +} + +EntityItemProperties PolyLineEntityItem::getProperties() const { + QWriteLocker lock(&_quadReadWriteLock); + EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class + + + properties._color = getXColor(); + properties._colorChanged = false; + + COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineWidth, getLineWidth); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(normals, getNormals); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeWidths, getStrokeWidths); + + properties._glowLevel = getGlowLevel(); + properties._glowLevelChanged = false; + return properties; +} + +bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) { + QWriteLocker lock(&_quadReadWriteLock); + bool somethingChanged = false; + somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class + + SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineWidth, setLineWidth); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(normals, setNormals); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(strokeWidths, setStrokeWidths); + + if (somethingChanged) { + bool wantDebug = false; + if (wantDebug) { + uint64_t now = usecTimestampNow(); + int elapsed = now - getLastEdited(); + qCDebug(entities) << "PolyLineEntityItem::setProperties() AFTER update... edited AGO=" << elapsed << + "now=" << now << " getLastEdited()=" << getLastEdited(); + } + setLastEdited(properties._lastEdited); + } + return somethingChanged; +} + +bool PolyLineEntityItem::appendPoint(const glm::vec3& point) { + if (_points.size() > MAX_POINTS_PER_LINE - 1) { + qDebug() << "MAX POINTS REACHED!"; + return false; + } + glm::vec3 halfBox = getDimensions() * 0.5f; + if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) { + qDebug() << "Point is outside entity's bounding box"; + return false; + } + _points << point; + _pointsChanged = true; + return true; +} + +bool PolyLineEntityItem::setStrokeWidths(const QVector& strokeWidths ) { + _strokeWidths = strokeWidths; + return true; +} + +bool PolyLineEntityItem::setNormals(const QVector& normals) { + _normals = normals; + if (_points.size () < 2 || _normals.size() < 2) { + return false; + } + + int minVectorSize = _normals.size(); + if (_points.size() < minVectorSize) { + minVectorSize = _points.size(); + } + if (_strokeWidths.size() < minVectorSize) { + minVectorSize = _strokeWidths.size(); + } + + _vertices.clear(); + glm::vec3 v1, v2, tangent, binormal, point; + + for (int i = 0; i < minVectorSize-1; i++) { + float width = _strokeWidths.at(i); + point = _points.at(i); + + tangent = _points.at(i+1) - point; + glm::vec3 normal = normals.at(i); + binormal = glm::normalize(glm::cross(tangent, normal)) * width; + + //This checks to make sure binormal is not a NAN + assert(binormal.x == binormal.x); + v1 = point + binormal; + v2 = point - binormal; + _vertices << v1 << v2; + } + //for last point we can just assume binormals are same since it represents last two vertices of quad + point = _points.at(_points.size() - 1); + v1 = point + binormal; + v2 = point - binormal; + _vertices << v1 << v2; + + return true; +} + +bool PolyLineEntityItem::setLinePoints(const QVector& points) { + if (points.size() > MAX_POINTS_PER_LINE) { + return false; + } + if (points.size() != _points.size()) { + _pointsChanged = true; + } + //Check to see if points actually changed. If they haven't, return before doing anything else + else if (points.size() == _points.size()) { + //same number of points, so now compare every point + for (int i = 0; i < points.size(); i++ ) { + if (points.at(i) != _points.at(i)){ + _pointsChanged = true; + break; + } + } + } + if (!_pointsChanged) { + return false; + } + + for (int i = 0; i < points.size(); i++) { + glm::vec3 point = points.at(i); + glm::vec3 pos = getPosition(); + glm::vec3 halfBox = getDimensions() * 0.5f; + if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) { + qDebug() << "Point is outside entity's bounding box"; + return false; + } + } + _points = points; + return true; +} + +int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData) { + QWriteLocker lock(&_quadReadWriteLock); + int bytesRead = 0; + const unsigned char* dataAt = data; + + READ_ENTITY_PROPERTY(PROP_COLOR, rgbColor, setColor); + READ_ENTITY_PROPERTY(PROP_LINE_WIDTH, float, setLineWidth); + READ_ENTITY_PROPERTY(PROP_LINE_POINTS, QVector, setLinePoints); + READ_ENTITY_PROPERTY(PROP_NORMALS, QVector, setNormals); + READ_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, QVector, setStrokeWidths); + + return bytesRead; +} + + +// TODO: eventually only include properties changed since the params.lastViewFrustumSent time +EntityPropertyFlags PolyLineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + requestedProperties += PROP_COLOR; + requestedProperties += PROP_LINE_WIDTH; + requestedProperties += PROP_LINE_POINTS; + requestedProperties += PROP_NORMALS; + requestedProperties += PROP_STROKE_WIDTHS; + return requestedProperties; +} + +void PolyLineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + QWriteLocker lock(&_quadReadWriteLock); + bool successPropertyFits = true; + + APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); + APPEND_ENTITY_PROPERTY(PROP_LINE_WIDTH, getLineWidth()); + APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, getLinePoints()); + APPEND_ENTITY_PROPERTY(PROP_NORMALS, getNormals()); + APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, getStrokeWidths()); +} + +void PolyLineEntityItem::debugDump() const { + quint64 now = usecTimestampNow(); + qCDebug(entities) << " QUAD EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; + qCDebug(entities) << " position:" << debugTreeVector(getPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); + qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); +} + diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h new file mode 100644 index 0000000000..25b348fa55 --- /dev/null +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -0,0 +1,94 @@ +// +// PolyLineEntityItem.h +// libraries/entities/src +// +// Created by Eric Levin on 8/3/15. +// Copyright 2015 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_PolyLineEntityItem_h +#define hifi_PolyLineEntityItem_h + +#include "EntityItem.h" + +class PolyLineEntityItem : public EntityItem { + public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + PolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + + ALLOW_INSTANTIATION // This class can be instantiated + + // methods for getting/setting all properties of an entity + virtual EntityItemProperties getProperties() const; + virtual bool setProperties(const EntityItemProperties& properties); + + // TODO: eventually only include properties changed since the params.lastViewFrustumSent time + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const; + + virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData, + 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); + + const rgbColor& getColor() const { return _color; } + xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } + + void setColor(const rgbColor& value) { + memcpy(_color, value, sizeof(_color)); + } + void setColor(const xColor& value) { + + _color[RED_INDEX] = value.red; + _color[GREEN_INDEX] = value.green; + _color[BLUE_INDEX] = value.blue; + } + + void setLineWidth(float lineWidth){ _lineWidth = lineWidth; } + float getLineWidth() const{ return _lineWidth; } + + bool setLinePoints(const QVector& points); + bool appendPoint(const glm::vec3& point); + const QVector& getLinePoints() const{ return _points; } + + bool setNormals(const QVector& normals); + const QVector& getNormals() const{ return _normals; } + + bool setStrokeWidths(const QVector& strokeWidths); + const QVector& getStrokeWidths() const{ return _strokeWidths; } + + + virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; } + + // never have a ray intersection pick a PolyLineEntityItem. + virtual bool supportsDetailedRayIntersection() const { return true; } + virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face, + void** intersectedObject, bool precisionPicking) const { return false; } + + virtual void debugDump() const; + static const float DEFAULT_LINE_WIDTH; + static const int MAX_POINTS_PER_LINE; + + protected: + rgbColor _color; + float _lineWidth; + bool _pointsChanged; + QVector _points; + QVector _vertices; + QVector _normals; + QVector _strokeWidths; + mutable QReadWriteLock _quadReadWriteLock; +}; + +#endif // hifi_PolyLineEntityItem_h diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index a4e9b5f799..0146abdb7c 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityAdd: case EntityEdit: case EntityData: - return VERSION_POLYVOX_TEXTURES; + return VERSION_ENTITIES_POLYLINE; default: return 11; } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 96f097a4b2..1aeadb1af9 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -75,7 +75,7 @@ namespace PacketType { EntityErase, EntityEdit, DomainServerConnectionToken - }; + }; }; const int NUM_BYTES_MD5_HASH = 16; @@ -141,5 +141,6 @@ const PacketVersion VERSION_ENTITIES_SCRIPT_TIMESTAMP_FIX = 32; const PacketVersion VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE = 33; const PacketVersion VERSION_ENTITIES_NEW_PROTOCOL_LAYER = 35; const PacketVersion VERSION_POLYVOX_TEXTURES = 36; +const PacketVersion VERSION_ENTITIES_POLYLINE = 37; -#endif // hifi_PacketHeaders_h +#endif // hifi_PacketHeaders_h \ No newline at end of file diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index db2e2953c0..8430e21d79 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -394,6 +394,19 @@ bool OctreePacketData::appendValue(const QVector& value) { return success; } +bool OctreePacketData::appendValue(const QVector& value) { + uint16_t qVecSize = value.size(); + bool success = appendValue(qVecSize); + if (success) { + success = append((const unsigned char*)value.constData(), qVecSize * sizeof(float)); + if (success) { + _bytesOfValues += qVecSize * sizeof(float); + _totalBytesOfValues += qVecSize * sizeof(float); + } + } + return success; +} + bool OctreePacketData::appendValue(const glm::quat& value) { const size_t VALUES_PER_QUAT = 4; const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT; @@ -609,6 +622,16 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVecto memcpy(result.data(), dataBytes, length * sizeof(glm::vec3)); return sizeof(uint16_t) + length * sizeof(glm::vec3); } + +int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVector& result) { + uint16_t length; + memcpy(&length, dataBytes, sizeof(uint16_t)); + dataBytes += sizeof(length); + result.resize(length); + memcpy(result.data(), dataBytes, length * sizeof(float)); + return sizeof(uint16_t) + length * sizeof(float); +} + int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) { uint16_t length; memcpy(&length, dataBytes, sizeof(length)); diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 439a07087c..1a396210cb 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -165,6 +165,9 @@ public: //appends a QVector of vec3's to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const QVector& value); + + //appends a QVector of floats to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const QVector& value); /// appends a packed quat to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const glm::quat& value); @@ -245,6 +248,7 @@ public: static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result); static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); + static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result); private: diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 4941818bf4..6776fa6c79 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -139,6 +139,8 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET)); } + + void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool emmisive, bool depthBias) { SimpleProgramKey config{textured, culled, emmisive, depthBias}; diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 62497851d7..2fe56732cb 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -77,6 +77,7 @@ public: void setGlobalAtmosphere(const model::AtmospherePointer& atmosphere) { _atmosphere = atmosphere; } void setGlobalSkybox(const model::SkyboxPointer& skybox); + private: DeferredLightingEffect() {} virtual ~DeferredLightingEffect() { } diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp index f65bc7666f..cf01ccbcc9 100644 --- a/libraries/render-utils/src/HitEffect.cpp +++ b/libraries/render-utils/src/HitEffect.cpp @@ -19,6 +19,7 @@ #include "AbstractViewStateInterface.h" #include "HitEffect.h" + #include "TextureCache.h" #include "DependencyManager.h" #include "ViewFrustum.h" @@ -43,6 +44,7 @@ const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() { gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(false, false, gpu::LESS_EQUAL); @@ -50,7 +52,7 @@ const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() { // Blend on transparent state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - + // Good to go add the brand new pipeline _hitEffectPipeline.reset(gpu::Pipeline::create(program, state)); } @@ -77,9 +79,6 @@ void HitEffect::run(const render::SceneContextPointer& sceneContext, const rende glm::vec2 bottomLeft(-1.0f, -1.0f); glm::vec2 topRight(1.0f, 1.0f); DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, color); - - - // Ready to render args->_context->render((batch)); } diff --git a/libraries/render-utils/src/HitEffect.h b/libraries/render-utils/src/HitEffect.h index 91ac7e5700..b560cf5550 100644 --- a/libraries/render-utils/src/HitEffect.h +++ b/libraries/render-utils/src/HitEffect.h @@ -26,7 +26,6 @@ public: const gpu::PipelinePointer& getHitEffectPipeline(); private: - gpu::PipelinePointer _hitEffectPipeline; }; diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 2db56fe68a..efef423623 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -106,6 +106,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() { _drawStatusJobIndex = _jobs.size() - 1; _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D"))); + _jobs.push_back(Job(new HitEffect::JobModel("HitEffect"))); _jobs.back().setEnabled(false); _drawHitEffectJobIndex = _jobs.size() -1; diff --git a/libraries/render-utils/src/hit_effect.slf b/libraries/render-utils/src/hit_effect.slf index ed11aea0b9..c059488ba1 100644 --- a/libraries/render-utils/src/hit_effect.slf +++ b/libraries/render-utils/src/hit_effect.slf @@ -2,6 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // + // hit_effect.frag // fragment shader // @@ -12,6 +13,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + <@include DeferredBufferWrite.slh@> in vec2 varQuadPosition; diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index de684dced1..c4e05a68fb 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -33,6 +33,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, vec4toScriptValue, vec4FromScriptValue); qScriptRegisterMetaType(engine, vec3toScriptValue, vec3FromScriptValue); qScriptRegisterMetaType(engine, qVectorVec3ToScriptValue, qVectorVec3FromScriptValue); + qScriptRegisterMetaType(engine, qVectorFloatToScriptValue, qVectorFloatFromScriptValue); qScriptRegisterMetaType(engine, vec2toScriptValue, vec2FromScriptValue); qScriptRegisterMetaType(engine, quatToScriptValue, quatFromScriptValue); qScriptRegisterMetaType(engine, qRectToScriptValue, qRectFromScriptValue); @@ -43,6 +44,7 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue); + } QScriptValue vec4toScriptValue(QScriptEngine* engine, const glm::vec4& vec4) { @@ -79,7 +81,7 @@ void vec3FromScriptValue(const QScriptValue &object, glm::vec3 &vec3) { vec3.z = object.property("z").toVariant().toFloat(); } -QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector){ +QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector) { QScriptValue array = engine->newArray(); for (int i = 0; i < vector.size(); i++) { array.setProperty(i, vec3toScriptValue(engine, vector.at(i))); @@ -87,6 +89,39 @@ QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector qVectorFloatFromScriptValue(const QScriptValue& array) { + if(!array.isArray()) { + return QVector(); + } + QVector newVector; + int length = array.property("length").toInteger(); + newVector.reserve(length); + for (int i = 0; i < length; i++) { + if(array.property(i).isNumber()) { + newVector << array.property(i).toNumber(); + } + } + + return newVector; +} + +QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector& vector) { + QScriptValue array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + float num = vector.at(i); + array.setProperty(i, QScriptValue(num)); + } + return array; +} + +void qVectorFloatFromScriptValue(const QScriptValue& array, QVector& vector) { + int length = array.property("length").toInteger(); + + for (int i = 0; i < length; i++) { + vector << array.property(i).toVariant().toFloat(); + } +} +// QVector qVectorVec3FromScriptValue(const QScriptValue& array){ QVector newVector; int length = array.property("length").toInteger(); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index f5f39cd3f6..31f1da8a40 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -29,6 +29,7 @@ Q_DECLARE_METATYPE(glm::vec2) Q_DECLARE_METATYPE(glm::quat) Q_DECLARE_METATYPE(xColor) Q_DECLARE_METATYPE(QVector) +Q_DECLARE_METATYPE(QVector) void registerMetaTypes(QScriptEngine* engine); @@ -60,6 +61,10 @@ QScriptValue qVectorVec3ToScriptValue(QScriptEngine* engine, const QVector& vector); QVector qVectorVec3FromScriptValue( const QScriptValue& array); +QScriptValue qVectorFloatToScriptValue(QScriptEngine* engine, const QVector& vector); +void qVectorFloatFromScriptValue(const QScriptValue& array, QVector& vector); +QVector qVectorFloatFromScriptValue(const QScriptValue& array); + class PickRay { public: PickRay() : origin(0.0f), direction(0.0f) { } diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index c514532eac..dde7419264 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -109,6 +109,8 @@ #include "sdf_text3D_vert.h" #include "sdf_text3D_frag.h" +#include "paintStroke_vert.h" +#include "paintStroke_frag.h" class RateCounter { std::vector times; @@ -324,6 +326,8 @@ void QTestWindow::draw() { testShaderBuild(SkyFromAtmosphere_vert, SkyFromAtmosphere_frag); testShaderBuild(Skybox_vert, Skybox_frag); + + testShaderBuild(paintStroke_vert,paintStroke_frag); });